diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/phidgetcontrol.c | 469 | ||||
-rw-r--r-- | src/phidgetcontrol.cfg | 42 |
2 files changed, 511 insertions, 0 deletions
diff --git a/src/phidgetcontrol.c b/src/phidgetcontrol.c new file mode 100644 index 0000000..d60451a --- /dev/null +++ b/src/phidgetcontrol.c @@ -0,0 +1,469 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +// gcc phidgetcontrol.c -o phidgetcontrol `pkg-config --libs --cflags `libphidget21 libconfig` + +#ifndef VERSION_STRING +#define VERSION_STRING "[undefined version]" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <time.h> +#include <unistd.h> +#include <sys/select.h> +#include <signal.h> +#include <fcntl.h> + +#include <libconfig.h> +#include <phidget21.h> + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <string.h> + +#include <syslog.h> + +#include <termios.h> +#include <fcntl.h> + +// 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); + + // 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; + } + + // 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]; + + //<mac address>_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); + printf ("VOLTAGE: %f\n", output_voltage); + CPhidgetAnalog_setVoltage (Aphid, output_port, + output_voltage); + usleep (100000); + CPhidgetAnalog_getVoltage (Aphid, output_port, + &output_voltage_result); + printf ("VOLTAGE_RESULT: %f\n", 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); + } + } + } + } +} diff --git a/src/phidgetcontrol.cfg b/src/phidgetcontrol.cfg new file mode 100644 index 0000000..e9ff094 --- /dev/null +++ b/src/phidgetcontrol.cfg @@ -0,0 +1,42 @@ +cfg_version = 1.0; + +setup = +{ + phidgetinterfacekit = 1; + phidgetanalog = 1; +}; + +input = +( + { + type = "digital"; + port = 3; + intervalvalue = 1; + intervalunit = "m"; + }, + { + type = "analog"; + port = 2; + intervalvalue = 1; + intervalunit = "m"; + } +); + +output = +( + { + type = "digital"; + port = 2; + enabled = 1; + day = "tuesday"; + time = "12:00"; + }, + { + type = "analog"; + port = 1; + voltage = 6.0; + enabled = 1; + day = "tuesday"; + time = "12:00"; + } +); |