/*
* 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);
}
}
}
}
}