/*
* lightingcontrol
*
* 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 lightingcontrol.c -o lightingcontrol -lm `pkg-config --libs --cflags 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
// handle SIGALRM by resetting it
void
minute_check (int signum)
{
syslog (LOG_DEBUG, "SIGALRM");
alarm (60);
}
int
main (int argc, char *argv[])
{
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)
{
SYSLOG_CONSOLE_OUTPUT = LOG_PERROR;
}
}
openlog ("lightingcontrol", SYSLOG_CONSOLE_OUTPUT | LOG_PID | LOG_CONS,
LOG_USER);
syslog (LOG_INFO, "");
syslog (LOG_INFO, "lightingcontrol [%s] starting", VERSION_STRING);
syslog (LOG_INFO, "");
const char *configfile = "lightingcontrol.cfg";
config_t cfg;
const char *serial_device_address;
int serial_baud_rate;
int serial_data_bits;
const char *serial_parity;
int serial_stop_bits;
char *p;
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_string (&cfg, "serial.device", &serial_device_address)
&& config_lookup_int (&cfg, "serial.baud", &serial_baud_rate)
&& config_lookup_int (&cfg, "serial.data_bits", &serial_data_bits)
&& config_lookup_string (&cfg, "serial.parity", &serial_parity)
&& config_lookup_int (&cfg, "serial.stop_bits", &serial_stop_bits)))
{
syslog (LOG_ERR,
"Incomplete serial configuration. Check configuration file");
closelog ();
return -1;
}
syslog (LOG_INFO, "Serial Port=[%s]", serial_device_address);
syslog (LOG_INFO, "Serial Port Parameters=[%d %d %c %d]", serial_baud_rate,
serial_data_bits, serial_parity[0], serial_stop_bits);
// 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 (1);
for (;;)
{
// block until SIGARLM
select (0, NULL, NULL, NULL, NULL);
time_t t = time (NULL);
struct tm unixtime_min_time_t = *localtime (&t);
config_setting_t *schedules;
schedules = config_lookup (&cfg, "schedule");
// find number of schedules
unsigned int num_schedules = config_setting_length (schedules);
syslog (LOG_DEBUG, "num_schedules=[%d]", num_schedules);
int i;
// cycle through each schedule and pull info from config file
for (i = 0; i < num_schedules; ++i)
{
config_setting_t *scene_element =
config_setting_get_elem (schedules, i);
int sceneid;
config_setting_lookup_int (scene_element, "sceneid", &sceneid);
syslog (LOG_DEBUG, "sceneid=[%d]", sceneid);
const char *scene_day;
char scene_day_lower[20];
config_setting_lookup_string (scene_element, "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 (scene_element, "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);
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))
{
// attempt to create new serial connection
struct termios term;
int serialport = open (serial_device_address,
O_RDWR | O_NOCTTY | O_NONBLOCK);
if (serialport < 0)
{
syslog (LOG_ERR, "Unable to create serial object");
}
syslog (LOG_INFO, "serialport=[%d]", serialport);
if (serial_baud_rate == 115200)
{
term.c_cflag = B115200;
}
else if (serial_baud_rate == 57600)
{
term.c_cflag = B57600;
}
else if (serial_baud_rate == 38400)
{
term.c_cflag = B38400;
}
else if (serial_baud_rate == 19200)
{
term.c_cflag = B19200;
}
else if (serial_baud_rate == 9600)
{
term.c_cflag = B9600;
}
else if (serial_baud_rate == 4800)
{
term.c_cflag = B4800;
}
else if (serial_baud_rate == 2400)
{
term.c_cflag = B2400;
}
else if (serial_baud_rate == 1800)
{
term.c_cflag = B1800;
}
else if (serial_baud_rate == 1200)
{
term.c_cflag = B1200;
}
if (serial_data_bits == 5)
{
term.c_cflag |= CS5;
}
else if (serial_data_bits == 6)
{
term.c_cflag |= CS6;
}
else if (serial_data_bits == 7)
{
term.c_cflag |= CS7;
}
else
{
term.c_cflag |= CS8;
}
if (serial_parity == "E")
{
term.c_cflag |= PARENB;
}
else if (serial_parity == "O")
{
term.c_cflag |= PARENB | PARODD;
}
if (serial_stop_bits == 2)
{
term.c_cflag |= CSTOPB;
}
term.c_iflag = 0;
term.c_oflag = 0;
term.c_lflag = 0;
tcflush (serialport, TCIFLUSH);
tcsetattr (serialport, TCSANOW, &term);
config_setting_t *messagearray;
messagearray =
config_setting_get_member (scene_element, "message");
int j, k;
// eight byte messages
unsigned char serialmsg[8];
int nummessages;
// count number of messages to send
nummessages = config_setting_length (messagearray);
for (j = 0; j < nummessages; j++)
{
config_setting_t *message;
// iterate over each message
message = config_setting_get_elem (messagearray, j);
// ensure checksum byte is zero'd before calculation
serialmsg[7] = 0;
for (k = 0; k < 7; k++)
{
serialmsg[k] = config_setting_get_int_elem (message, k);
serialmsg[7] += serialmsg[k];
}
// checksum calculation
serialmsg[7] = (~serialmsg[7] & 0xff) + 1;
// write message out over serial port
write (serialport, serialmsg, sizeof (serialmsg));
syslog (LOG_INFO, "MESSAGE SENT");
syslog (LOG_INFO,
"[%02x][%02x][%02x][%02x][%02x][%02x][%02x][%02x]",
serialmsg[0], serialmsg[1], serialmsg[2],
serialmsg[3], serialmsg[4], serialmsg[5],
serialmsg[6], serialmsg[7]);
syslog (LOG_INFO, "SCENEID=[%d] SENT", sceneid);
syslog (LOG_INFO, "current_day=[%s]", daystring);
syslog (LOG_INFO, "current_time=[%s]", timestring);
syslog (LOG_INFO, "nummessages=[%d]", nummessages);
usleep (100);
}
close (serialport);
sleep (1);
}
}
}
}