aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/phidgetcontrol.c469
-rw-r--r--src/phidgetcontrol.cfg42
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";
+ }
+);