--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pbmd.c Fri May 07 12:04:06 2010 +0100
@@ -0,0 +1,637 @@
+// pbm.c
+//
+// The Program Formerly Known as pollbatterymonitor.c
+//
+// The Phidget Interface Kit with the integrated LCD screen is actually
+// two separate devices and so you must set up two handles and two sets of
+// handlers
+//
+// This program connects to a Phidget with LCD which has an ammeter and a
+// voltmeter attached. It reads the both and writes the results to a log file
+// It then writes summary info to a "snapshot" file including a state.
+//
+//
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <phidget21.h>
+#include <time.h>
+#include <stdlib.h>
+
+#define INIT 0 // Initialised (first run or reset manually)
+#define STBYLONG 1 // Standby 180 - reboot, check voltage, sleep 3 hours
+#define STBYSHORT 2 // Standby 30 - boot, check voltage, sleep 30 mins
+#define OVERRIDE 3 // manually started - run 30 mins then sleep
+#define SLEEP 4 // Sleep during the night
+#define UP 9 // Running normally - dont sleep
+#define GREEN 1150 // Voltage level for normal running
+#define AMBER 1129 // Voltage level at which we must go asleep
+#define SLEEPTIMESTART "22:00" // Time to start sleeping
+#define SLEEPTIMEEND "06:00" // Time to end sleeping
+
+void display_generic_properties(CPhidgetHandle phid)
+{
+ int sernum, version;
+ const char *deviceptr;
+ CPhidget_getDeviceType(phid, &deviceptr);
+ CPhidget_getSerialNumber(phid, &sernum);
+ CPhidget_getDeviceVersion(phid, &version);
+
+ printf("%s\n", deviceptr);
+ printf("Version: %8d SerialNumber: %10d\n", version, sernum);
+ return;
+}
+
+int display_properties(CPhidgetTextLCDHandle phid)
+{
+ int serialNo, version, numRows, numColumns, backlight, cursor, contrast, cursor_blink;
+ const char* ptr;
+
+ CPhidget_getDeviceType((CPhidgetHandle)phid, &ptr);
+ CPhidget_getSerialNumber((CPhidgetHandle)phid, &serialNo);
+ CPhidget_getDeviceVersion((CPhidgetHandle)phid, &version);
+
+ CPhidgetTextLCD_getRowCount (phid, &numRows);
+ CPhidgetTextLCD_getColumnCount (phid, &numColumns);
+ CPhidgetTextLCD_getBacklight (phid, &backlight);
+ CPhidgetTextLCD_getContrast (phid, &contrast);
+ CPhidgetTextLCD_getCursorOn (phid, &cursor);
+ CPhidgetTextLCD_getCursorBlink (phid, &cursor_blink);
+
+ printf("%s\n", ptr);
+ printf("Serial Number: %10d\nVersion: %8d\n", serialNo, version);
+ printf("# Rows: %d\n# Columns: %d\n", numRows, numColumns);
+ printf("Current Contrast Level: %d\nBacklight Status: %d\n", contrast, backlight);
+ printf("Cursor Status: %d\nCursor Blink Status: %d\n", cursor, cursor_blink);
+
+ return 0;
+}
+
+
+int IFK_DetachHandler(CPhidgetHandle IFK, void *userptr)
+{
+ printf("IFK Detach handler ran!\n");
+ return 0;
+}
+
+int IFK_ErrorHandler(CPhidgetHandle IFK, void *userptr, int ErrorCode, const char *unknown)
+{
+ printf("IFK Error handler ran!\n");
+ return 0;
+}
+
+int IFK_OutputChangeHandler(CPhidgetInterfaceKitHandle IFK, void *userptr, int Index, int Value)
+{
+ printf("Output %d is %d\n", Index, Value);
+ return 0;
+}
+
+int IFK_InputChangeHandler(CPhidgetInterfaceKitHandle IFK, void *userptr, int Index, int Value)
+{
+ printf("Input %d is %d\n", Index, Value);
+ return 0;
+}
+
+int IFK_SensorChangeHandler(CPhidgetInterfaceKitHandle IFK, void *userptr, int Index, int Value)
+{
+ float fValue;
+ int oValue, rValue;
+
+ rValue = 0;
+ oValue = Value;
+
+
+ if (Index == 0) {
+ fValue = Value; // Sensor 0 is Amps - adj accordingly
+ fValue = (fValue*13.2)-37.8787; // (SensorValue / 13.2) - 37.8787
+ Value = fValue;
+ }
+
+ return 0;
+}
+
+
+int IFK_AttachHandler(CPhidgetHandle IFK, void *userptr)
+{
+ CPhidgetInterfaceKit_setSensorChangeTrigger((CPhidgetInterfaceKitHandle)IFK, 0, 0);
+ printf("IFK Attach handler ran!\n");
+ return 0;
+}
+
+int LCD_AttachHandler(CPhidgetHandle IFK, void *userptr)
+{
+ printf("LCD Attach handler ran!\n");
+ return 0;
+}
+
+int LCD_DetachHandler(CPhidgetHandle IFK, void *userptr)
+{
+ printf("LCD Detach handler ran!\n");
+ return 0;
+}
+
+int LCD_ErrorHandler(CPhidgetHandle IFK, void *userptr, int ErrorCode, const char *unknown)
+{
+ printf("LCD Error handler ran!\n");
+ return 0;
+}
+
+
+int getVoltage(CPhidgetInterfaceKitHandle IFK, int voltIndex, int *Voltage)
+{
+ float fValue = 0, avgValue = 0;
+ int Value= 0, i = 0;
+
+ CPhidgetInterfaceKit_setRatiometric(IFK, PFALSE); // set to non-ratio
+ sleep(2); // wait at least 800ms to settle
+ CPhidgetInterfaceKit_getSensorRawValue(IFK, voltIndex, &Value); // Voltmeter
+
+ // Calibration // this is zero point calibration.
+ Value = Value + 5;
+ // End calibration
+
+ // get an average over 5 readings to allow for sensor noise. 1 per second for 5 seconds
+
+ for (i = 0; i < 5 ; i++)
+ {
+ fValue = Value;
+ fValue = (((fValue/4.095)*0.06)-30)*100; // multiply raw value and up by 100 to keep
+ avgValue = avgValue + fValue;
+ sleep (1);
+ }
+ avgValue = avgValue / 5;
+ *Voltage = avgValue;
+
+// printf("Volts value %d\n", Value);
+
+ return 0;
+}
+
+int getAmps(CPhidgetInterfaceKitHandle IFK, int ampIndex, int *Amps)
+{
+ float fValue;
+ int Value,nValue;
+
+ CPhidgetInterfaceKit_setRatiometric (IFK, PTRUE); // set to ratiometric
+ sleep(2); // wait at least 800ms
+ CPhidgetInterfaceKit_getSensorRawValue(IFK, ampIndex, &Value); // Ampmeter
+ CPhidgetInterfaceKit_getSensorValue(IFK, ampIndex, &nValue);
+
+ // Calibration
+ Value = Value + 2;
+ // End calibration
+
+ fValue = Value;
+ fValue = (((fValue/4.095)/13.2)-37.8787)*1000; // multiply raw value to get amps
+ *Amps = fValue;
+
+// printf("Amps value Raw %d Normal %d\n", Value, nValue);
+ return 0;
+}
+
+int getLux(CPhidgetInterfaceKitHandle IFK, int luxIndex, int *Lux)
+{
+ int Value;
+
+ CPhidgetInterfaceKit_setRatiometric(IFK, PFALSE); // set to non-ratio
+ sleep(2); // wait at least 800ms
+ CPhidgetInterfaceKit_getSensorValue(IFK, luxIndex, &Value); // Voltmeter
+
+ // Calibration
+ // None required
+ // End calibration
+
+ *Lux = Value;
+
+// printf("Volts value %d\n", Value);
+ return 0;
+}
+
+
+int updateSnapshotfile(char *SNAPSHOTFILE, int newState, int Voltage, int Amps, int Lux)
+{
+ // Snapshot file is a single line file, overwritten each time with the current and latest values
+ time_t rawtime;
+ struct tm * timeinfo;
+ char timeStr [80];
+
+ time ( &rawtime );
+ timeinfo = localtime ( &rawtime );
+
+ strftime (timeStr,80,"%Y-%m-%d,%H:%M:%S",timeinfo);
+
+ FILE *filesnap = fopen( SNAPSHOTFILE, "w" ); // Open file (delete previous)
+
+ if (filesnap == 0) // Aaargh! Problem ...
+ {
+ printf( "Could not open the snapshot file\n" );
+ }
+ else
+ {
+ fprintf(filesnap, "%d,%s,%d,%d,%d\n", newState, timeStr, Voltage, Amps, Lux);
+ fflush(filesnap);
+ }
+ fclose( filesnap );
+
+ return 0;
+}
+
+
+
+int updateLogfile(FILE *filelog, int Voltage, int Amps, int Lux)
+{
+ time_t rawtime;
+ struct tm * timeinfo;
+ char timeStr [80];
+
+ time ( &rawtime );
+ timeinfo = localtime ( &rawtime );
+
+ strftime (timeStr,80,"%Y-%m-%d,%H:%M:%S",timeinfo);
+
+ fprintf(filelog, "%s,%d,%d,%d\n", timeStr, Voltage, Amps, Lux);
+ fflush(filelog);
+
+ return 0;
+}
+
+
+// getTimeString returns the time in a string in the form "HH:MM". It takes the current
+// time and adds the wakeTime to it. This can also be used to simply return the current time if the
+// wakeTime is 0.
+
+int getTimeString (int wakeTime, char *wakeTimeStr)
+{
+ time_t rawtime;
+ struct tm * timeinfo;
+
+ time ( &rawtime );
+ rawtime = rawtime + (wakeTime * 60);
+ timeinfo = localtime ( &rawtime );
+
+ // strftime (wakeTimeStr,80,"%Y-%m-%d,%H:%M:%S",timeinfo);
+ strftime (wakeTimeStr,20,"%H:%M",timeinfo);
+
+ return 0;
+}
+
+int getState(char *SNAPSHOTFILE, int previousState, char *bootflag)
+{
+ // Snapshot file is a single line file, overwritten each time with the current and latest values
+
+ FILE *filesnap = fopen( SNAPSHOTFILE, "r" ); // Open file (delete previous)
+
+ if (filesnap == 0) // Aaargh! Problem ...
+ {
+ printf( "getState: Could not open the snapshot file to retrieve state\n" );
+ }
+ else
+ {
+ //fprintf(filesnap, "%s,%d,%d,%d\n", timeStr, Voltage, Amps, Lux);
+ //fflush(filesnap);
+ }
+ fclose( filesnap );
+
+ return 0;
+}
+
+int getnewState(int Voltage, char *bootflag, int *newState)
+{
+ char *timeStr = malloc(20);
+
+ int localState = 0;
+
+ printf ("In getnewState: Bootflag %s Voltage %d\n", bootflag, Voltage);
+
+ *newState = localState; // Just to be sure its 0}
+
+ getTimeString (0, timeStr); // Use this to return current time as a string
+
+ if (strncmp(bootflag, "S",1) != 0) { // Anything except an S will mean manual start
+ localState = OVERRIDE;
+ }
+ else if (strcmp(timeStr, SLEEPTIMESTART) > 0 || strcmp(timeStr, SLEEPTIMEEND) < 0) {
+ localState = SLEEP;
+ }
+ else if (Voltage >= GREEN) {
+ localState = UP;
+ }
+ else if (Voltage >= AMBER) {
+ localState = STBYSHORT;
+ }
+ else {
+ localState = STBYLONG;
+ }
+
+ *newState = localState; // and set it across the wormhole
+
+ return 0;
+}
+
+int test_interfacekit(FILE *filelog, char *SNAPSHOTFILE, char * bootflag, time_t boottime, int Sleep, int testVoltage)
+{
+ int LUXINDEX=2;
+ int VOLTINDEX=1;
+ int AMPINDEX=0;
+
+ int numInputs, numOutputs, numSensors;
+ int err;
+ int lightTrigger;
+ int Voltage = 0, Amps = 0, Lux = 0;
+ int tts;
+ int newState = 0;
+ int ret;
+
+ char buffer1 [80];
+ char buffer2 [80];
+ char *wakeTimeStr = malloc(20);
+
+ char *stateDesc[10];
+
+ time_t timenow;
+
+ stateDesc[0] = "Initialise";
+ stateDesc[1] = "STBYLONG";
+ stateDesc[2] = "STBYSHORT";
+ stateDesc[3] = "OVERRIDE";
+ stateDesc[4] = "SLEEP";
+ stateDesc[9] = "UP";
+
+ CPhidgetInterfaceKitHandle IFK = 0;
+ CPhidgetInterfaceKit_create(&IFK);
+
+ CPhidgetTextLCDHandle LCD = 0;
+ CPhidgetTextLCD_create (&LCD);
+
+ //CPhidget_enableLogging(PHIDGET_LOG_VERBOSE, NULL);
+
+ // Set up handlers for the Interface Kit
+
+ CPhidget_set_OnAttach_Handler((CPhidgetHandle)IFK, IFK_AttachHandler, NULL);
+ CPhidget_set_OnDetach_Handler((CPhidgetHandle)IFK, IFK_DetachHandler, NULL);
+ CPhidget_set_OnError_Handler((CPhidgetHandle)IFK, IFK_ErrorHandler, NULL);
+
+ // Set up handlers for the TextLCD
+
+ CPhidget_set_OnAttach_Handler((CPhidgetHandle)LCD, LCD_AttachHandler, NULL);
+ CPhidget_set_OnDetach_Handler((CPhidgetHandle)LCD, LCD_DetachHandler, NULL);
+ CPhidget_set_OnError_Handler((CPhidgetHandle)LCD, LCD_ErrorHandler, NULL);
+
+ CPhidget_open((CPhidgetHandle)IFK, -1);
+ CPhidget_open((CPhidgetHandle)LCD, -1);
+
+ //wait 5 seconds for attachment of the Interface Kit
+ printf("Waiting for IFK to be attached...\n");
+ if((err = CPhidget_waitForAttachment((CPhidgetHandle)IFK, 5000)) != EPHIDGET_OK )
+ {
+ const char *errStr;
+ CPhidget_getErrorDescription(err, &errStr);
+ printf("Error waiting for IFK attachment: (%d): %s\n",err,errStr);
+ goto exit;
+ }
+
+ display_generic_properties((CPhidgetHandle)IFK);
+ CPhidgetInterfaceKit_getOutputCount((CPhidgetInterfaceKitHandle)IFK, &numOutputs);
+ CPhidgetInterfaceKit_getInputCount((CPhidgetInterfaceKitHandle)IFK, &numInputs);
+ CPhidgetInterfaceKit_getSensorCount((CPhidgetInterfaceKitHandle)IFK, &numSensors);
+
+ CPhidgetInterfaceKit_setOutputState((CPhidgetInterfaceKitHandle)IFK, 0, 1);
+
+ printf("Sensors:%d Inputs:%d Outputs:%d\n", numSensors, numInputs, numOutputs);
+
+ //get the program to wait for an TextLCD device to be attached
+ printf("Waiting for LCD to be attached...\n");
+ if((err = CPhidget_waitForAttachment((CPhidgetHandle)LCD, 10000)))
+ {
+ const char *errStr;
+ CPhidget_getErrorDescription(err, &errStr);
+ printf("Problem waiting for LCD attachment: (%d): %s\n",err,errStr);
+ return 0;
+ }
+
+ //Display the properties of the attached textlcd device
+ display_properties(LCD);
+
+
+ CPhidgetInterfaceKit_getSensorChangeTrigger (IFK, 0, &lightTrigger);
+
+
+ while(1)
+ {
+ getVoltage(IFK, VOLTINDEX, &Voltage);
+ getAmps(IFK, AMPINDEX, &Amps);
+ getLux(IFK, LUXINDEX, &Lux);
+
+
+ if (testVoltage != 0) {
+ Voltage = testVoltage;
+ }
+
+ getnewState (Voltage, bootflag, &newState);
+
+ updateLogfile (filelog, Voltage, Amps, Lux);
+
+ updateSnapshotfile (SNAPSHOTFILE, newState, Voltage, Amps, Lux);
+
+ // Now Update the LCD
+
+ getTimeString (0, wakeTimeStr);
+ sprintf (buffer1, "V:%4d A:%-5d %s", Voltage, Amps,wakeTimeStr);
+ sprintf (buffer2, "%-s", stateDesc[newState]);
+
+ CPhidgetTextLCD_setDisplayString (LCD, 0, buffer1);
+ CPhidgetTextLCD_setDisplayString (LCD, 1, buffer2);
+
+
+
+ // Do what the state demands
+ printf ("Begin main while loop: State is %s\n", stateDesc[newState]);
+
+ switch (newState)
+ {
+ case INIT:
+ // Shouldnt be here!
+ break;
+
+ case STBYLONG:
+ // sleep for 3 hours, then wake, reboot
+ getTimeString (180, wakeTimeStr);
+ sprintf (buffer2, "%-s Back@%-s", stateDesc[newState], wakeTimeStr);
+
+ CPhidgetTextLCD_setDisplayString (LCD, 1, buffer2);
+
+ ret = system ("/etc/stbylong.sh");
+ if (!ret) {
+ printf ("STBYLONG - executing ...\n");
+ }
+ else {
+ printf ("STBYLONG - problem kicking off STBYLONG ... not running. Error %d\n",ret);
+ }
+ break;
+
+ case STBYSHORT:
+ // sleep for 30 mins, then wake, reboot
+ getTimeString (30, wakeTimeStr);
+ sprintf (buffer2, "%-s Wake@%-s", stateDesc[newState], wakeTimeStr);
+
+ CPhidgetTextLCD_setDisplayString (LCD, 1, buffer2);
+
+ ret = system ("/etc/stbyshort.sh");
+ if (!ret) {
+ printf ("STBYSHORT - executing ...\n");
+ }
+ else {
+ printf ("STBYSHORT - problem kicking off STBYSHORT ... not running. Error %d\n",ret);
+ }
+ break;
+
+ case OVERRIDE:
+ // stay up for 30 mins, then sleep, wake, reboot
+ time (&timenow);
+ tts = 1800 - (timenow - boottime);
+ printf ("%d to sleep\n", tts);
+
+ sprintf (buffer2, "%-s Time:%d", stateDesc[newState], tts/60);
+
+ CPhidgetTextLCD_setDisplayString (LCD, 1, buffer2);
+
+ if (timenow > boottime + 1800) {
+
+ printf ("OVERRIDE - 30 mins expired ... switching to normal mode\n");
+ bootflag = "S";
+ printf ("Bootflag in case OVERRIDE %s \n", bootflag);
+ }
+ break;
+
+ case SLEEP:
+ // We're running during night time - go to sleep
+ wakeTimeStr = SLEEPTIMEEND;
+ sprintf (buffer2, "%-s Wake@%-s", stateDesc[newState], wakeTimeStr);
+
+ CPhidgetTextLCD_setDisplayString (LCD, 1, buffer2);
+
+ ret = system ("/etc/sleeprtc.sh");
+ if (!ret) {
+ printf ("SLEEPRTC - executing ...\n");
+ }
+ else {
+ printf ("SLEEPRTC - problem kicking off SLEEPRTC ... not running. Error %d\n",ret);
+ }
+ break;
+ case UP:
+ // normal running here
+ // Nothing to do but continue loop
+ break;
+ }
+
+ fflush (stdout);
+ sleep (Sleep);
+
+ }
+
+exit:
+ CPhidget_close((CPhidgetHandle)IFK);
+ CPhidget_delete((CPhidgetHandle)IFK);
+ CPhidget_close((CPhidgetHandle)LCD);
+ CPhidget_delete((CPhidgetHandle)LCD);
+
+ return 0;
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ int Sleep, testVoltage;
+ char *SNAPSHOTFILE;
+ char *bootflag = malloc(2);
+ time_t boottime;
+
+
+ if ( argc != 6 ) { // 5 args inc program name
+ printf( "usage: %s logfile snapshotfile rebootfile sleeptime testvoltage\n", argv[0] );
+ exit(1);
+ }
+
+ // Close out stdout and point to a file cos if we are running as a demon we need to log this somewhere.
+
+ fclose(stdout);
+ fclose(stderr);
+ stdout = fopen("/var/log/pbm.log", "a");
+ stderr = fopen("/var/log/pbm.err", "a");
+
+ Sleep = atoi(argv[4]); // Arg 4 is sleep interval
+ testVoltage = atoi(argv[5]); // Arg 5 is used for testing
+ // - 0 is use voltmeter reading
+ // - any other value overrides
+
+ FILE *filelog = fopen( argv[1], "a" ); // Open log file
+ FILE *filesnap = fopen( argv[2], "w" ); // Open snapshot file
+
+ if ( (filelog == 0) || (filesnap == 0)) { // Aaargh! Problem ...
+ printf( "Could not open log file or snapshot file\n" );
+ exit(1);
+ }
+
+ fclose( filesnap ); // cos we need to overwrite it every time we write to it
+
+ // The system reboots after a sleep period to ensure everyting is restarted properly
+ // As part of this "planned" reboot the boot flag file is written to.
+ // If this file does not have the correct value, then a user has powered off/on the box
+ // in order to force a wakeup, so we dont want to go asleep straight away
+ // If the value is S then we have scheduled a wakeup. Anything else, or no file means manual
+ // override.
+
+ FILE *fileboot = fopen( argv[3], "r"); // Open boot flag file
+ if ( (fileboot == 0) ) {
+ printf( "Could not open boot flag file - assuming manual override\n" );
+ bootflag = "N";
+ }
+ else {
+ // read from boot state file
+ printf( "Opened boot flag file\n");
+ // bootflag should be "S"
+ if (fscanf (fileboot, "%s", bootflag)) {
+ time ( &boottime ); // log time we booted
+ fclose( fileboot );
+ }
+ else {
+ printf( "Error reading in from bootflag file - assuming manual restart\n" );
+ bootflag = "X";
+ }
+ }
+
+
+// clear bootflag file - an S in this file means we are controlling the reboot (eg the user
+// did not manually turn off and on the box
+
+ fileboot = fopen( argv[3], "w"); // Open boot flag file for writing
+ if ( (fileboot == 0) ) {
+ printf( "Could not open boot flag file for writing\n" );
+ }
+ else { // read from boot state file
+ printf( "Clearing boot flag\n");
+ fprintf(fileboot, "%s", "X");
+ fclose( fileboot );
+ }
+
+
+
+ printf ("Output to file %s\n", argv[1]);
+ printf ("Output to snapshot %s\n", argv[2]);
+ printf ("Boot flag file is %s\n", argv[3]);
+ printf ("Sleep time is %d\n", Sleep);
+ printf ("Bootflag is %s\n", bootflag);
+
+ fprintf (filelog, "\nYYYY-M-MDD,HH:MM:SS,mVolts,mAmps,Lux\n");
+
+ SNAPSHOTFILE = argv[2];
+
+ test_interfacekit(filelog, SNAPSHOTFILE, bootflag, boottime, Sleep, testVoltage);// and off we go
+
+
+ fclose( filelog );
+ return 0;
+}
+