// sblog.cc // This file is part of SlugBee; see http://chezphil.org/slugbee // (C) 2006-2007 Philip Endecott // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Wait for a device to send a wakeup packet, then interrogate it for // ADC data, and store it in a database. Repeat. #include #include #include #include #include "SerialPort.hh" #include "Exception.hh" #include "rfcdate.hh" #include "Database.hh" #include "SippPacket.hh" using namespace std; using namespace pbe; int verbose=0; void send_cmd_no_reply(SerialPort& port, SippPacket& pkt) { //cout << "Sending packet: " << pkt << "\n"; pkt.send(port); } class NoReply: public StrException { public: NoReply(): StrException("No reply") {}; }; SippPacket::data_t send_cmd_get_reply(SerialPort& port, SippPacket& pkt, uint8_t reply_command, int reply_length) { for (int attempt=0; attempt<3; ++attempt) { //cout << "Sending packet: " << pkt << "\n"; pkt.send(port); bool readable = port.wait_until_readable_or_timeout(0.2); if (readable) { SippPacket resp; resp.rcv(port); //cout << "Got packet: " << resp << "\n"; if (resp.command!=reply_command) { cout << "after sending cmd " << static_cast(pkt.command) << " got reply " << static_cast(resp.command) << " while expecting " << static_cast(reply_command) << "\n"; throw "Wrong command in reply"; } if (resp.data.length()!=reply_length) { throw "Wrong data length in reply"; } return resp.data; } if (verbose) { cout << "No reply, trying again\n"; } } if (verbose) { cout << "No reply, giving up\n"; } throw NoReply(); } void setupadc(SerialPort& port, SippID id, int channel, bool on) { SippPacket pkt; pkt.source_id=1; pkt.destination_id=id; pkt.command=0xAD; pkt.data.push_back(channel); pkt.data.push_back(on); send_cmd_get_reply(port,pkt,0xC9,0); } float readadc(SerialPort& port, SippID id, int channel) { SippPacket pkt; pkt.source_id=1; pkt.destination_id=id; pkt.command=0xAE; pkt.data.push_back(channel); SippPacket::data_t data = send_cmd_get_reply(port,pkt,0xCA,2); short raw = (data[0]<<8) | (data[1]&0xff); return 2.5 * raw / (1<<10); } void setiopindir(SerialPort& port, SippID id, int pin, int dir) { SippPacket pkt; pkt.source_id=1; pkt.destination_id=id; pkt.command=0xAB; pkt.data.push_back(pin); pkt.data.push_back(dir); send_cmd_get_reply(port,pkt,0xC7,0); } void writeiopin(SerialPort& port, SippID id, int pin, int val) { SippPacket pkt; pkt.source_id=1; pkt.destination_id=id; pkt.command=0xAC; pkt.data.push_back(pin); pkt.data.push_back(val); send_cmd_get_reply(port,pkt,0xC8,0); } void releasetosleep(SerialPort& port, SippID id) { SippPacket pkt; pkt.source_id=1; pkt.destination_id=id; pkt.command=0xA4; send_cmd_no_reply(port,pkt); } void wait_for_checkin(SerialPort& port, SippID id) { while (1) { SippPacket resp; resp.rcv(port); //cout << "Got packet: " << resp << "\n"; if (resp.command==0xC2 && resp.source_id==id) { break; } } } void usage(void) { cout << "Usage: sblog [-v] \n"; } int main(int argc, char* argv[]) { try { try { if (argc<2) { usage(); exit(1); } string arg1(argv[1]); if (arg1=="-v") { verbose=1; argv++; argc--; } if (argc!=5) { usage(); exit(1); } string port_fn = argv[1]; SippID id = boost::lexical_cast(argv[2]); int channel = boost::lexical_cast(argv[3]); SerialPort port(port_fn, FileDescriptor::read_write); port.set_serial_mode(9600); port.discard_pending_input(); string dbspec = argv[4]; Database db(dbspec); Query insert_reading (db, "insert into readings(value) values($1)"); while (1) { try { try { if (verbose) cout << "\nwaiting....\n\n"; wait_for_checkin(port,id); float v; try { if (verbose) cout << "switching on analogue power" << flush; setiopindir(port,id,7,1); if (verbose) cout << "... " << flush; writeiopin(port,id,7,1); if (verbose) cout << "setting up ADC... " << flush; setupadc(port,id,channel,true); if (verbose) cout << "pausing... " << flush; usleep(200000); if (verbose) cout << "reading ADC... " << flush; v = readadc(port,id,channel); if (verbose) cout<< "got a reading: " << v << "\n"; } catch(...) { if (verbose) cout << "discarding input and switching off after error...\n"; usleep(50000); port.discard_pending_input(); writeiopin(port,id,7,0); releasetosleep(port,id); if (verbose) cout << " done.\n"; throw; } writeiopin(port,id,7,0); releasetosleep(port,id); if (verbose) cout << "sending to database..." << flush; insert_reading(v); if (verbose) cout << "done.\n"; } RETHROW_MISC_EXCEPTIONS } catch (Exception& E) { E.report(cout); cout << "continuing after error\n" << flush; } } } RETHROW_MISC_EXCEPTIONS } catch (Exception& E) { E.report(cout); cout << "terminating after error\n" << flush; } }