From cfbdf5c48ba58bb97db1717d0aa852f3cd797cff Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Mon, 1 Oct 2012 21:30:05 +0100 Subject: Import lightingcontrol.{c,cfg} --- src/lightingcontrol.c | 323 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lightingcontrol.cfg | 44 +++++++ 2 files changed, 367 insertions(+) create mode 100644 src/lightingcontrol.c create mode 100644 src/lightingcontrol.cfg diff --git a/src/lightingcontrol.c b/src/lightingcontrol.c new file mode 100644 index 0000000..11384d6 --- /dev/null +++ b/src/lightingcontrol.c @@ -0,0 +1,323 @@ +/* + * 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); + + } + } + } +} diff --git a/src/lightingcontrol.cfg b/src/lightingcontrol.cfg new file mode 100644 index 0000000..945a44c --- /dev/null +++ b/src/lightingcontrol.cfg @@ -0,0 +1,44 @@ +cfg_version = 0.99; + +serial = +{ + device = "/dev/ttyS0"; + baud = 9600; + data_bits = 8; + parity = "N"; + stop_bits = 1; +}; + +schedule = +( + { + #Scene 1 – Daytime, mall open + sceneid = 1; + day = "monday" + time = "02:06"; + message = ( + [0x1c,0x01,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x02,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x03,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x04,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x05,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x00,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x03,0x0a,0x04,0x00,0x00,0xff] + ); + }, + { + #Scene 2 – Nighttime, mall open + sceneid = 1; + day = "WEDNESDAY" + time = "10:12"; + message = ( + [0x1c,0x01,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x02,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x03,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x04,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x05,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x00,0x20,0x03,0x00,0x00,0xff], + [0x1c,0x03,0x0a,0x04,0x00,0x00,0xff] + ); + } +); -- cgit v1.2.3