|
From: <j-...@us...> - 2012-05-11 18:24:45
|
Revision: 809
http://openautomation.svn.sourceforge.net/openautomation/?rev=809&view=rev
Author: j-n-k
Date: 2012-05-11 18:24:37 +0000 (Fri, 11 May 2012)
Log Message:
-----------
Changed logging, rewrite fixtures, added scenes
Modified Paths:
--------------
tools/knxdmxd/knxdmxd.conf
tools/knxdmxd/src/Makefile.am
Added Paths:
-----------
tools/knxdmxd/src/cue.cc
tools/knxdmxd/src/cue.h
tools/knxdmxd/src/fixture.cc
tools/knxdmxd/src/fixture.h
tools/knxdmxd/src/knxdmxd.cc
tools/knxdmxd/src/knxdmxd.h
tools/knxdmxd/src/log.cc
tools/knxdmxd/src/log.h
Removed Paths:
-------------
tools/knxdmxd/src/knxdmxd.cpp
Modified: tools/knxdmxd/knxdmxd.conf
===================================================================
--- tools/knxdmxd/knxdmxd.conf 2012-05-11 18:16:06 UTC (rev 808)
+++ tools/knxdmxd/knxdmxd.conf 2012-05-11 18:24:37 UTC (rev 809)
@@ -2,8 +2,8 @@
{ "name" : "Treppe",
"channels" : [
{ "name": "oben",
- "knx" : "1/7/170",
- "dmx" : "1.0"
+ "dmx" : "1.0",
+ "knx" : "1/7/170"
},
{ "name": "mitte",
"knx" : "1/7/170",
@@ -16,7 +16,7 @@
],
"fading" : {
"knx" : "1/6/170",
- "time": "1.7"
+ "time": "10"
}
},
{ "name" : "Kueche",
@@ -39,12 +39,48 @@
"time": "3.0"
}
},
- { "name" : "Test",
+ { "name" : "Test"
+ } ],
+"scenes": [
+ { "name" : "Treppe_Full_On",
+ "trigger" : {
+ "knx" : "1/0/170",
+ "call" : 1
+ },
"channels" : [
- { "name": "TestC",
- "knx": "1/7/170",
- "dmx" : "1.100"
+ { "fixture" : "Treppe",
+ "channel" : "oben",
+ "value" : 255
+ },
+ { "fixture" : "Treppe",
+ "channel" : "mitte",
+ "value" : 255
+ },
+ { "fixture" : "Treppe",
+ "channel" : "unten",
+ "value" : 255
}
+ ],
+ },
+ {
+ "name" : "Treppe_Blackout",
+ "trigger" : {
+ "knx" : "1/0/170",
+ "call" : 0
+ },
+ "channels" : [
+ { "fixture" : "Treppe",
+ "channel" : "oben",
+ "value" : 0
+ },
+ { "fixture" : "Treppe",
+ "channel" : "mitte",
+ "value" : 0
+ },
+ { "fixture" : "Treppe",
+ "channel" : "unten",
+ "value" : 0
+ }
]
} ]
}
Modified: tools/knxdmxd/src/Makefile.am
===================================================================
--- tools/knxdmxd/src/Makefile.am 2012-05-11 18:16:06 UTC (rev 808)
+++ tools/knxdmxd/src/Makefile.am 2012-05-11 18:24:37 UTC (rev 809)
@@ -8,4 +8,4 @@
# this lists the binaries to produce, the (non-PHONY, binary) targets in
# the previous manual Makefile
bin_PROGRAMS = knxdmxd
-knxdmxd_SOURCES = knxdmxd.cpp
+knxdmxd_SOURCES = knxdmx.cc log.cc fixture.cc cue.cc
Added: tools/knxdmxd/src/cue.cc
===================================================================
--- tools/knxdmxd/src/cue.cc (rev 0)
+++ tools/knxdmxd/src/cue.cc 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,53 @@
+/*
+ * cue.cc
+ *
+ * (c) by JNK 2012
+ *
+ *
+*/
+
+
+#include "cue.h"
+
+namespace knxdmxd {
+
+Cue::Cue(const std::string name) {
+ _name=name;
+ std::clog << "Creating Cue '" << name << "'" << std::endl;
+}
+
+void Cue::AddTrigger(knxdmxd::knx_patch_map_t& patchMap, int KNX, int val) {
+ _triggerKNX = KNX;
+ _trigger_val = val;
+
+ std::clog << kLogDebug << "Cue '" << _name << "': Trigger by KNX:" << _triggerKNX << ", value " << _trigger_val << ((_trigger_val==-1) ? " (all)" : "") << std::endl;
+
+ std::pair<knxdmxd::knx_patch_map_t::iterator, knxdmxd::knx_patch_map_t::iterator> alreadypatched;
+ alreadypatched = patchMap.equal_range(KNX);
+
+ for (knxdmxd::knx_patch_map_t::iterator it = alreadypatched.first; it != alreadypatched.second; ++it) {
+ if (it->second == _name) return; // already patched that one
+ }
+
+ patchMap.insert(knxdmxd::knx_patch_map_element_t(KNX,_name)); // no, add to patchMap
+}
+
+void Cue::AddTrigger(knxdmxd::knx_patch_map_t& patchMap, std::string KNX, int val) {
+ AddTrigger(patchMap, readgaddr(KNX), val);
+}
+
+void Cue::AddChannel(cue_channel_t channel) {
+ _channel_data.push_back(channel);
+ std::clog << "Added Channel definition " << channel.fixture << "/" << channel.name << "@" << channel.value << std::endl;
+}
+
+void Cue::Update(std::map<std::string, knxdmxd::Fixture>& fixtureList, const int KNX, const int val) {
+ if ((_trigger_val==-1) || (_trigger_val==val)) {
+ for(std::list<cue_channel_t>::iterator it = _channel_data.begin(); it != _channel_data.end(); ++it) {
+ fixtureList[it->fixture].Update(it->name, it->value, (float)255.);
+ }
+ std::clog << "Called cue " << _name << std::endl;
+ }
+}
+
+}
Added: tools/knxdmxd/src/cue.h
===================================================================
--- tools/knxdmxd/src/cue.h (rev 0)
+++ tools/knxdmxd/src/cue.h 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,46 @@
+/*
+ * cue.h
+ *
+ * (c) by JNK 2012
+ *
+ *
+*/
+
+#ifndef CUE_H
+#define CUE_H
+
+#include <string.h>
+#include <knxdmxd.h>
+#include <list>
+#include <fixture.h>
+
+namespace knxdmxd {
+
+typedef struct {
+ std::string fixture;
+ std::string name;
+ int value;
+} cue_channel_t;
+
+class Cue {
+ public:
+ Cue() {};
+ Cue(const std::string name);
+
+ void AddTrigger(knxdmxd::knx_patch_map_t& patchMap, int KNX, int val);
+ void AddTrigger(knxdmxd::knx_patch_map_t& patchMap, std::string KNX, int val);
+ void AddChannel(cue_channel_t channel);
+
+ void Update(std::map<std::string, knxdmxd::Fixture>& fixtureList, const int KNX, const int val);
+
+ private:
+ std::string _name;
+ int _triggerKNX;
+ int _trigger_val;
+ std::list<cue_channel_t> _channel_data;
+};
+
+
+}
+
+#endif
Added: tools/knxdmxd/src/fixture.cc
===================================================================
--- tools/knxdmxd/src/fixture.cc (rev 0)
+++ tools/knxdmxd/src/fixture.cc 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,93 @@
+/*
+ * fixture.cc
+ *
+ * (c) by JNK 2012
+ *
+ *
+*/
+
+
+#include "fixture.h"
+
+namespace knxdmxd {
+
+Fixture::Fixture(const std::string name) {
+ _name=name;
+ std::clog << "Creating Fixture '" << _name << "'" << std::endl;
+}
+
+void Fixture::Patch(knx_patch_map_t& patchMap, const std::string channel, const int DMX, const int KNX=-1) {
+ _channelKNX[channel] = KNX;
+ _channelDMX[channel] = DMX;
+
+ std::clog << "Fixture '" << _name << "': Patched channel '" << channel << "' (KNX " << KNX << " to " << DMX << ") " << std::endl;
+
+ std::pair<knxdmxd::knx_patch_map_t::iterator, knxdmxd::knx_patch_map_t::iterator> alreadypatched; // fixtures that handle this
+ alreadypatched = patchMap.equal_range(KNX);
+
+ for (knxdmxd::knx_patch_map_t::iterator it = alreadypatched.first; it != alreadypatched.second; ++it) {
+ if (it->second == _name) return; // already patched that one
+ }
+
+ patchMap.insert(knxdmxd::knx_patch_map_element_t(KNX,_name)); // no, add to patchMap
+
+}
+
+void Fixture::Patch(knx_patch_map_t& patchMap, const std::string channel, const std::string DMX, const std::string KNX) {
+ Patch(patchMap, channel, readdaddr(DMX), readgaddr(KNX));
+}
+
+void Fixture::SetFadeTime(const float t) {
+ _fadeTime = t;
+ _fadeStep = (t<=0) ? 256 : 256/(t*1e6/FADING_INTERVAL);
+ std::clog << "Fixture '" << _name << "': Set global fadetime to " << _fadeTime << "s (" << _fadeStep << " steps/interval)" << std::endl;
+}
+
+void Fixture::PatchFadeTime(const int KNX) {
+ _fadeTimeKNX = KNX;
+}
+
+void Fixture::Update(std::string channel, const int val, bool direct) {
+ _channelValue[channel] = val;
+ _channelFadeStep[channel] = direct ? 256 : _fadeStep;
+ std::clog << "Fixture '" << _name << "': Channel '" << channel << "' @ " << val << ", direct: " << ((direct) ? "true" : "false") << std::endl;
+}
+
+void Fixture::Update(const int KNX, const int val, bool direct) {
+ for(std::map<std::string, int>::const_iterator i = _channelKNX.begin(); i != _channelKNX.end(); ++i) {
+ if (i->second == KNX) Update(i->first, val, direct);
+ }
+}
+
+void Fixture::Update(std::string channel, const int val, float fadeStep) {
+ _channelValue[channel] = val;
+ _channelFadeStep[channel] = fadeStep;
+ std::clog << "Fixture '" << _name << "': Channel '" << channel << "' @ " << val << ", fading: " << fadeStep << std::endl;
+}
+
+
+void Fixture::Refresh(std::map<int, ola::DmxBuffer>& output) {
+ for(std::map<std::string, int>::const_iterator i = _channelDMX.begin(); i != _channelDMX.end(); ++i) {
+ int dmxuniverse = (int) (i->second / 512) , dmxchannel = i->second % 512;
+ int oldValue = output[dmxuniverse].Get(dmxchannel);
+ int newValue = _channelValue[i->first];
+ if (oldValue<newValue) {
+ _channelFloatValue[i->first] += _channelFadeStep[i->first];
+ if (_channelFloatValue[i->first]>newValue) {
+ _channelFloatValue[i->first] = newValue;
+ }
+ output[dmxuniverse].SetChannel(dmxchannel, (int) _channelFloatValue[i->first]);
+ std::clog << "Fade: " << dmxuniverse << "." << dmxchannel << " @ " << _channelFloatValue[i->first] << std::endl;
+ }
+ if (oldValue>newValue) {
+ _channelFloatValue[i->first] -= _channelFadeStep[i->first];
+ if (_channelFloatValue[i->first]<newValue) {
+ _channelFloatValue[i->first] = newValue;
+ }
+ output[dmxuniverse].SetChannel(dmxchannel, (int) _channelFloatValue[i->first]);
+ std::clog << "Fade: " << dmxuniverse << "." << dmxchannel << " @ " << _channelFloatValue[i->first] << std::endl;
+ }
+ }
+}
+
+}
Added: tools/knxdmxd/src/fixture.h
===================================================================
--- tools/knxdmxd/src/fixture.h (rev 0)
+++ tools/knxdmxd/src/fixture.h 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,45 @@
+/*
+ * fixture.h
+ *
+ * (c) by JNK 2012
+ *
+ *
+*/
+
+#ifndef FIXTURE_H
+#define FIXTURE_H
+
+#include <string.h>
+#include <knxdmxd.h>
+
+namespace knxdmxd {
+
+class Fixture {
+ public:
+ Fixture() {};
+ Fixture(const std::string name);
+
+ void Patch(knxdmxd::knx_patch_map_t& patchMap, const std::string channel, const int DMX, const int KNX);
+ void Patch(knxdmxd::knx_patch_map_t& patchMap, const std::string channel, const std::string DMX, const std::string KNX);
+ void SetFadeTime(const float t);
+ void PatchFadeTime(const int KNX);
+ void Update(std::string channel, const int val, const bool direct=false);
+ void Update(std::string channel, const int val, const float fadeStep);
+ void Update(const int KNX, const int val, const bool direct=false);
+ void Refresh(std::map<int, ola::DmxBuffer>& output);
+ private:
+ std::string _name;
+ std::map <std::string, int> _channelKNX;
+ std::map <std::string, int> _channelDMX;
+ std::map <std::string, int> _channelValue; // set value
+ std::map <std::string, float> _channelFadeStep; // individual by channel
+ std::map <std::string, float> _channelFloatValue; // internal calculation
+
+ float _fadeTime; // is set by knx or config
+ float _fadeStep; // calculated from _fadeTime
+ int _fadeTimeKNX;
+};
+
+}
+
+#endif
Added: tools/knxdmxd/src/knxdmxd.cc
===================================================================
--- tools/knxdmxd/src/knxdmxd.cc (rev 0)
+++ tools/knxdmxd/src/knxdmxd.cc 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,533 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * knxdmxd.c
+ * Copyright (C) Jan N. Klug 2012 <jan...@ru...>
+ * Daemon skeleton by Michael Markstaller 2011 <de...@wi...>
+ *
+ * knxdmxd 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.
+ *
+ * knxdmxd 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/>.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+#include <json/json.h>
+
+#include <ola/Logging.h>
+#include <ola/StreamingClient.h>
+#include <ola/StringUtils.h>
+
+#include <pthread.h>
+#include <eibclient.h>
+
+#include <iostream>
+#include <fstream>
+#include <map>
+
+#include <knxdmxd.h>
+#include <log.h>
+
+#include <fixture.h>
+#include <cue.h>
+
+#define DEBUG 1
+#define DAEMON_NAME "knxdmxd"
+#define USAGESTRING "\n"\
+ "\t-d Run as daemon/No debug output\n"\
+ "\t-p <pidfile> PID-filename\n"\
+ "\t-u <eib url> URL to contact eibd like local:/tmp/eib or ip:192.168.0.101\n"\
+ "\t-c <config-file> Config-File\n"
+#define NUM_THREADS 4
+#define MAX_ZONES 31
+#define RETRY_TIME 5
+#define BUFLEN 1024
+#define POLLING_INTERVAL 10
+
+template<class T>
+std::string t_to_string(T i) {
+ std::stringstream ss;
+ ss << i;
+ return ss.str();
+}
+
+void daemonShutdown();
+
+eibaddr_t readgaddr (const std::string addr) {
+ int a, b, c;
+ char *s = (char *)addr.c_str();
+
+ if (sscanf (s, "%d/%d/%d", &a, &b, &c) == 3)
+ return ((a & 0x01f) << 11) | ((b & 0x07) << 8) | ((c & 0xff));
+ if (sscanf (s, "%d/%d", &a, &b) == 2)
+ return ((a & 0x01f) << 11) | ((b & 0x7FF));
+ if (sscanf (s, "%x", &a) == 1)
+ return a & 0xffff;
+ std::clog << kLogWarning << "invalid group address format " << addr << std::endl;
+ daemonShutdown();
+ return 0;
+}
+
+int readdaddr (const std::string addr) {
+ int universe, channel;
+ sscanf( (char*)addr.c_str(), "%d.%d", &universe, &channel);
+ if (channel==-1) { // default universe is 1
+ channel = universe;
+ universe = 1;
+ }
+ return (universe << 9) + channel;
+}
+
+pthread_mutex_t zonelock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t initlock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t standbylock = PTHREAD_MUTEX_INITIALIZER;
+
+std::string eibd_url = "local:/tmp/eib";
+std::string conf_file = "knxdmxd.conf";
+int pidFilehandle;
+std::string pidfilename = "/var/run/dmxknxd.pid";
+
+std::map<int, ola::DmxBuffer> dmxWriteBuffer;
+std::map<std::string, knxdmxd::Fixture> fixtureList;
+std::map<std::string, knxdmxd::Cue> sceneList;
+
+knxdmxd::knx_patch_map_t KNX_fixture_patchMap;
+knxdmxd::knx_patch_map_t KNX_scene_patchMap;
+
+//map<int, channel> DMXpatchMap;
+
+void daemonShutdown() {
+ //FIXME: clean exit pthread_exit(NULL); pthread_cancel(..);
+ std::clog << kLogInfo << DAEMON_NAME << " daemon exiting" << std::endl;
+ fprintf(stderr, "%s daemon exiting", DAEMON_NAME);
+ close(pidFilehandle);
+ unlink((char *)pidfilename.c_str());
+ exit(EXIT_SUCCESS);
+}
+
+void signal_handler(int sig) {
+ switch(sig) {
+ case SIGHUP:
+ std::clog << kLogWarning << "Received SIGHUP signal." << std::endl;
+ break;
+ case SIGTERM:
+ std::clog << kLogWarning << "Received SIGTERM signal." << std::endl;
+ daemonShutdown();
+ break;
+ case SIGINT:
+ std::clog << kLogWarning << "Received SIGINT signal." << std::endl;
+ daemonShutdown();
+ break;
+ default:
+ std::clog << kLogWarning << "Unhandled signal (" << sig << ") " << strsignal(sig) << std::endl;
+ break;
+ }
+}
+
+void refresh_output(int signo)
+{
+ for(std::map<std::string, knxdmxd::Fixture>::const_iterator i = fixtureList.begin(); i != fixtureList.end(); ++i) {
+ fixtureList[i->first].Refresh(dmxWriteBuffer);
+ }
+ signal(SIGALRM, refresh_output);
+}
+
+void *worker(void *) {
+ std::clog << "Internal worker thread started" << std::endl;
+
+ signal(SIGALRM, refresh_output);
+
+ itimerval itm;
+ itm.it_interval.tv_sec=0;
+ itm.it_value.tv_sec = 0;
+ itm.it_interval.tv_usec = FADING_INTERVAL; // 20 ms is enough
+ itm.it_value.tv_usec = FADING_INTERVAL;
+ setitimer(ITIMER_REAL,&itm,0);
+
+ while (1) {
+ sleep(POLLING_INTERVAL);
+ }
+
+ pthread_exit(NULL);
+}
+
+void *handleKNXdgram(eibaddr_t dest, unsigned char* buf, int len){
+ unsigned char val;
+ switch (buf[1] & 0xC0) {
+ case 0x00:
+// sendKNXresponse (dest,zone+(controller*ZONES_PER_CONTROLLER),func);
+ break;
+ case 0x40:
+ //FIXME: response dunno
+ break;
+ case 0x80:
+ if (buf[1] & 0xC0) {
+ if (len == 2)
+ val = buf[1] & 0x3F;
+ else
+ val = buf[2];
+
+ if (KNX_fixture_patchMap.count(dest)>0) {
+ std::pair<knxdmxd::knx_patch_map_t::iterator, knxdmxd::knx_patch_map_t::iterator> uFixtures; // fixtures that handle this
+ uFixtures = KNX_fixture_patchMap.equal_range(dest);
+ int unum=0;
+ for (knxdmxd::knx_patch_map_t::iterator it = uFixtures.first; it != uFixtures.second; ++it)
+ {
+ fixtureList[it->second].Update(dest, val);
+ unum++;
+ }
+ std::clog << "Received " << (int)val << " @ " << dest << ", updated " << unum << " fixtures" << std::endl;
+ }
+ if (KNX_scene_patchMap.count(dest)>0) {
+ std::pair<knxdmxd::knx_patch_map_t::iterator, knxdmxd::knx_patch_map_t::iterator> uScenes; // fixtures that handle this
+ uScenes = KNX_scene_patchMap.equal_range(dest);
+ int unum=0;
+ for (knxdmxd::knx_patch_map_t::iterator it = uScenes.first; it != uScenes.second; ++it)
+ {
+ sceneList[it->second].Update(fixtureList, dest, val);
+ unum++;
+ }
+ std::clog << "Received " << (int) val << " @ " << dest << ", checked " << unum << " scenes" << std::endl;
+ }
+
+
+ }
+ break;
+ }
+ return 0;
+}
+
+
+void *olahandler(void *) { // thread just reliably sends the data to DMX via OLA
+ std::clog << kLogDebug << "OLA sender thread started" << std::endl;
+
+ ola::InitLogging(ola::OLA_LOG_WARN, ola::OLA_LOG_STDERR);
+
+ while (1) { // retry forever
+
+ ola::StreamingClient ola_client;
+
+ if (!ola_client.Setup()) { // setup client
+ std::clog << kLogWarning << "OLA: Client setup failed" << std::endl;
+ sleep(RETRY_TIME);
+ continue;
+ }
+
+ std::clog << kLogInfo << "OLA: Client connected" << std::endl;
+
+ while (1) { // loop forever
+ int error_flag=0;
+ for(std::map<int, ola::DmxBuffer>::const_iterator i = dmxWriteBuffer.begin(); i != dmxWriteBuffer.end(); ++i) {
+ int universe = i->first;
+ if (!ola_client.SendDmx(universe, i->second)) { // send all universes
+ std::clog << kLogWarning << "OLA: failed to send universe "<< universe << std::endl;
+ error_flag = 1;
+ break; // something went wrong
+ }
+ }
+ if (error_flag==1) {
+ sleep(RETRY_TIME);
+ break;
+ }
+
+ usleep(20000);
+ }
+
+ ola_client.Stop(); // close the client
+ }
+
+ pthread_exit(NULL);
+}
+
+
+void *knxhandler(void *) {
+ std::clog << "KNX reader thread started" << std::endl;
+ int len;
+ EIBConnection *con;
+ eibaddr_t dest;
+ eibaddr_t src;
+ unsigned char buf[255];
+
+ while (1) //retry infinite
+ {
+ con = EIBSocketURL ((char *)eibd_url.c_str());
+ if (!con) {
+ std::clog << kLogWarning << "eibd: Open failed" << std::endl;
+ sleep(RETRY_TIME);
+ continue;
+ }
+
+ if (EIBOpen_GroupSocket (con, 0) == -1) {
+ std::clog << kLogWarning << "eibd: Connect failed" << std::endl;
+ sleep(RETRY_TIME);
+ continue;
+ }
+
+ while (1)
+ {
+ len = EIBGetGroup_Src (con, sizeof (buf), buf, &src, &dest);
+ if (len == -1) {
+ std::clog << kLogWarning << "eibd: Read failed" << std::endl;
+ sleep(RETRY_TIME);
+ break;
+ }
+ if (len < 2) {
+ std::clog << kLogWarning << "eibd: Invalid Packet" << std::endl;
+ break;
+ }
+ if (buf[0] & 0x3 || (buf[1] & 0xC0) == 0xC0) {
+ std::clog << kLogWarning << "eibd: Unknown APDU from "<< src << " to " << dest << std::endl;
+ break;
+ } else {
+ if ( (KNX_fixture_patchMap.count(dest)+KNX_scene_patchMap.count(dest))<=0 ) //not for us
+ continue;
+ handleKNXdgram(dest,buf,len);
+ }
+ }
+
+ std::clog << kLogWarning << "eibd: Closed connection" << std::endl; //break in read-loop
+ EIBClose (con);
+ }
+ pthread_exit(NULL);
+}
+
+void load_config() {
+
+ struct json_object *config;
+
+ config = json_object_from_file((char *)conf_file.c_str());
+
+ // first all fixtures
+ struct json_object *fixtures = json_object_object_get(config, "fixtures");
+ int fixturenum = json_object_array_length(fixtures);
+ std::clog << "Trying to import " << fixturenum << " fixtures" << std::endl;
+
+ for (int i=0; i<fixturenum; i++) { // read all
+ // get fixture
+ struct json_object *fixture = json_object_array_get_idx(fixtures, i);
+
+ // get name & create
+ struct json_object *name = json_object_object_get(fixture, "name");
+ std::string fname = (name) ? json_object_get_string(name) : "_f_"+t_to_string(i);
+ knxdmxd::Fixture f(fname);
+
+ // get channels & patch them
+ struct json_object *channels = json_object_object_get(fixture, "channels");
+ if (!channels) {
+ std::clog << kLogInfo << "Skipping fixture '" << fname << "' (no channels defined)" << std::endl;
+ continue;
+ }
+
+ int channelnum = json_object_array_length(channels);
+ for (int j=0; j<channelnum; j++) { // read all
+ // get channel
+ struct json_object *channel = json_object_array_get_idx(channels, j);
+
+ // channel name, default is _c_<num>
+ struct json_object *name = json_object_object_get(channel, "name");
+ std::string cname = (name) ? json_object_get_string(name) : "_c_"+t_to_string(j);
+
+ // dmx is required
+ struct json_object *dmx = json_object_object_get(channel, "dmx");
+ if (!dmx) {
+ std::clog << kLogInfo << "Skipping channel '" << cname << "' in fixture '" << fname << "' (missing dmx)" << std::endl;
+ continue;
+ }
+ std::string cdmx(json_object_get_string(dmx));
+
+ // knx is optional
+ struct json_object *knx = json_object_object_get(channel, "knx"); // knx is optional
+ std::string cknx = (knx) ? json_object_get_string(knx) : "";
+
+ // patch
+ f.Patch(KNX_fixture_patchMap, cname, cdmx, cknx);
+ }
+
+ // get fading
+ struct json_object *fading = json_object_object_get(fixture, "fading");
+ float ftime = (fading) ? json_object_get_double(json_object_object_get(fading, "time")) : 0;
+ f.SetFadeTime(ftime);
+
+ fixtureList[fname] = f;
+ }
+
+ struct json_object *scenes = json_object_object_get(config, "scenes");
+ int scenenum = json_object_array_length(scenes);
+ std::clog << "Trying to import " << scenenum << " scenes" << std::endl;
+
+ for (int i=0; i<scenenum; i++) { // read all
+ struct json_object *scene = json_object_array_get_idx(scenes, i);
+
+ // get name & create
+ struct json_object *name = json_object_object_get(scene, "name");
+ std::string sname = (name) ? json_object_get_string(name) : "_s_"+t_to_string(i);
+ knxdmxd::Cue s(sname);
+
+ // trigger is required
+ struct json_object *trigger = json_object_object_get(scene, "trigger");
+ struct json_object *trigger_knx = json_object_object_get(trigger, "knx");
+
+ if ((!trigger) || (!trigger_knx)) {
+ std::clog << kLogInfo << "Skipping scene '" << sname << "' (error in trigger)" << std::endl;
+ continue;
+ }
+
+ struct json_object *trigger_call = json_object_object_get(trigger, "call");
+ s.AddTrigger(KNX_scene_patchMap, json_object_get_string(trigger_knx), (trigger_call) ? json_object_get_int(trigger_call) : -1);
+
+ // get channels
+ struct json_object *channels = json_object_object_get(scene, "channels");
+ if (!channels) {
+ std::clog << kLogInfo << "Skipping scene '" << sname << "' (no channels defined)" << std::endl;
+ continue;
+ }
+
+ int channelnum = json_object_array_length(channels);
+ for (int j=0; j<channelnum; j++) { // read all
+ // get channel
+ struct json_object *channel = json_object_array_get_idx(channels, j);
+
+ struct json_object *fixt = json_object_object_get(channel, "fixture");
+ struct json_object *chan = json_object_object_get(channel, "channel");
+ struct json_object *value = json_object_object_get(channel, "value");
+
+ if ((!fixt) || (!chan) || (!value)) {
+ std::clog << kLogInfo << "Skipping errorneous channel def " << j << "' in scene '" << sname << "'" << std::endl;
+ continue;
+ }
+
+ knxdmxd::cue_channel_t channeldata;
+ channeldata.fixture = json_object_get_string(fixt);
+ channeldata.name = json_object_get_string(chan);
+ channeldata.value = json_object_get_int(value);
+
+ // add
+ s.AddChannel(channeldata);
+ }
+
+
+ sceneList[sname] = s;
+ }
+
+ return;
+}
+
+int main(int argc, char **argv) {
+ int daemonize = 0;
+ int c;
+ //char *p;
+ char pidstr[255];
+
+ while ((c = getopt (argc, argv, "dp:u:c:")) != -1)
+ switch (c) {
+ case 'd':
+ daemonize = 1;
+ break;
+ case 'p':
+ pidfilename.assign(optarg);
+ break;
+ case 'u':
+ eibd_url.assign(optarg);
+ break;
+ case 'c':
+ conf_file.assign(optarg);
+ break;
+ case '?':
+ //FIXME: check arguments better, print_usage
+ fprintf (stderr, "Unknown option `-%c'.\nUsage: %s %s", optopt, argv[0], USAGESTRING);
+ return 1;
+ default:
+ abort ();
+ }
+
+ //FIXME: clean shutdown in sub-thread with signals?
+ signal(SIGHUP, signal_handler);
+ signal(SIGTERM, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGQUIT, signal_handler);
+
+ if (!daemonize) {
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ std::clog.rdbuf(new Log(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER));
+ std::clog << "startup with debug; pidfile: " << pidfilename << ", eibd: " << eibd_url << std::endl;
+ } else {
+ setlogmask(LOG_UPTO(LOG_INFO));
+ std::clog.rdbuf(new Log(DAEMON_NAME, LOG_CONS, LOG_USER));
+ }
+
+ std::clog << kLogInfo << "using config-file " << conf_file << std::endl;
+
+ load_config();
+
+ pid_t pid, sid;
+
+ if (daemonize) {
+ std::clog << kLogInfo << "starting daemon" << std::endl;
+
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
+ }
+ if (pid > 0) {
+ exit(EXIT_SUCCESS);
+ }
+ umask(0);
+ sid = setsid();
+ if (sid < 0) {
+ exit(EXIT_FAILURE);
+ }
+ if ((chdir("/")) < 0) {
+ exit(EXIT_FAILURE);
+ }
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ }
+ //FIXME: output errors to stderr, change order
+ pidFilehandle = open((char *)pidfilename.c_str(), O_RDWR|O_CREAT, 0600);
+ if (pidFilehandle == -1 )
+ {
+ std::clog << kLogInfo << "Could not open pidfile " << pidfilename << ", exiting" << std::endl;
+ fprintf(stderr, "Could not open pidfile %s, exiting", (char *)pidfilename.c_str());
+ exit(EXIT_FAILURE);
+ }
+ if (lockf(pidFilehandle,F_TLOCK,0) == -1)
+ {
+ std::clog << kLogInfo << "Could not lock pidfile " << pidfilename << ", exiting" << std::endl;
+ fprintf(stderr, "Could not lock pidfile %s, exiting", (char *)pidfilename.c_str());
+ exit(EXIT_FAILURE);
+ }
+ sprintf(pidstr,"%d\n",getpid());
+ c = write(pidFilehandle, pidstr, strlen(pidstr));
+
+ int knxthread, olathread, workerthread;
+ pthread_t threads[NUM_THREADS];
+ // PTHREAD_CREATE_DETACHED?
+ knxthread = pthread_create(&threads[1], NULL, knxhandler, NULL); //id, thread attributes, subroutine, arguments
+ olathread = pthread_create(&threads[2], NULL, olahandler, NULL); //id, thread attributes, subroutine, arguments
+ workerthread = pthread_create(&threads[3], NULL, worker, NULL); //id, thread attributes, subroutine, arguments
+ std::clog << "Threads created: " << knxthread << " " << olathread << " " << workerthread << std::endl;
+ //TODO: Maybe another console/TCP-server/Logging thread?
+ while (1) {
+// std::clog << DAEMON_NAME << " daemon running" << std::endl;
+ sleep(POLLING_INTERVAL*1000);
+ }
+ std::clog << kLogInfo << DAEMON_NAME << " daemon exiting" << std::endl;
+ // TODO: Free any allocated resources before exiting - we never get here though -> signal handler
+ exit(EXIT_SUCCESS);
+}
Deleted: tools/knxdmxd/src/knxdmxd.cpp
===================================================================
--- tools/knxdmxd/src/knxdmxd.cpp 2012-05-11 18:16:06 UTC (rev 808)
+++ tools/knxdmxd/src/knxdmxd.cpp 2012-05-11 18:24:37 UTC (rev 809)
@@ -1,653 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-/*
- * knxdmxd.c
- * Copyright (C) Jan N. Klug 2012 <jan...@ru...>
- * Daemon skeleton by Michael Markstaller 2011 <de...@wi...>
- *
- * knxdmxd 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.
- *
- * knxdmxd 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/>.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include <signal.h>
-#include <getopt.h>
-#include <json/json.h>
-
-#include <ola/Logging.h>
-#include <ola/DmxBuffer.h>
-#include <ola/StreamingClient.h>
-#include <ola/StringUtils.h>
-
-//#include <assert.h>
-
-#include <arpa/inet.h>
-//#include <netinet/in.h>
-//#include <sys/socket.h>
-
-#include <pthread.h>
-#include <eibclient.h>
-
-#include <iostream>
-#include <fstream>
-#include <map>
-
-/*#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/xml_parser.hpp>
-#include <boost/foreach.hpp>*/
-
-#define DEBUG 1
-#define DAEMON_NAME "knxdmxd"
-#define USAGESTRING "\n"\
- "\t-d Run as daemon/No debug output\n"\
- "\t-p <pidfile> PID-filename\n"\
- "\t-u <eib url> URL to contact eibd like local:/tmp/eib or ip:192.168.0.101\n"\
- "\t-c <config-file> Config-File\n"
-#define NUM_THREADS 4
-#define MAX_ZONES 31
-#define RETRY_TIME 5
-#define BUFLEN 1024
-#define POLLING_INTERVAL 10
-#define FADING_INTERVAL 50000
-
-using namespace std;
-//namespace bpt = boost::property_tree;
-typedef vector<string> svector;
-
-void daemonShutdown();
-
-eibaddr_t readgaddr (const char *addr) {
- int a, b, c;
- if (sscanf (addr, "%d/%d/%d", &a, &b, &c) == 3)
- return ((a & 0x01f) << 11) | ((b & 0x07) << 8) | ((c & 0xff));
- if (sscanf (addr, "%d/%d", &a, &b) == 2)
- return ((a & 0x01f) << 11) | ((b & 0x7FF));
- if (sscanf (addr, "%x", &a) == 1)
- return a & 0xffff;
- syslog(LOG_WARNING,"invalid group address format %s", addr);
- daemonShutdown();
- return 0;
-}
-
-int readdaddr (const string addr) {
- int universe, channel;
- sscanf( (char*)addr.c_str(), "%d.%d", &universe, &channel);
- if (channel==-1) { // default universe is 1
- channel = universe;
- universe = 1;
- }
- return (universe << 9) + channel;
-}
-
-namespace knxdmxd {
-
-class Fixture {
- public:
- Fixture() {};
- Fixture(const string str);
-
- void Patch(map<int, svector >& patchMap, const string channel, const int DMX, const int KNX);
- void Patch(map<int, svector >& patchMap, const string channel, const string DMX, const string KNX);
- void SetFadeTime(const float t);
- void PatchFadeTime(const int KNX);
- void Update(const int KNX, const int val);
- void Refresh(map<int, ola::DmxBuffer>& output);
- private:
- string name;
- map <string, int> channelKNX;
- map <string, int> channelDMX;
- map <string, int> channelValue;
- map <string, float> channelFloatValue;
- float fadeTime, fadeStep;
- int fadeTimeKNX;
-};
-
-Fixture::Fixture(const string str) {
- name=str;
- syslog(LOG_DEBUG, "Created Fixture '%s'", (char *)str.c_str());
-}
-
-void Fixture::Patch(map<int, svector>& patchMap, const string channel, const int DMX, const int KNX) {
- channelKNX[channel] = KNX;
- channelDMX[channel] = DMX;
-
- syslog(LOG_DEBUG, "Fixture '%s': Patched channel '%s' (KNX %d to DMX %d) ", (char *)name.c_str(), (char *)channel.c_str(), KNX, DMX);
-
- svector assignedChannels = patchMap[KNX]; // check if already patched
- for (vector<string>::iterator i = assignedChannels.begin(); i != assignedChannels.end(); ++i) {
- if ((*i)==name) { // already patched;
- return;
- }
- }
-
- patchMap[KNX].push_back(name); // no, add to patchMap
-
-}
-
-void Fixture::Patch(map<int, svector>& patchMap, const string channel, const string DMX, const string KNX) {
- Patch(patchMap, channel, readdaddr(DMX), readgaddr((char *) KNX.c_str()));
-}
-
-void Fixture::SetFadeTime(const float t) {
- fadeTime = t;
- fadeStep = (t<=0) ? 256 : 256/(t*1e6/FADING_INTERVAL);
- syslog(LOG_DEBUG, "Fixture '%s': Set Fadetime to %.2f s'(%.2f steps/interval)", (char *)name.c_str(), fadeTime, fadeStep);
-}
-
-void Fixture::PatchFadeTime(const int KNX) {
- fadeTimeKNX = KNX;
-}
-
-void Fixture::Update(const int KNX, const int val) {
- for(std::map<string, int>::const_iterator i = channelKNX.begin(); i != channelKNX.end(); ++i) {
- if (i->second == KNX) {
- channelValue[i->first] = val;
- syslog(LOG_DEBUG, "Updated channel '%s' to %d", (char *)i->first.c_str(), val);
- }
- }
-}
-
-void Fixture::Refresh(map<int, ola::DmxBuffer>& output) {
- for(std::map<string, int>::const_iterator i = channelDMX.begin(); i != channelDMX.end(); ++i) {
- int dmxuniverse = (int) (i->second / 512) , dmxchannel = i->second % 512;
- int oldValue = output[dmxuniverse].Get(dmxchannel);
- int newValue = channelValue[i->first];
- if (oldValue<newValue) {
- channelFloatValue[i->first] += fadeStep;
- if (channelFloatValue[i->first]>newValue) {
- channelFloatValue[i->first] = newValue;
- }
- output[dmxuniverse].SetChannel(dmxchannel, (int) channelFloatValue[i->first]);
- }
- if (oldValue>newValue) {
- channelFloatValue[i->first] -= fadeStep;
- if (channelFloatValue[i->first]<newValue) {
- channelFloatValue[i->first] = newValue;
- }
- output[dmxuniverse].SetChannel(dmxchannel, (int) channelFloatValue[i->first]);
- }
- }
-}
-
-}
-
-pthread_mutex_t zonelock = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t initlock = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t standbylock = PTHREAD_MUTEX_INITIALIZER;
-
-string eibd_url = "local:/tmp/eib";
-string conf_file = "knxdmxd.conf";
-int pidFilehandle;
-string pidfilename = "/var/run/dmxknxd.pid";
-
-map<int, ola::DmxBuffer> dmxWriteBuffer;
-map<string, knxdmxd::Fixture> fixtureList;
-map<int, svector> patchMap;
-
-void daemonShutdown() {
- //FIXME: clean exit pthread_exit(NULL); pthread_cancel(..);
- //close(udpSocket);
- syslog(LOG_INFO, "%s daemon exiting", DAEMON_NAME);
- fprintf(stderr, "%s daemon exiting", DAEMON_NAME);
- close(pidFilehandle);
- unlink((char *)pidfilename.c_str());
- exit(EXIT_SUCCESS);
-}
-
-void signal_handler(int sig) {
- switch(sig) {
- case SIGHUP:
- syslog(LOG_WARNING, "Received SIGHUP signal.");
- break;
- case SIGTERM:
- syslog(LOG_WARNING, "Received SIGTERM signal.");
- daemonShutdown();
- break;
- case SIGINT:
- syslog(LOG_WARNING, "Received SIGINT signal.");
- daemonShutdown();
- break;
- default:
- syslog(LOG_WARNING, "Unhandled signal (%d) %s", sig, strsignal(sig));
- break;
- }
-}
-
-/*void *sendKNXdgram(int type, int dpt, eibaddr_t dest, unsigned char val) {
- int len = 0;
- EIBConnection *con;
- unsigned char buf[255] = { 0, 0x80 };
- buf[1] = type; //0x40 response, 0x80 write
- syslog(LOG_DEBUG,"Send KNX dgram Type %d DPT %d dest %d val %d",type,dpt,dest,val);
- con = EIBSocketURL ((char *)eibd_url.c_str());
- if (!con)
- syslog(LOG_WARNING,"sendknxdgram: Open failed");
- if (EIBOpenT_Group (con, dest, 1) == -1)
- syslog(LOG_WARNING,"sendknxdgram: Connect failed");
- switch (dpt)
- {
- case 0:
- len=1;
- //for(i = 0; i < strlen(val)/2; i++)
- //raw value: nothing for now
- break;
- case 1:
- buf[1] |= val & 0x3f;
- len=2;
- break;
- case 3:
- // EIS2/DPT3 4bit dim
- buf[1] |= val & 0x3f;
- len=2;
- break;
- case 5:
- buf[2] = val*255/100;
- len=3;
- break;
- case 51:
- case 5001:
- buf[2] = val;
- len=3;
- break;
- case 6:
- case 6001:
- //FIXME: This is basically wrong but as we get a uchar we expect the sender to know..
- buf[2] = val;
- len=3;
- break;
- }
-
- len = EIBSendAPDU (con, len, buf);
- if (len == -1)
- syslog (LOG_WARNING,"sendknxdram: Request failed");
- EIBClose (con);
- usleep(50*1000); //throttle a little (50ms/max 20tps)
- return 0;
-} */
-
-void sigtime(int signo)
-{
- for(std::map<string, knxdmxd::Fixture>::const_iterator i = fixtureList.begin(); i != fixtureList.end(); ++i) {
- fixtureList[i->first].Refresh(dmxWriteBuffer);
- }
- signal(SIGALRM, sigtime);
-}
-
-void *worker(void *) {
- syslog(LOG_DEBUG, "Internal worker thread started");
-
- signal(SIGALRM, sigtime);
-
- itimerval itm;
- itm.it_interval.tv_sec=0;
- itm.it_value.tv_sec = 0;
- itm.it_interval.tv_usec = FADING_INTERVAL; // 20 ms is enough
- itm.it_value.tv_usec = FADING_INTERVAL;
- setitimer(ITIMER_REAL,&itm,0);
-
- while (1) {
- sleep(POLLING_INTERVAL);
- }
-
- pthread_exit(NULL);
-}
-
-/*void *sendKNXresponse(eibaddr_t dest, int zone, int func) {
- syslog(LOG_DEBUG, "KNX response %d zone %d func %d", dest,zone,func);
- pthread_mutex_lock (&zonelock);
- switch (func) {
- case 0:
- case 20:
- sendKNXdgram (0x40,1,dest,zones[zone].zonepower);
- break;
- case 1:
- case 21:
- sendKNXdgram (0x40,51,dest,zones[zone].srcid);
- break;
- case 2:
- case 22:
- sendKNXdgram (0x40,5,dest,zones[zone].volume*2);
- break;
- case 3:
- case 23:
- if (zones[zone].bass<10)
- sendKNXdgram (0x40,51,dest,zones[zone].bass-10+256);
- else
- sendKNXdgram (0x40,51,dest,zones[zone].bass-10);
- break;
- case 4:
- case 24:
- if (zones[zone].treble<10)
- sendKNXdgram (0x40,51,dest,zones[zone].treble-10+256);
- else
- sendKNXdgram (0x40,51,dest,zones[zone].treble-10);
- break;
- case 5:
- case 25:
- sendKNXdgram (0x40,1,dest,zones[zone].loudness);
- break;
- case 6:
- case 26:
- if (zones[zone].balance<10)
- sendKNXdgram (0x40,51,dest,zones[zone].balance-10+256);
- else
- sendKNXdgram (0x40,51,dest,zones[zone].balance-10);
- break;
- case 27:
- sendKNXdgram (0x40,1,dest,zones[zone].partymode);
- break;
- case 28:
- sendKNXdgram (0x40,1,dest,zones[zone].dnd);
- break;
- case 29:
- sendKNXdgram (0x40,5,dest,zones[zone].onvolume*2);
- break;
- }
- pthread_mutex_unlock (&zonelock);
- return 0;
-}
-*/
-void *handleKNXdgram(eibaddr_t dest, unsigned char* buf, int len){
- unsigned char val;
- switch (buf[1] & 0xC0) {
- case 0x00:
-// sendKNXresponse (dest,zone+(controller*ZONES_PER_CONTROLLER),func);
- break;
- case 0x40:
- //FIXME: response dunno
- break;
- case 0x80:
- if (buf[1] & 0xC0) {
- if (len == 2)
- val = buf[1] & 0x3F;
- else
- val = buf[2];
- svector uFixtures = patchMap.find(dest)->second;
- for (unsigned int i=0; i < uFixtures.size(); i++) {
- fixtureList[uFixtures[i]].Update(dest, val);
- }
- syslog(LOG_DEBUG, "Received %d @ %d, updated %d fixtures", val, dest, (int) uFixtures.size());
- }
- break;
- }
- return 0;
-}
-
-
-void *olahandler(void *) { // thread just reliably sends the data to DMX via OLA
- syslog(LOG_DEBUG, "OLA sender thread started");
-
- ola::InitLogging(ola::OLA_LOG_WARN, ola::OLA_LOG_STDERR);
-
- while (1) { // retry forever
-
- ola::StreamingClient ola_client;
-
- if (!ola_client.Setup()) { // setup client
- syslog(LOG_WARNING, "OLA: Client setup failed");
- sleep(RETRY_TIME);
- continue;
- }
-
- syslog(LOG_INFO, "OLA: Client connected");
-
- while (1) { // loop forever
- int error_flag=0;
- for(std::map<int, ola::DmxBuffer>::const_iterator i = dmxWriteBuffer.begin(); i != dmxWriteBuffer.end(); ++i) {
- int universe = i->first;
- if (!ola_client.SendDmx(universe, i->second)) { // send all universes
- syslog(LOG_WARNING, "OLA: failed to send universe %d", universe);
- error_flag = 1;
- break; // something went wrong
- }
- }
- if (error_flag==1) {
- sleep(RETRY_TIME);
- break;
- }
-
- usleep(20000);
- }
-
- ola_client.Stop(); // close the client
- }
-
- pthread_exit(NULL);
-}
-
-
-void *knxhandler(void *) {
- syslog(LOG_DEBUG, "KNX reader thread started");
- int len;
- EIBConnection *con;
- eibaddr_t dest;
- eibaddr_t src;
- unsigned char buf[255];
-
- while (1) //retry infinite
- {
- con = EIBSocketURL ((char *)eibd_url.c_str());
- if (!con) {
- syslog(LOG_WARNING, "eibd: Open failed");
- sleep(RETRY_TIME);
- continue;
- }
-
- if (EIBOpen_GroupSocket (con, 0) == -1) {
- syslog(LOG_WARNING, "eibd: Connect failed");
- sleep(RETRY_TIME);
- continue;
- }
-
- while (1)
- {
- len = EIBGetGroup_Src (con, sizeof (buf), buf, &src, &dest);
- if (len == -1) {
- syslog(LOG_WARNING, "eibd: Read failed");
- sleep(RETRY_TIME);
- break;
- }
- if (len < 2) {
- syslog(LOG_WARNING, "eibd: Invalid Packet");
- break;
- }
- if (buf[0] & 0x3 || (buf[1] & 0xC0) == 0xC0) {
- syslog(LOG_WARNING, "eibd: Unknown APDU from %d to %d",src,dest);
- break;
- } else {
- if ( patchMap.count(dest)<=0 ) //not for us
- continue;
- handleKNXdgram(dest,buf,len);
- }
- }
- syslog(LOG_WARNING,"eibd: closed connection"); //break in read-loop
- EIBClose (con);
- }
- pthread_exit(NULL);
-}
-
-void load_config() {
-
-/* bpt::ptree config;
-
- read_xml(conf_file, config);
-
- BOOST_FOREACH( bpt::ptree::value_type const& e, config) {
- if( e.first == "fixture" ) {
- string name = e.second.get<std::string>("<xmlattr>.name");
- knxdmxd::Fixture f(name);
- BOOST_FOREACH( bpt::ptree::value_type const& c, e.second) {
- if (c.first == "channel") {
- f.Patch(patchMap, c.second.data(), c.second.get<std::string>("<xmlattr>.dmx"), c.second.get<std::string>("<xmlattr>.knx"));
- }
- if (c.first == "fading") {
- float t;
- string content = c.second.data();
- sscanf((char*) content.c_str(), "%f", &t);
- f.SetFadeTime((int) (t*1.e6));
- }
- }
- fixtureList[name] = f;
- }
-
- } */
- struct json_object *config;
-
- config = json_object_from_file((char *)conf_file.c_str());
- // first all fixtures
- struct json_object *fixtures = json_object_object_get(config, "fixtures");
-
- int fixturenum = json_object_array_length(fixtures);
-
- for (int i=0; i<fixturenum; i++) { // read all
- // get fixture
- struct json_object *fixture = json_object_array_get_idx(fixtures, i);
-
- // get name & create
- string fname(json_object_get_string(json_object_object_get(fixture, "name")));
- knxdmxd::Fixture f(fname);
-
- // get channels & patch them
- struct json_object *channels = json_object_object_get(fixture, "channels");
- int channelnum = json_object_array_length(channels);
- for (int j=0; j<channelnum; j++) { // read all
- // get channel
- struct json_object *channel = json_object_array_get_idx(channels, j);
- string cname(json_object_get_string(json_object_object_get(channel, "name")));
- string cdmx(json_object_get_string(json_object_object_get(channel, "dmx")));
- string cknx(json_object_get_string(json_object_object_get(channel, "knx")));
- f.Patch(patchMap, cname, cdmx, cknx);
- }
-
- // get fading
- struct json_object *fading = json_object_object_get(fixture, "fading");
- float ftime = (fading) ? json_object_get_double(json_object_object_get(fading, "time")) : 0;
- f.SetFadeTime(ftime);
-
- fixtureList[fname] = f;
- }
-
- return;
-}
-
-int main(int argc, char **argv) {
- int daemonize = 0;
- int c;
- //char *p;
- char pidstr[255];
-
- while ((c = getopt (argc, argv, "dp:u:c:")) != -1)
- switch (c) {
- case 'd':
- daemonize = 1;
- break;
- case 'p':
- pidfilename.assign(optarg);
- break;
- case 'u':
- eibd_url.assign(optarg);
- break;
- case 'c':
- conf_file.assign(optarg);
- break;
- case '?':
- //FIXME: check arguments better, print_usage
- fprintf (stderr, "Unknown option `-%c'.\nUsage: %s %s", optopt, argv[0], USAGESTRING);
- return 1;
- default:
- abort ();
- }
-
- //FIXME: clean shutdown in sub-thread with signals?
- signal(SIGHUP, signal_handler);
- signal(SIGTERM, signal_handler);
- signal(SIGINT, signal_handler);
- signal(SIGQUIT, signal_handler);
-
- if (!daemonize) {
- setlogmask(LOG_UPTO(LOG_DEBUG));
- openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
- syslog(LOG_DEBUG, "startup with debug; pidfile: %s, eibd: %s",
- (char *)pidfilename.c_str(), (char *)eibd_url.c_str());
- } else {
- setlogmask(LOG_UPTO(LOG_INFO));
- openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
- }
-
- syslog(LOG_INFO, "using config-file %s", (char *)conf_file.c_str());
-
- load_config();
-
- pid_t pid, sid;
-
- if (daemonize) {
- syslog(LOG_INFO, "starting daemon");
-
- pid = fork();
- if (pid < 0) {
- exit(EXIT_FAILURE);
- }
- if (pid > 0) {
- exit(EXIT_SUCCESS);
- }
- umask(0);
- sid = setsid();
- if (sid < 0) {
- exit(EXIT_FAILURE);
- }
- if ((chdir("/")) < 0) {
- exit(EXIT_FAILURE);
- }
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- }
- //FIXME: output errors to stderr, change order
- pidFilehandle = open((char *)pidfilename.c_str(), O_RDWR|O_CREAT, 0600);
- if (pidFilehandle == -1 )
- {
- syslog(LOG_INFO, "Could not open pidfile %s, exiting", (char *)pidfilename.c_str());
- fprintf(stderr, "Could not open pidfile %s, exiting", (char *)pidfilename.c_str());
- exit(EXIT_FAILURE);
- }
- if (lockf(pidFilehandle,F_TLOCK,0) == -1)
- {
- syslog(LOG_INFO, "Could not lock pidfile %s, exiting", (char *)pidfilename.c_str());
- fprintf(stderr, "Could not lock pidfile %s, exiting", (char *)pidfilename.c_str());
- exit(EXIT_FAILURE);
- }
- sprintf(pidstr,"%d\n",getpid());
- c = write(pidFilehandle, pidstr, strlen(pidstr));
-
- int knxthread, olathread, workerthread;
- pthread_t threads[NUM_THREADS];
- // PTHREAD_CREATE_DETACHED?
- knxthread = pthread_create(&threads[1], NULL, knxhandler, NULL); //id, thread attributes, subroutine, arguments
- olathread = pthread_create(&threads[2], NULL, olahandler, NULL); //id, thread attributes, subroutine, arguments
- workerthread = pthread_create(&threads[3], NULL, worker, NULL); //id, thread attributes, subroutine, arguments
- syslog(LOG_DEBUG,"Threads created: %d %d %d",knxthread, olathread, workerthread);
- //TODO: Maybe another console/TCP-server/Logging thread?
- while (1) {
-// syslog(LOG_DEBUG, "%s daemon running", DAEMON_NAME);
- sleep(POLLING_INTERVAL);
- }
- syslog(LOG_INFO, "%s daemon exiting", DAEMON_NAME);
- // TODO: Free any allocated resources before exiting - we never get here though -> signal handler
- exit(EXIT_SUCCESS);
-}
Added: tools/knxdmxd/src/knxdmxd.h
===================================================================
--- tools/knxdmxd/src/knxdmxd.h (rev 0)
+++ tools/knxdmxd/src/knxdmxd.h 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,33 @@
+/*
+ * knxdmxd.h
+ *
+ * (c) by JNK 2012
+ *
+ *
+*/
+
+#ifndef KNXDMXD_H
+#define KNXDMXD_H
+
+#include <iostream>
+#include <map>
+#include <vector>
+#include <log.h>
+
+#include <eibclient.h>
+#include <ola/DmxBuffer.h>
+
+#define FADING_INTERVAL 25000 // in us
+
+namespace knxdmxd {
+ typedef std::vector<std::string> svector_t;
+ typedef std::pair<int, std::string> knx_patch_map_element_t;
+ typedef std::multimap<int, std::string> knx_patch_map_t;
+}
+
+eibaddr_t readgaddr (const std::string addr);
+int readdaddr (const std::string addr);
+
+#endif
+
+
Added: tools/knxdmxd/src/log.cc
===================================================================
--- tools/knxdmxd/src/log.cc (rev 0)
+++ tools/knxdmxd/src/log.cc 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,47 @@
+/*
+ * log.cc
+ *
+ * by eater (2010)
+ * modfied by JNK 2012
+ *
+ * copied from stackoverflow.com/questions/2638654/redirect-c-stdclog-to-syslog-on-unix
+ *
+ * licensed under creative commons
+ *
+*/
+
+#include "log.h"
+
+Log::Log(std::string ident, int option, int facility) {
+ facility_ = facility;
+ option_ = option;
+ priority_ = LOG_DEBUG;
+ strncpy(ident_, ident.c_str(), sizeof(ident_));
+ ident_[sizeof(ident_)-1] = '\0';
+
+ openlog(ident_, option_, facility_);
+}
+
+int Log::sync() {
+ if (buffer_.length()) {
+ syslog(priority_, buffer_.c_str());
+ buffer_.erase();
+ priority_ = LOG_DEBUG; // default to debug for each message
+ }
+ return 0;
+}
+
+int Log::overflow(int c) {
+ if (c != EOF) {
+ buffer_ += static_cast<char>(c);
+ } else {
+ sync();
+ }
+ return c;
+}
+
+std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority) {
+ static_cast<Log *>(os.rdbuf())->priority_ = (int)log_priority;
+ return os;
+}
+
Added: tools/knxdmxd/src/log.h
===================================================================
--- tools/knxdmxd/src/log.h (rev 0)
+++ tools/knxdmxd/src/log.h 2012-05-11 18:24:37 UTC (rev 809)
@@ -0,0 +1,51 @@
+/*
+ * log.h
+ *
+ * by eater (2010)
+ * modfied by JNK 2012
+ *
+ * copied from stackoverflow.com/questions/2638654/redirect-c-stdclog-to-syslog-on-unix
+ *
+ * licensed under creative commons
+ *
+*/
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <syslog.h>
+#include <iostream>
+#include <string.h>
+#include <fstream>
+
+enum LogPriority {
+ kLogEmerg = LOG_EMERG, // system is unusable
+ kLogAlert = LOG_ALERT, // action must be taken immediately
+ kLogCrit = LOG_CRIT, // critical conditions
+ kLogErr = LOG_ERR, // error conditions
+ kLogWarning = LOG_WARNING, // warning conditions
+ kLogNotice = LOG_NOTICE, // normal, but significant, condition
+ kLogInfo = LOG_INFO, // informational message
+ kLogDebug = LOG_DEBUG // debug-level message
+};
+
+std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority);
+
+class Log : public std::basic_streambuf<char, std::char_traits<char> > {
+public:
+ explicit Log(std::string ident, int option, int facility);
+
+protected:
+ int sync();
+ int overflow(int c);
+
+private:
+ friend std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority);
+ std::string buffer_;
+ int facility_;
+ int priority_;
+ int option_;
+ char ident_[50];
+};
+
+#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|