/* * phidgetcontrol * * Copyright (C) 2012 Jonathan McCrohan * * 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 3 of the License, or * (at your option) 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, see . */ // gcc phidgetcontrol.c -o phidgetcontrol `pkg-config --libs --cflags `libphidget21 libconfig` #ifndef VERSION_STRING #define VERSION_STRING "[undefined version]" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // handle SIGALRM by resetting it void minute_check (int signum) { alarm (60); } // get mac address of primary interface eth0 char * mac_address () { int s; struct ifreq ifr; s = socket (PF_INET, SOCK_DGRAM, 0); memset (&ifr, 0x00, sizeof (ifr)); strcpy (ifr.ifr_name, "eth0"); ioctl (s, SIOCGIFHWADDR, &ifr); close (s); static char mac_address[12]; sprintf (mac_address, "%.2X%.2X%.2X%.2X%.2X%.2X", (unsigned char) ifr.ifr_hwaddr.sa_data[0], (unsigned char) ifr.ifr_hwaddr.sa_data[1], (unsigned char) ifr.ifr_hwaddr.sa_data[2], (unsigned char) ifr.ifr_hwaddr.sa_data[3], (unsigned char) ifr.ifr_hwaddr.sa_data[4], (unsigned char) ifr.ifr_hwaddr.sa_data[5]); return mac_address; } int main (int argc, char *argv[]) { int DEBUG = 0; int SYSLOG_CONSOLE_OUTPUT = 0; int k; // check the argv array for strings matching -d for (k = 1; k < argc; k++) { if (strcmp (argv[k], "-d") == 0) { DEBUG = 1; SYSLOG_CONSOLE_OUTPUT = LOG_PERROR; } } openlog ("phidgetcontrol", SYSLOG_CONSOLE_OUTPUT | LOG_PID | LOG_CONS, LOG_USER); syslog (LOG_INFO, ""); syslog (LOG_INFO, "phidgetcontrol [%s] starting", VERSION_STRING); syslog (LOG_INFO, ""); const char *configfile = "/etc/phidgetcontrol.cfg"; config_t cfg; int setup_phidgetinterfacekit; int setup_phidgetanalog; int result, i; const char *err; char *p; int numInterfaceKitSensors = 8; int num1002AnalogSensors = 4; config_init (&cfg); // attempt to read config // loads entire file to memory and destroys file descriptor if (!config_read_file (&cfg, configfile)) { fprintf (stderr, "%s:%d - %s\n", config_error_file (&cfg), config_error_line (&cfg), config_error_text (&cfg)); config_destroy (&cfg); syslog (LOG_ERR, "Unable to find configfile"); return -1; } else { syslog (LOG_INFO, "configfile found successfully"); } // die if core config file options aren't there if (! (config_lookup_int (&cfg, "setup.phidgetinterfacekit", &setup_phidgetinterfacekit) && config_lookup_int (&cfg, "setup.phidgetanalog", &setup_phidgetanalog))) { syslog (LOG_ERR, "Incomplete phidget configuration. Check configuration file"); closelog (); return -1; } // declare InterfaceKit handle CPhidgetInterfaceKitHandle IKphid = 0; // declare Analog handle CPhidgetAnalogHandle Aphid = 0; // create InterfaceKit object CPhidgetInterfaceKit_create (&IKphid); //create the Analog object CPhidgetAnalog_create (&Aphid); // connect to InterfaceKit object CPhidget_open ((CPhidgetHandle) IKphid, -1); // connect to Analog object CPhidget_open ((CPhidgetHandle) Aphid, -1); // check if we should have a phidgetinterfacekit connected if (setup_phidgetinterfacekit) { // phidget interfacekit handle timeout if ((result = CPhidget_waitForAttachment ((CPhidgetHandle) IKphid, 5000))) { CPhidget_getErrorDescription (result, &err); printf ("PHIDGET: Problem waiting for attachment: %s\n", err); return -1; } } // check if we should have a phidgetanalog connected if (setup_phidgetanalog) { // phidget analog handle timeout if ((result = CPhidget_waitForAttachment ((CPhidgetHandle) Aphid, 5000))) { CPhidget_getErrorDescription (result, &err); printf ("PHIDGET: Problem waiting for attachment: %s\n", err); return -1; } } // set digital outputs low on program startup for (i = 0; i < numInterfaceKitSensors; i++) { CPhidgetInterfaceKit_setOutputState (IKphid, i, 0); } // set analog outputs as disabled on program startup for (i = 0; i < num1002AnalogSensors; i++) { CPhidgetAnalog_setEnabled (Aphid, i, 0); } // SIGALRM used to wake for loop up every 60 secs // sleep puts whole thread to sleep which isn't what we want // other methods involve CPU spinlocks which are inefficient signal (SIGALRM, minute_check); alarm (60); for (;;) { // block until SIGARLM select (0, NULL, NULL, NULL, NULL); time_t t = time (NULL); struct tm unixtime_min_time_t = *gmtime (&t); unixtime_min_time_t.tm_sec = 0; time_t unixtime_min = mktime (&unixtime_min_time_t); config_setting_t *config_input; config_setting_t *config_output; config_input = config_lookup (&cfg, "input"); config_output = config_lookup (&cfg, "output"); // find number of required readings unsigned int num_input_readings = config_setting_length (config_input); unsigned int num_output_entries = config_setting_length (config_output); // cycle through each input reading and pull info from config file for (i = 0; i < num_input_readings; ++i) { config_setting_t *input_element = config_setting_get_elem (config_input, i); const char *input_reading_type; config_setting_lookup_string (input_element, "type", &input_reading_type); int input_port; config_setting_lookup_int (input_element, "port", &input_port); int input_intervalvalue; config_setting_lookup_int (input_element, "intervalvalue", &input_intervalvalue); const char *input_intervalunit; config_setting_lookup_string (input_element, "intervalunit", &input_intervalunit); int input_intervalduration; if (input_intervalunit[0] == 'h') input_intervalduration = input_intervalvalue * 3600; else input_intervalduration = input_intervalvalue * 60; // if we match the required time for the reading or first run if ((unixtime_min % input_intervalduration == 0)) { int reading_result; if (!strcmp (input_reading_type, "digital")) { // digital input CPhidgetInterfaceKit_getInputState (IKphid, input_port, &reading_result); // digital input is somewhat counter inutitive // <1.25V returns TRUE; >3.75V returns FALSE } else { //analog input CPhidgetInterfaceKit_getSensorValue (IKphid, input_port, &reading_result); // one analog unit is ~5 millivolts reading_result *= 5; } // round forward to next midnight struct tm midnight = *localtime (&t); midnight.tm_hour = 0; midnight.tm_min = 0; midnight.tm_sec = 0; midnight.tm_mday += 1; mktime (&midnight); char log_filename[50]; //_YYYY_MM_DD_HH_MM_SS.log sprintf (log_filename, "/var/phidgetcontrol/%s_%04i_%02i_%02i_%02i_%02i_%02i.log", mac_address (), midnight.tm_year + 1900, midnight.tm_mon + 1, midnight.tm_mday, midnight.tm_hour, midnight.tm_min, midnight.tm_sec); FILE *fp = fopen (log_filename, "r"); if (fp) { fclose (fp); } else { // file doesn't exist. create it. syslog (LOG_NOTICE, "logfile does not exist"); syslog (LOG_INFO, "creating file: [%s]", log_filename); FILE *fp = fopen (log_filename, "w"); fprintf (fp, "IntervalID|UTCDate|UTCTime|LOCALDate|LOCALTime|SensorType|PortID|Reading\n"); fclose (fp); } FILE *filehandle = fopen (log_filename, "a+"); syslog (LOG_DEBUG, "opening file for append: [%s]", log_filename); struct tm utc = *gmtime (&unixtime_min); struct tm lc = *localtime (&unixtime_min); int intervalid; char interval_filename[50]; sprintf (interval_filename, "/var/phidgetcontrol/interval/interval.txt"); syslog (LOG_DEBUG, "opening interval file: [%s]", interval_filename); FILE *intervalfile = fopen (interval_filename, "r+"); if (intervalfile) { fclose (intervalfile); } else { // file doesn't exist. create it. syslog (LOG_NOTICE, "interval file does not exist"); syslog (LOG_INFO, "attempting to create file: [%s]", interval_filename); intervalfile = fopen (interval_filename, "w"); fprintf (intervalfile, "0\n"); fclose (intervalfile); } // file now exists, try opening again intervalfile = fopen (interval_filename, "r+"); fscanf (intervalfile, "%d", &intervalid); //handle 32bit signed overflow if (intervalid >= 2147483647) { intervalid = 0; } else { intervalid++; } rewind (intervalfile); fprintf (intervalfile, "%d", intervalid); fclose (intervalfile); fprintf (filehandle, "%i|%04i%02i%02i|%02i%02i%02i|%04i%02i%02i|%02i%02i%02i|%s|%i|%i\n", intervalid, utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, lc.tm_year + 1900, lc.tm_mon + 1, lc.tm_mday, lc.tm_hour, lc.tm_min, lc.tm_sec, input_reading_type, input_port, reading_result); fclose (filehandle); syslog (LOG_DEBUG, "INPUT:[%i|%04i%02i%02i|%02i%02i%02i|%04i%02i%02i|%02i%02i%02i|%s|%i|%i]\n", intervalid, utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, lc.tm_year + 1900, lc.tm_mon + 1, lc.tm_mday, lc.tm_hour, lc.tm_min, lc.tm_sec, input_reading_type, input_port, reading_result); sleep (1); } } // cycle through each output reading and pull info from config file for (i = 0; i < num_output_entries; ++i) { config_setting_t *output_entry = config_setting_get_elem (config_output, i); const char *output_entry_type; config_setting_lookup_string (output_entry, "type", &output_entry_type); int output_port; config_setting_lookup_int (output_entry, "port", &output_port); int output_enabled; config_setting_lookup_int (output_entry, "enabled", &output_enabled); const char *scene_day; char scene_day_lower[20]; config_setting_lookup_string (output_entry, "day", &scene_day); strcpy (scene_day_lower, scene_day); p = scene_day_lower; // convert strings to lower case for (; *p; ++p) *p = tolower (*p); syslog (LOG_DEBUG, "scene_day=[%s]", scene_day_lower); const char *scene_time; config_setting_lookup_string (output_entry, "time", &scene_time); syslog (LOG_DEBUG, "scene_time=[%s]", scene_time); char daystring[20]; char timestring[20]; strftime (daystring, 20, "%A", &unixtime_min_time_t); strftime (timestring, 20, "%H:%M", &unixtime_min_time_t); p = daystring; // convert strings to lower case for (; *p; ++p) *p = tolower (*p); struct tm utc = *gmtime (&unixtime_min); struct tm lc = *localtime (&unixtime_min); syslog (LOG_DEBUG, "current_day=[%s]", daystring); syslog (LOG_DEBUG, "current_time=[%s]", timestring); if ((strcmp (scene_day_lower, daystring) == 0) && (strcmp (scene_time, timestring) == 0)) { int output_result; if (!strcmp (output_entry_type, "digital")) { CPhidgetInterfaceKit_setOutputState (IKphid, output_port, output_enabled); usleep (100000); CPhidgetInterfaceKit_getOutputState (IKphid, output_port, &output_result); syslog (LOG_DEBUG, "OUTPUT:[%04i%02i%02i|%02i%02i%02i|%04i%02i%02i|%02i%02i%02i|%s|%i|%i]\n", utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, lc.tm_year + 1900, lc.tm_mon + 1, lc.tm_mday, lc.tm_hour, lc.tm_min, lc.tm_sec, output_entry_type, output_port, output_result); } else { double output_voltage; double output_voltage_result; config_setting_lookup_float (output_entry, "voltage", &output_voltage); CPhidgetAnalog_setVoltage (Aphid, output_port, output_voltage); usleep (100000); CPhidgetAnalog_getVoltage (Aphid, output_port, &output_voltage_result); CPhidgetAnalog_setEnabled (Aphid, output_port, output_enabled); usleep (100000); CPhidgetAnalog_getEnabled (Aphid, output_port, &output_result); syslog (LOG_DEBUG, "OUTPUT:[%04i%02i%02i|%02i%02i%02i|%04i%02i%02i|%02i%02i%02i|%s|%i|%i|%f]\n", utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, lc.tm_year + 1900, lc.tm_mon + 1, lc.tm_mday, lc.tm_hour, lc.tm_min, lc.tm_sec, output_entry_type, output_port, output_result, output_voltage_result); } } } } }