1 /*
2     LinKNX KNX home automation platform
3     Copyright (C) 2007 Jean-François Meessen <linknx@ouaye.net>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include "objectcontroller.h"
21 #include "persistentstorage.h"
22 #include "services.h"
23 #include <cmath>
24 #include <cassert>
25 #include <iomanip>
26 
27 ObjectController* ObjectController::instance_m;
28 
29 Logger& Object::logger_m(Logger::getInstance("Object"));
30 
Object()31 Object::Object() : init_m(false), flags_m(Default), refCount_m(0), gad_m(0), readRequestGad_m(0), persist_m(false), writeLog_m(false), readPending_m(false)
32 {}
33 
~Object()34 Object::~Object()
35 {
36     if (refCount_m > 0)
37         logger_m.errorStream() << "Object (id=" << getID() << "): deleted object still has " << refCount_m << " references" << endlog;
38 }
39 
create(const std::string & type)40 Object* Object::create(const std::string& type)
41 {
42     if (type == "" || type == "EIS1" || type == "1.001")
43         return new SwitchingSwitchObject();
44     else if (type.compare(0, 2, "1.") == 0)
45     {
46         if (type == "1.002")
47             return new SwitchingObjectImpl<SwitchingImplObjectValue<2> >();
48         else if (type == "1.003")
49             return new SwitchingObjectImpl<SwitchingImplObjectValue<3> >();
50         else if (type == "1.004")
51             return new SwitchingObjectImpl<SwitchingImplObjectValue<4> >();
52         else if (type == "1.005")
53             return new SwitchingObjectImpl<SwitchingImplObjectValue<5> >();
54         else if (type == "1.006")
55             return new SwitchingObjectImpl<SwitchingImplObjectValue<6> >();
56         else if (type == "1.007")
57             return new SwitchingObjectImpl<SwitchingImplObjectValue<7> >();
58         else if (type == "1.008")
59             return new SwitchingObjectImpl<SwitchingImplObjectValue<8> >();
60         else if (type == "1.009")
61             return new SwitchingObjectImpl<SwitchingImplObjectValue<9> >();
62         else if (type == "1.010")
63             return new SwitchingObjectImpl<SwitchingImplObjectValue<10> >();
64         else if (type == "1.011")
65             return new SwitchingObjectImpl<SwitchingImplObjectValue<11> >();
66         else if (type == "1.012")
67             return new SwitchingObjectImpl<SwitchingImplObjectValue<12> >();
68         else if (type == "1.013")
69             return new SwitchingObjectImpl<SwitchingImplObjectValue<13> >();
70         else if (type == "1.014")
71             return new SwitchingObjectImpl<SwitchingImplObjectValue<14> >();
72         else return 0;
73     }
74     else if (type.compare(0, 2, "2.") == 0)
75     {
76         if (type == "2.xxx")
77             return new SwitchingControlObject<SwitchingControlImplObjectValue<0> >();
78         else if (type == "2.001")
79             return new SwitchingControlObject<SwitchingControlImplObjectValue<1> >();
80         else if (type == "2.002")
81             return new SwitchingControlObject<SwitchingControlImplObjectValue<2> >();
82         else if (type == "2.003")
83             return new SwitchingControlObject<SwitchingControlImplObjectValue<3> >();
84         else if (type == "2.004")
85             return new SwitchingControlObject<SwitchingControlImplObjectValue<4> >();
86         else if (type == "2.005")
87             return new SwitchingControlObject<SwitchingControlImplObjectValue<5> >();
88         else if (type == "2.006")
89             return new SwitchingControlObject<SwitchingControlImplObjectValue<6> >();
90         else if (type == "2.007")
91             return new SwitchingControlObject<SwitchingControlImplObjectValue<7> >();
92         else if (type == "2.008")
93             return new SwitchingControlObject<SwitchingControlImplObjectValue<8> >();
94         else if (type == "2.009")
95             return new SwitchingControlObject<SwitchingControlImplObjectValue<9> >();
96         else if (type == "2.010")
97             return new SwitchingControlObject<SwitchingControlImplObjectValue<10> >();
98         else if (type == "2.011")
99             return new SwitchingControlObject<SwitchingControlImplObjectValue<11> >();
100         else if (type == "2.012")
101             return new SwitchingControlObject<SwitchingControlImplObjectValue<12> >();
102         else return 0;
103     }
104     else if (type == "EIS2" || type == "3.007")
105         return new DimmingObject();
106     else if (type == "3.008")
107         return new BlindsObject();
108     else if (type == "4.001")
109         return new AsciiCharObject();
110     else if (type == "4.002")
111         return new Latin1CharObject();
112     else if (type == "EIS3" || type == "10.001")
113         return new TimeObject();
114     else if (type == "EIS4" || type == "11.001")
115         return new DateObject();
116     else if (type == "EIS5" || type == "9.xxx")
117         return new ValueObjectImpl<ValueImplObjectValue<0> >();
118     else if (type.compare(0, 2, "9.") == 0)
119     {
120         if (type == "9.001")
121             return new ValueObjectImpl<ValueImplObjectValue<1> >();
122         else if (type == "9.002")
123             return new ValueObjectImpl<ValueImplObjectValue<2> >();
124         else if (type == "9.003")
125             return new ValueObjectImpl<ValueImplObjectValue<3> >();
126         else if (type == "9.004")
127             return new ValueObjectImpl<ValueImplObjectValue<4> >();
128         else if (type == "9.005")
129             return new ValueObjectImpl<ValueImplObjectValue<5> >();
130         else if (type == "9.006")
131             return new ValueObjectImpl<ValueImplObjectValue<6> >();
132         else if (type == "9.007")
133             return new ValueObjectImpl<ValueImplObjectValue<7> >();
134         else if (type == "9.008")
135             return new ValueObjectImpl<ValueImplObjectValue<8> >();
136         else if (type == "9.010")
137             return new ValueObjectImpl<ValueImplObjectValue<10> >();
138         else if (type == "9.011")
139             return new ValueObjectImpl<ValueImplObjectValue<11> >();
140         else if (type == "9.020")
141             return new ValueObjectImpl<ValueImplObjectValue<20> >();
142         else if (type == "9.021")
143             return new ValueObjectImpl<ValueImplObjectValue<21> >();
144         else if (type == "9.022")
145             return new ValueObjectImpl<ValueImplObjectValue<22> >();
146         else if (type == "9.023")
147             return new ValueObjectImpl<ValueImplObjectValue<23> >();
148         else if (type == "9.024")
149             return new ValueObjectImpl<ValueImplObjectValue<24> >();
150         else if (type == "9.025")
151             return new ValueObjectImpl<ValueImplObjectValue<25> >();
152         else if (type == "9.026")
153             return new ValueObjectImpl<ValueImplObjectValue<26> >();
154         else if (type == "9.027")
155             return new ValueObjectImpl<ValueImplObjectValue<27> >();
156         else if (type == "9.028")
157             return new ValueObjectImpl<ValueImplObjectValue<28> >();
158         else return 0;
159     }
160     else if (type == "14.xxx")
161         return new ValueObject32();
162     else if (type == "EIS6" || type == "5.xxx")
163         return new U8Object();
164     else if (type == "5.001")
165         return new ScalingObject();
166     else if (type == "5.003")
167         return new AngleObject();
168     else if (type == "5.010")
169         return new U8CountObject();
170     else if (type == "heat-mode" || type == "20.102")
171         return new HeatingModeObject();
172     else if (type == "EIS10" || type == "7.xxx")
173         return new U16Object();
174     else if (type == "EIS11" || type == "12.xxx")
175         return new U32Object();
176     else if (type == "EIS14" || type == "6.xxx")
177         return new S8Object();
178     else if (type == "8.xxx")
179         return new S16Object();
180     else if (type == "13.xxx")
181         return new S32Object();
182 #ifdef STL_STREAM_SUPPORT_INT64
183     else if (type == "29.xxx")
184         return new S64Object();
185 #endif
186     else if (type == "16.001")
187         return new String14Object();
188     else if (type == "EIS15" || type == "16.000")
189         return new String14AsciiObject();
190     else if (type == "28.001")
191         return new StringObject();
192     else if (type == "232.600")
193         return new RGBObject();
194     else
195         return 0;
196 }
197 
create(ticpp::Element * pConfig)198 Object* Object::create(ticpp::Element* pConfig)
199 {
200     std::string type = pConfig->GetAttribute("type");
201     Object* obj = Object::create(type);
202     if (obj == 0)
203     {
204         std::stringstream msg;
205         msg << "Object type not supported: '" << type << "'" << std::endl;
206         throw ticpp::Exception(msg.str());
207     }
208     obj->importXml(pConfig);
209     return obj;
210 }
211 
setValue(ObjectValue * value)212 void Object::setValue(ObjectValue* value)
213 {
214     if (set(value) || forceUpdate())
215         onInternalUpdate();
216 }
217 
setFloatValue(double value)218 void Object::setFloatValue(double value)
219 {
220     if (set(value) || forceUpdate())
221         onInternalUpdate();
222 }
223 
get()224 ObjectValue* Object::get()
225 {
226     if (!init_m)
227         read();
228     logger_m.debugStream() << "Object (id=" << getID() << "): get" << endlog;
229     return getObjectValue();
230 }
231 
importXml(ticpp::Element * pConfig)232 void Object::importXml(ticpp::Element* pConfig)
233 {
234     std::string type = pConfig->GetAttribute("type");
235     if (type != getType())
236     {
237         // sometimes, different type strings refer to the same type
238         // in that case, create a temporary object just to get the type string.
239         Object* obj = Object::create(type);
240         type = obj->getType();
241         delete obj;
242         if (type != getType())
243             throw ticpp::Exception("Changing type of existing object is not allowed");
244     }
245     std::string id = pConfig->GetAttribute("id");
246     if (id == "")
247         throw ticpp::Exception("Missing or empty object ID");
248     if(id.find("/", 0) != std::string::npos)
249     {
250         std::stringstream msg;
251         msg << "Slash character '/' not allowed in Object ID: " << id <<std::endl;
252         throw ticpp::Exception(msg.str());
253     }
254 
255     if (id_m == "")
256         id_m = id;
257 
258     std::string gad = pConfig->GetAttributeOrDefault("gad", "nochange");
259     // set default value to "nochange" just to see if the attribute was present or not in xml
260     if (gad == "")
261         gad_m = 0;
262     else if (gad != "nochange")
263         gad_m = Object::ReadGroupAddr(gad);
264     readRequestGad_m = gad_m;
265 
266     bool has_descr = false;
267     bool has_listener = false;
268     ticpp::Iterator< ticpp::Node > child;
269     for ( child = pConfig->FirstChild(false); child != child.end(); child++ )
270     {
271         std::string val = child->Value();
272         if (child->Type() == TiXmlNode::TEXT && val.length())
273         {
274             if (!has_descr)
275             {
276                 descr_m = "";
277                 has_descr = true;
278             }
279             descr_m.append(val);
280         }
281         else if (child->Type() == TiXmlNode::ELEMENT && val == "listener")
282         {
283             if (!has_listener)
284             {
285                 listenerGadList_m.clear();
286                 has_listener = true;
287             }
288             std::string listener_gad = child->ToElement()->GetAttribute("gad");
289             eibaddr_t gad = Object::ReadGroupAddr(listener_gad);
290             listenerGadList_m.push_back(gad);
291             if (child->ToElement()->GetAttribute("read") == "true")
292                 readRequestGad_m = gad;
293         }
294         //        else
295         //        {
296         //            std::stringstream msg;
297         //            msg << "Invalid element '" << val << "' inside object definition" << std::endl;
298         //            throw ticpp::Exception(msg.str());
299         //        }
300     }
301 
302     try
303     {
304         std::string flags;
305         pConfig->GetAttribute("flags", &flags);
306         flags_m = 0;
307         if (flags.find('c') != flags.npos)
308             flags_m |= Comm;
309         if (flags.find('r') != flags.npos)
310             flags_m |= Read;
311         if (flags.find('w') != flags.npos)
312             flags_m |= Write;
313         if (flags.find('t') != flags.npos)
314             flags_m |= Transmit;
315         if (flags.find('u') != flags.npos)
316             flags_m |= Update;
317         if (flags.find('i') != flags.npos)
318             flags_m |= Init;
319         if (flags.find('s') != flags.npos || flags.find('f') != flags.npos)
320             flags_m |= Stateless;
321     }
322     catch( ticpp::Exception& ex )
323     {
324         flags_m = Default;
325     }
326 
327     writeLog_m = (pConfig->GetAttribute("log") == "true");
328 
329     std::string precision = pConfig->GetAttribute("precision");
330     if (!precision.empty())
331         getObjectValue()->setPrecision(precision);
332 
333     // TODO: do we need to use the 'i' flag instead of init="request" attribute
334     persist_m = false;
335     initValue_m = pConfig->GetAttribute("init");
336     if (initValue_m == "persist")
337     {
338         PersistentStorage *persistence = Services::instance()->getPersistentStorage();
339         if (persistence)
340         {
341             std::string val = persistence->read(id_m);
342             if (val != "")
343             {
344                 ObjectValue *objval = createObjectValue(val);
345                 set(objval); // Here, we use set() instead of setValue() to avoid call to onInternalUpdate()
346                 delete objval;
347             }
348             persist_m = true;
349         }
350         else
351         {
352             std::stringstream msg;
353             msg << "Unable to persist object '" << id_m << "'; PersistentStorage not configured" << std::endl;
354             throw ticpp::Exception(msg.str());
355         }
356     }
357     else if (initValue_m != "" && initValue_m != "request")
358     {
359         ObjectValue *objval = createObjectValue(initValue_m);
360         set(objval); // Here, we use set() instead of setValue() to avoid call to onInternalUpdate()
361         delete objval;
362     }
363 
364     logger_m.infoStream() << "Configured object '" << id_m << "': gad=" << WriteGroupAddr(gad_m) << endlog;
365 }
366 
exportXml(ticpp::Element * pConfig)367 void Object::exportXml(ticpp::Element* pConfig)
368 {
369     pConfig->SetAttribute("type", getType());
370     pConfig->SetAttribute("id", id_m);
371 
372     if (gad_m != 0)
373         pConfig->SetAttribute("gad", WriteGroupAddr(gad_m));
374 
375     if (initValue_m != "")
376         pConfig->SetAttribute("init", initValue_m);
377 
378     if (writeLog_m)
379         pConfig->SetAttribute("log", "true");
380 
381     std::string precision = getObjectValue()->getPrecision();
382     if (!precision.empty())
383         pConfig->SetAttribute("precision", precision);
384 
385 
386     if (flags_m != Default)
387     {
388         std::stringstream flags;
389         if (flags_m & Comm)
390             flags << 'c';
391         if (flags_m & Read)
392             flags << 'r';
393         if (flags_m & Write)
394             flags << 'w';
395         if (flags_m & Transmit)
396             flags << 't';
397         if (flags_m & Update)
398             flags << 'u';
399         if (flags_m & Init)
400             flags << 'i';
401         if (flags_m & Stateless)
402             flags << 's';
403         pConfig->SetAttribute("flags", flags.str());
404     }
405 
406     if (descr_m != "")
407         pConfig->SetText(descr_m);
408 
409     ListenerGadList_t::iterator it;
410     for (it = listenerGadList_m.begin(); it != listenerGadList_m.end(); it++)
411     {
412         ticpp::Element pElem("listener");
413         pElem.SetAttribute("gad", WriteGroupAddr(*it));
414         if (readRequestGad_m == (*it))
415             pElem.SetAttribute("read", "true");
416         pConfig->LinkEndChild(&pElem);
417     }
418 }
419 
read()420 void Object::read()
421 {
422     KnxConnection* con = Services::instance()->getKnxConnection();
423     if (!readPending_m)
424     {
425         uint8_t buf[2] = { 0, 0 };
426         con->write(getReadRequestGad(), buf, 2);
427     }
428     readPending_m = true;
429 
430     pth_event_t tmout = pth_event (PTH_EVENT_TIME, pth_timeout(1,0));
431     int cnt = 0;
432     while (cnt < 100 && readPending_m)
433     {
434         if (con->isRunning())
435         {
436             if (con->checkInput(tmout) == -1)
437                 cnt = 100;
438         }
439         else
440             pth_usleep(10000);
441         ++cnt;
442     }
443     pth_event_free (tmout, PTH_FREE_THIS);
444     // If the device didn't answer after 1 second, we consider the object's
445     // default value as the current value to avoid waiting forever.
446     init_m = true;
447 }
448 
onInternalUpdate()449 void Object::onInternalUpdate()
450 {
451     if ((flags_m & Transmit) && (flags_m & Comm))
452         doSend(true);
453     onUpdate();
454 }
455 
onUpdate()456 void Object::onUpdate()
457 {
458     init_m = true;
459     logger_m.infoStream() << "New value " << getValue() << " for object " << getID() << " (type: " << getType() << ")" << endlog;
460 
461     ListenerList_t::iterator it;
462     for (it = listenerList_m.begin(); it != listenerList_m.end(); it++)
463     {
464         logger_m.debugStream() << "Calling onChange on listener for " << id_m << endlog;
465         (*it)->onChange(this);
466     }
467     if (persist_m || writeLog_m)
468     {
469         PersistentStorage *persistence = Services::instance()->getPersistentStorage();
470         if (persistence)
471         {
472             if (persist_m)
473                 persistence->write(id_m, getValue());
474             if (writeLog_m)
475                 persistence->writelog(id_m, getValue());
476         }
477     }
478 }
479 
onWrite(const uint8_t * buf,int len,eibaddr_t src)480 void Object::onWrite(const uint8_t* buf, int len, eibaddr_t src)
481 {
482     if ((flags_m & Write) && (flags_m & Comm))
483     {
484         lastTx_m = src;
485         doWrite(buf, len, src);
486     }
487 }
488 
onRead(const uint8_t * buf,int len,eibaddr_t src)489 void Object::onRead(const uint8_t* buf, int len, eibaddr_t src)
490 {
491     if ((flags_m & Read) && (flags_m & Comm))
492         doSend(false);
493 }
494 
onResponse(const uint8_t * buf,int len,eibaddr_t src)495 void Object::onResponse(const uint8_t* buf, int len, eibaddr_t src)
496 {
497     if ((flags_m & Update) && (flags_m & Comm))
498     {
499         readPending_m = false;
500         lastTx_m = src;
501         doWrite(buf, len, src);
502     }
503 }
504 
addChangeListener(ChangeListener * listener)505 void Object::addChangeListener(ChangeListener* listener)
506 {
507     logger_m.debugStream()  << "Adding listener to object '" << id_m << "'" << endlog;
508     listenerList_m.push_back(listener);
509 }
removeChangeListener(ChangeListener * listener)510 void Object::removeChangeListener(ChangeListener* listener)
511 {
512     listenerList_m.remove(listener);
513 }
514 
ReadGroupAddr(const std::string & addr)515 eibaddr_t Object::ReadGroupAddr(const std::string& addr)
516 {
517     int a, b, c;
518     if (sscanf (addr.c_str(), "%d/%d/%d", &a, &b, &c) == 3)
519         return ((a & 0x01f) << 11) | ((b & 0x07) << 8) | ((c & 0xff));
520     if (sscanf (addr.c_str(), "%d/%d", &a, &b) == 2)
521         return ((a & 0x01f) << 11) | ((b & 0x7FF));
522     if (sscanf (addr.c_str(), "%x", &a) == 1)
523         return a & 0xffff;
524     std::stringstream msg;
525     msg << "Object: Invalid group address format: '" << addr << "'" << std::endl;
526     throw ticpp::Exception(msg.str());
527 }
528 
ReadAddr(const std::string & addr)529 eibaddr_t Object::ReadAddr(const std::string& addr)
530 {
531     int a, b, c;
532     if (sscanf (addr.c_str(), "%d.%d.%d", &a, &b, &c) == 3)
533         return ((a & 0x0f) << 12) | ((b & 0x0f) << 8) | ((c & 0xff));
534     if (sscanf (addr.c_str(), "%x", &a) == 1)
535         return a & 0xffff;
536     std::stringstream msg;
537     msg << "Object: Invalid individual address format: '" << addr << "'" << std::endl;
538     throw ticpp::Exception(msg.str());
539 }
540 
WriteGroupAddr(eibaddr_t addr)541 std::string Object::WriteGroupAddr(eibaddr_t addr)
542 {
543     char writegaddr_buf[16];
544     sprintf (writegaddr_buf, "%d/%d/%d", (addr >> 11) & 0x1f, (addr >> 8) & 0x07, (addr) & 0xff);
545     return std::string(writegaddr_buf);
546 }
547 
WriteAddr(eibaddr_t addr)548 std::string Object::WriteAddr(eibaddr_t addr)
549 {
550     char writeaddr_buf[16];
551     sprintf (writeaddr_buf, "%d.%d.%d", (addr >> 12) & 0x0f, (addr >> 8) & 0x0f, (addr) & 0xff);
552     return std::string(writeaddr_buf);
553 }
554 
getKnxConnection()555 KnxConnection* Object::getKnxConnection()
556 {
557     return Services::instance()->getKnxConnection();
558 }
559 
560 Logger& ObjectValue::logger_m(Logger::getInstance("ObjectValue"));
561 
init(const std::string & value)562 void SwitchingObjectValue::init(const std::string& value)
563 {
564     if (value == "1" || value == "on" || value == getValueString(true))
565         value_m = true;
566     else if (value == "0" || value == "off" || value == getValueString(false))
567         value_m = false;
568     else
569     {
570         std::stringstream msg;
571         msg << "SwitchingObjectValue: Bad value: '" << value << "' for object type " << getType() << std::endl;
572         throw ticpp::Exception(msg.str());
573     }
574 }
575 
toString()576 std::string SwitchingObjectValue::toString()
577 {
578     return getValueString(value_m);
579 }
580 
toNumber()581 double SwitchingObjectValue::toNumber()
582 {
583     return value_m ? 1.0 : 0.0;
584 }
585 
equals(ObjectValue * value)586 bool SwitchingObjectValue::equals(ObjectValue* value)
587 {
588     assert(value);
589     SwitchingObjectValue* val = dynamic_cast<SwitchingObjectValue*>(value);
590     if (val == 0)
591     {
592         logger_m.errorStream() << "SwitchingObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
593         return false;
594     }
595     logger_m.infoStream() << "SwitchingObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
596     return value_m == val->value_m;
597 }
598 
compare(ObjectValue * value)599 int SwitchingObjectValue::compare(ObjectValue* value)
600 {
601     assert(value);
602     SwitchingObjectValue* val = dynamic_cast<SwitchingObjectValue*>(value);
603     if (val == 0)
604     {
605         logger_m.errorStream()  << "SwitchingObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
606         return false;
607     }
608     logger_m.infoStream() << "SwitchingObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
609     if (value_m == val->value_m)
610         return 0;
611     else if (value_m)
612         return 1;
613     else
614         return -1;
615 }
616 
set(bool value)617 bool SwitchingObjectValue::set(bool value)
618 {
619     if (value_m != value)
620     {
621         value_m = value;
622         return true;
623     }
624     return false;
625 }
626 
set(ObjectValue * value)627 bool SwitchingObjectValue::set(ObjectValue* value)
628 {
629     SwitchingObjectValue* val = dynamic_cast<SwitchingObjectValue*>(value);
630     if (val == 0)
631     {
632         logger_m.errorStream()  << "SwitchingObjectValue: ERROR, set() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
633         return false;
634     }
635     return set(val->value_m);
636 }
637 
set(double value)638 bool SwitchingObjectValue::set(double value)
639 {
640     return set(value != 0.0);
641 }
642 
643 Logger& SwitchingObject::logger_m(Logger::getInstance("SwitchingObject"));
644 
doWrite(const uint8_t * buf,int len,eibaddr_t src)645 void SwitchingObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
646 {
647     bool newValue;
648     if (len == 2)
649         newValue = (buf[1] & 0x3F) != 0;
650     else
651         newValue = buf[2] != 0;
652 
653     if (set(newValue) || forceUpdate())
654         onUpdate();
655 }
656 
doSend(bool isWrite)657 void SwitchingObject::doSend(bool isWrite)
658 {
659     uint8_t buf[2] = { 0, (isWrite ? 0x80 : 0x40) | (getBoolObjectValue() ? 1 : 0) };
660     Services::instance()->getKnxConnection()->write(getGad(), buf, 2);
661 }
662 
init(const std::string & value)663 void SwitchingControlObjectValue::init(const std::string& value)
664 {
665     control_m = (value != "-1" && value != "no control");
666     if (value == "1" || value == "on" || value == getValueString(true))
667         value_m = true;
668     else if (!control_m || value == "0" || value == "off" || value == getValueString(false))
669         value_m = false;
670     else
671     {
672         std::stringstream msg;
673         msg << "SwitchingObjectValue: Bad value: '" << value << "' for object type " << getType() << std::endl;
674         throw ticpp::Exception(msg.str());
675     }
676 }
677 
toString()678 std::string SwitchingControlObjectValue::toString()
679 {
680     if (!control_m)
681         return "no control";
682     return getValueString(value_m);
683 }
684 
toNumber()685 double SwitchingControlObjectValue::toNumber()
686 {
687     return control_m ? (value_m ? 1.0 : 0.0) : -1.0;
688 }
689 
equals(ObjectValue * value)690 bool SwitchingControlObjectValue::equals(ObjectValue* value)
691 {
692     assert(value);
693     SwitchingControlObjectValue* val = dynamic_cast<SwitchingControlObjectValue*>(value);
694     if (val == 0)
695     {
696         logger_m.errorStream() << "SwitchingControlObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
697         return false;
698     }
699     logger_m.infoStream() << "SwitchingControlObjectValue: Compare value_m='" << value_m << "' : control_m='" << control_m << "' to value='" << val->value_m << "' : control='" << val->control_m << "'" << endlog;
700     return (!control_m && !val->control_m) || (control_m && val->control_m && value_m == val->value_m);
701 }
702 
compare(ObjectValue * value)703 int SwitchingControlObjectValue::compare(ObjectValue* value)
704 {
705     assert(value);
706     SwitchingControlObjectValue* val = dynamic_cast<SwitchingControlObjectValue*>(value);
707     if (val == 0)
708     {
709         logger_m.errorStream()  << "SwitchingControlObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
710         return false;
711     }
712     logger_m.infoStream() << "SwitchingControlObjectValue: Compare value_m='" << value_m << "' : control_m='" << control_m << "' with value='" << val->value_m << "' : control='" << val->control_m << "'" << endlog;
713     if (!control_m && !val->control_m)
714         return 0;
715     else if (control_m && !val->control_m)
716         return 1;
717     else if (!control_m && val->control_m)
718         return -1;
719     else if (value_m == val->value_m)
720         return 0;
721     else if (value_m)
722         return 1;
723     else
724         return -1;
725 }
726 
set(bool value,bool control)727 bool SwitchingControlObjectValue::set(bool value, bool control)
728 {
729     if (control_m != control || (control && (value_m != value)))
730     {
731         value_m = value;
732         control_m = control;
733         return true;
734     }
735     return false;
736 }
737 
set(ObjectValue * value)738 bool SwitchingControlObjectValue::set(ObjectValue* value)
739 {
740     SwitchingControlObjectValue* val = dynamic_cast<SwitchingControlObjectValue*>(value);
741     if (val == 0)
742     {
743         logger_m.errorStream()  << "SwitchingControlObjectValue: ERROR, set() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
744         return false;
745     }
746     return set(val->value_m, val->control_m);
747 }
748 
set(double value)749 bool SwitchingControlObjectValue::set(double value)
750 {
751     if (value < 0)
752         return set(false, false);
753     return set(value != 0.0, true);
754 }
755 
equals(ObjectValue * value)756 bool StepDirObjectValue::equals(ObjectValue* value)
757 {
758     assert(value);
759     StepDirObjectValue* val = dynamic_cast<StepDirObjectValue*>(value);
760     if (val == 0)
761     {
762         logger_m.errorStream() << "StepDirObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
763         return false;
764     }
765     logger_m.infoStream() << "StepDirObjectValue: Compare object='"
766     << toString() << "' to value='"
767     << val->toString() << "'" << endlog;
768     return (direction_m == val->direction_m) && (stepcode_m == val->stepcode_m);
769 }
770 
compare(ObjectValue * value)771 int StepDirObjectValue::compare(ObjectValue* value)
772 {
773     assert(value);
774     StepDirObjectValue* val = dynamic_cast<StepDirObjectValue*>(value);
775     if (val == 0)
776     {
777         logger_m.errorStream()  << "StepDirObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
778         return false;
779     }
780     logger_m.infoStream() << "StepDirObjectValue: Compare object='"
781     << toString() << "' to value='"
782     << val->toString() << "'" << endlog;
783 
784     if (stepcode_m == 0 && val->stepcode_m == 0)
785         return 0;
786     if (direction_m == val->direction_m)
787     {
788         if (stepcode_m == val->stepcode_m)
789             return 0;
790         if (stepcode_m > val->stepcode_m) // bigger stepcode => smaller steps
791             return direction_m ? -1 : 1;
792         else
793             return direction_m ? 1 : -1;
794     }
795     return direction_m ? 1 : -1;
796 }
797 
set(ObjectValue * value)798 bool StepDirObjectValue::set(ObjectValue* value)
799 {
800     StepDirObjectValue* val = dynamic_cast<StepDirObjectValue*>(value);
801     if (val == 0)
802     {
803         logger_m.errorStream()  << "StepDirObjectValue: ERROR, set() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
804         return false;
805     }
806     if (direction_m != val->direction_m || stepcode_m != val->stepcode_m)
807     {
808         direction_m = val->direction_m;
809         stepcode_m = val->stepcode_m;
810         return true;
811     }
812     return false;
813 }
814 
set(double value)815 bool StepDirObjectValue::set(double value)
816 {
817     int direction = 1;
818     int stepcode = 0;
819     if (value < 0.0)
820     {
821         direction = 0;
822         value = -value;
823     }
824     stepcode = static_cast<int>(value);
825     if (direction_m != direction || stepcode_m != stepcode)
826     {
827         direction_m = direction;
828         stepcode_m = stepcode;
829         return true;
830     }
831     return false;
832 }
833 
toNumber()834 double StepDirObjectValue::toNumber()
835 {
836     if (stepcode_m == 0)
837         return 0.0;
838     return (direction_m ? 1.0 : -1.0) * stepcode_m;
839 }
840 
841 Logger& StepDirObject::logger_m(Logger::getInstance("StepDirObject"));
842 
StepDirObject()843 StepDirObject::StepDirObject()
844 {}
845 
~StepDirObject()846 StepDirObject::~StepDirObject()
847 {}
848 
doWrite(const uint8_t * buf,int len,eibaddr_t src)849 void StepDirObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
850 {
851     int newValue;
852     if (len == 2)
853         newValue = (buf[1] & 0x3F);
854     else
855         newValue = buf[2];
856     int direction = (newValue & 0x08) >> 3;
857     int stepcode = newValue & 0x07;
858     if (stepcode == 0)
859         direction = 0;
860 
861     if (setStep(direction, stepcode) || forceUpdate())
862         onUpdate();
863 }
864 
doSend(bool isWrite)865 void StepDirObject::doSend(bool isWrite)
866 {
867     uint8_t buf[2] = { 0, (isWrite ? 0x80 : 0x40) | (getDirection() ? 8 : 0) | (getStepCode() & 0x07) };
868     Services::instance()->getKnxConnection()->write(getGad(), buf, 2);
869 }
870 
DimmingObjectValue(const std::string & value)871 DimmingObjectValue::DimmingObjectValue(const std::string& value)
872 {
873     std::string dir;
874     size_t pos = value.find(":");
875     dir = value.substr(0, pos);
876     stepcode_m = 1;
877     if (pos != value.npos)
878     {
879         if (value.length() > pos+1)
880         {
881             char step = value[pos+1];
882             if (step >= '1' && step <= '7')
883                 stepcode_m = step - '0';
884             else
885             {
886                 std::stringstream msg;
887                 msg << "DimmingObjectValue: Invalid stepcode (must be between 1 and 7): '" << step << "'" << std::endl;
888                 throw ticpp::Exception(msg.str());
889             }
890         }
891     }
892     if (dir == "stop")
893     {
894         direction_m = 0;
895         stepcode_m = 0;
896     }
897     else if (dir == "up")
898         direction_m = 1;
899     else if (dir == "down")
900         direction_m = 0;
901     else
902     {
903         std::stringstream msg;
904         msg << "DimmingObjectValue: Bad value: '" << value << "'" << std::endl;
905         throw ticpp::Exception(msg.str());
906     }
907 }
908 
toString()909 std::string DimmingObjectValue::toString()
910 {
911     if (stepcode_m == 0)
912         return "stop";
913     std::string ret(direction_m ? "up" : "down");
914     if (stepcode_m != 1)
915     {
916         ret.push_back(':');
917         ret.push_back('0' + stepcode_m);
918     }
919     return ret;
920 }
921 
922 Logger& DimmingObject::logger_m(Logger::getInstance("DimmingObject"));
923 
createObjectValue(const std::string & value)924 ObjectValue* DimmingObject::createObjectValue(const std::string& value)
925 {
926     return new DimmingObjectValue(value);
927 }
928 
setValue(const std::string & value)929 void DimmingObject::setValue(const std::string& value)
930 {
931     DimmingObjectValue val(value);
932     Object::setValue(&val);
933 }
934 
setStepValue(int direction,int stepcode)935 void DimmingObject::setStepValue(int direction, int stepcode)
936 {
937     if (forceUpdate() || stepcode_m != stepcode  || direction_m != direction)
938     {
939         stepcode_m = stepcode;
940         direction_m = direction;
941         onInternalUpdate();
942     }
943 }
944 
BlindsObjectValue(const std::string & value)945 BlindsObjectValue::BlindsObjectValue(const std::string& value)
946 {
947     std::string dir;
948     size_t pos = value.find(":");
949     dir = value.substr(0, pos);
950     stepcode_m = 1;
951     if (pos != value.npos)
952     {
953         if (value.length() > pos+1)
954         {
955             char step = value[pos+1];
956             if (step >= '1' && step <= '7')
957                 stepcode_m = step - '0';
958             else
959             {
960                 std::stringstream msg;
961                 msg << "BlindsObjectValue: Invalid stepcode (must be between 1 and 7): '" << step << "'" << std::endl;
962                 throw ticpp::Exception(msg.str());
963             }
964         }
965     }
966     if (dir == "stop")
967     {
968         direction_m = 0;
969         stepcode_m = 0;
970     }
971     else if (dir == "close")
972         direction_m = 1;
973     else if (dir == "open")
974         direction_m = 0;
975     else
976     {
977         std::stringstream msg;
978         msg << "BlindsObjectValue: Bad value: '" << value << "'" << std::endl;
979         throw ticpp::Exception(msg.str());
980     }
981 }
982 
toString()983 std::string BlindsObjectValue::toString()
984 {
985     if (stepcode_m == 0)
986         return "stop";
987     std::string ret(direction_m ? "close" : "open");
988     if (stepcode_m != 1)
989     {
990         ret.push_back(':');
991         ret.push_back('0' + stepcode_m);
992     }
993     return ret;
994 }
995 
996 Logger& BlindsObject::logger_m(Logger::getInstance("BlindsObject"));
997 
createObjectValue(const std::string & value)998 ObjectValue* BlindsObject::createObjectValue(const std::string& value)
999 {
1000     return new BlindsObjectValue(value);
1001 }
1002 
setValue(const std::string & value)1003 void BlindsObject::setValue(const std::string& value)
1004 {
1005     BlindsObjectValue val(value);
1006     Object::setValue(&val);
1007 }
1008 
setStepValue(int direction,int stepcode)1009 void BlindsObject::setStepValue(int direction, int stepcode)
1010 {
1011     if (forceUpdate() || stepcode_m != stepcode  || direction_m != direction)
1012     {
1013         stepcode_m = stepcode;
1014         direction_m = direction;
1015         onInternalUpdate();
1016     }
1017 }
1018 
TimeObjectValue(const std::string & value)1019 TimeObjectValue::TimeObjectValue(const std::string& value) : wday_m(-1), hour_m(-1), min_m(-1), sec_m(-1)
1020 {
1021     if (value == "now")
1022         return;
1023     std::istringstream val(value);
1024     char s1, s2;
1025     val >> hour_m >> s1 >> min_m >> s2 >> sec_m;
1026     wday_m = 0;
1027 
1028     if ( val.fail() ||
1029          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
1030          s1 != ':' || s2 != ':' ||
1031          hour_m < 0 || hour_m > 23  || min_m < 0 || min_m > 59 || sec_m < 0 || sec_m > 59 )
1032     {
1033         std::stringstream msg;
1034         msg << "TimeObjectValue: Bad value: '" << value << "'" << std::endl;
1035         throw ticpp::Exception(msg.str());
1036     }
1037 }
1038 
toString()1039 std::string TimeObjectValue::toString()
1040 {
1041     if (hour_m == -1)
1042         return "now";
1043     std::ostringstream out;
1044     out << std::setfill('0') << std::setw(2)
1045     << hour_m << ":" << std::setfill('0') << std::setw(2)
1046     << min_m << ":" << std::setfill('0') << std::setw(2)
1047     << sec_m;
1048     return out.str();
1049 }
1050 
toNumber()1051 double TimeObjectValue::toNumber()
1052 {
1053     if (hour_m == -1)
1054         return -1.0;
1055     return hour_m * 3600 + min_m * 60 + sec_m;
1056 }
1057 
equals(ObjectValue * value)1058 bool TimeObjectValue::equals(ObjectValue* value)
1059 {
1060     int wday, hour, min, sec;
1061     assert(value);
1062     TimeObjectValue* val = dynamic_cast<TimeObjectValue*>(value);
1063     if (val == 0)
1064     {
1065         logger_m.errorStream() << "TimeObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1066         return false;
1067     }
1068     // logger_m.debugStream() << "TimeObjectValue (id=" << getID() << "): Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1069     val->getTimeValue(&wday, &hour, &min, &sec);
1070     return (sec_m == sec) && (min_m == min) && (hour_m == hour) && (wday_m == wday);
1071 }
1072 
compare(ObjectValue * value)1073 int TimeObjectValue::compare(ObjectValue* value)
1074 {
1075     int wday, hour, min, sec;
1076     assert(value);
1077     TimeObjectValue* val = dynamic_cast<TimeObjectValue*>(value);
1078     if (val == 0)
1079     {
1080         logger_m.errorStream() << "TimeObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1081         return false;
1082     }
1083     // logger_m.debugStream() << "TimeObjectValue (id=" << getID() << "): Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1084     val->getTimeValue(&wday, &hour, &min, &sec);
1085 
1086     if (wday_m > wday)
1087         return 1;
1088     if (wday_m < wday)
1089         return -1;
1090 
1091     if (hour_m > hour)
1092         return 1;
1093     if (hour_m < hour)
1094         return -1;
1095 
1096     if (min_m > min)
1097         return 1;
1098     if (min_m < min)
1099         return -1;
1100 
1101     if (sec_m > sec)
1102         return 1;
1103     if (sec_m < sec)
1104         return -1;
1105     return 0;
1106 }
1107 
set(ObjectValue * value)1108 bool TimeObjectValue::set(ObjectValue* value)
1109 {
1110     int wday, hour, min, sec;
1111     assert(value);
1112     TimeObjectValue* val = dynamic_cast<TimeObjectValue*>(value);
1113     if (val == 0)
1114         logger_m.errorStream() << "TimeObject: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1115     else
1116     {
1117         val->getTimeValue(&wday, &hour, &min, &sec);
1118         if (wday_m != wday || hour_m != hour || min_m != min || sec_m != sec)
1119         {
1120             wday_m = wday;
1121             hour_m = hour;
1122             min_m = min;
1123             sec_m = sec;
1124             return true;
1125         }
1126     }
1127     return false;
1128 }
1129 
set(double value)1130 bool TimeObjectValue::set(double value)
1131 {
1132     int wday, hour, min, sec;
1133     if (value < 0)
1134     {
1135         wday = -1;
1136         hour = -1;
1137         min = -1;
1138         sec = -1;
1139     }
1140     else
1141     {
1142         wday = 0;
1143         hour = value / 3600;
1144         value -= hour * 3600;
1145         min = value / 60;
1146         sec = value - min * 60;
1147     }
1148     if (wday_m != wday || hour_m != hour || min_m != min || sec_m != sec)
1149     {
1150         wday_m = wday;
1151         hour_m = hour;
1152         min_m = min;
1153         sec_m = sec;
1154         return true;
1155     }
1156     return false;
1157 }
1158 
getTimeValue(int * wday,int * hour,int * min,int * sec)1159 void TimeObjectValue::getTimeValue(int *wday, int *hour, int *min, int *sec)
1160 {
1161     if (hour_m == -1)
1162     {
1163         time_t t = time(0);
1164         struct tm * timeinfo = localtime(&t);
1165         *wday = timeinfo->tm_wday;
1166         if (*wday == 0)
1167             *wday = 7;
1168         *hour = timeinfo->tm_hour;
1169         *min = timeinfo->tm_min;
1170         *sec = timeinfo->tm_sec;
1171     }
1172     else
1173     {
1174         *wday = wday_m;
1175         *hour = hour_m;
1176         *min = min_m;
1177         *sec = sec_m;
1178     }
1179 }
1180 
1181 Logger& TimeObject::logger_m(Logger::getInstance("TimeObject"));
1182 
TimeObject()1183 TimeObject::TimeObject() : TimeObjectValue(0, 0, 0, 0)
1184 {}
1185 
~TimeObject()1186 TimeObject::~TimeObject()
1187 {}
1188 
createObjectValue(const std::string & value)1189 ObjectValue* TimeObject::createObjectValue(const std::string& value)
1190 {
1191     return new TimeObjectValue(value);
1192 }
1193 
setValue(const std::string & value)1194 void TimeObject::setValue(const std::string& value)
1195 {
1196     TimeObjectValue val(value);
1197     Object::setValue(&val);
1198 }
1199 
doWrite(const uint8_t * buf,int len,eibaddr_t src)1200 void TimeObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
1201 {
1202     if (len < 5)
1203     {
1204         logger_m.errorStream() << "Invalid packet received for TimeObject (too short)" << endlog;
1205         return;
1206     }
1207     int wday, hour, min, sec;
1208 
1209     wday = (buf[2] & 0xE0) >> 5;
1210     hour = buf[2] & 0x1F;
1211     min = buf[3];
1212     sec = buf[4];
1213     if (forceUpdate() || wday != wday_m || hour != hour_m || min != min_m || sec != sec_m)
1214     {
1215         wday_m = wday;
1216         hour_m = hour;
1217         min_m = min;
1218         sec_m = sec;
1219         onUpdate();
1220     }
1221 }
1222 
setTime(time_t time)1223 void TimeObject::setTime(time_t time)
1224 {
1225     struct tm * timeinfo = localtime(&time);
1226     int wday = timeinfo->tm_wday;
1227     if (wday == 0)
1228         wday = 7;
1229     setTime(wday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
1230 }
1231 
doSend(bool isWrite)1232 void TimeObject::doSend(bool isWrite)
1233 {
1234     uint8_t buf[5] = { 0, (isWrite ? 0x80 : 0x40), ((wday_m<<5) & 0xE0) | (hour_m & 0x1F), min_m, sec_m };
1235     Services::instance()->getKnxConnection()->write(getGad(), buf, 5);
1236 }
1237 
setTime(int wday,int hour,int min,int sec)1238 void TimeObject::setTime(int wday, int hour, int min, int sec)
1239 {
1240     TimeObjectValue val(wday, hour, min, sec);
1241     Object::setValue(&val);
1242 }
1243 
getTime(int * wday,int * hour,int * min,int * sec)1244 void TimeObject::getTime(int *wday, int *hour, int *min, int *sec)
1245 {
1246     *wday = wday_m;
1247     *hour = hour_m;
1248     *min = min_m;
1249     *sec = sec_m;
1250 }
1251 
DateObjectValue(const std::string & value)1252 DateObjectValue::DateObjectValue(const std::string& value) : day_m(-1), month_m(-1), year_m(-1)
1253 {
1254     if (value == "now")
1255         return;
1256     std::istringstream val(value);
1257     char s1, s2;
1258     val >> year_m >> s1 >> month_m >> s2 >> day_m;
1259     year_m -= 1900;
1260     if ( val.fail() ||
1261          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
1262          s1 != '-' || s2 != '-' ||
1263          year_m < 0 || year_m > 255 || month_m < 1 || month_m > 12 || day_m < 1 || day_m > 31)
1264     {
1265         std::stringstream msg;
1266         msg << "DateObjectValue: Bad value: '" << value << "'" << std::endl;
1267         throw ticpp::Exception(msg.str());
1268     }
1269 }
1270 
toString()1271 std::string DateObjectValue::toString()
1272 {
1273     if (day_m == -1)
1274         return "now";
1275     std::ostringstream out;
1276     out << year_m+1900 << "-" << month_m << "-" << day_m;
1277     return out.str();
1278 }
1279 
toNumber()1280 double DateObjectValue::toNumber()
1281 {
1282     if (day_m == -1)
1283         return -1.0;
1284     return year_m * 400 + month_m * 31 + day_m;
1285 }
1286 
equals(ObjectValue * value)1287 bool DateObjectValue::equals(ObjectValue* value)
1288 {
1289     int day, month, year;
1290     assert(value);
1291     DateObjectValue* val = dynamic_cast<DateObjectValue*>(value);
1292     if (val == 0)
1293     {
1294         logger_m.errorStream()  << "DateObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1295         return false;
1296     }
1297     // logger_m.debugStream() << "DateObjectValue (id=" << getID() << "): Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1298     val->getDateValue(&day, &month, &year);
1299     return (day_m == day) && (month_m == month) && (year_m == year);
1300 }
1301 
compare(ObjectValue * value)1302 int DateObjectValue::compare(ObjectValue* value)
1303 {
1304     int day, month, year;
1305     assert(value);
1306     DateObjectValue* val = dynamic_cast<DateObjectValue*>(value);
1307     if (val == 0)
1308     {
1309         logger_m.errorStream() << "DateObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1310         return false;
1311     }
1312     // logger_m.debugStream() << "DateObjectValue (id=" << getID() << "): Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1313     val->getDateValue(&day, &month, &year);
1314 
1315     if (year_m > year)
1316         return 1;
1317     if (year_m < year)
1318         return -1;
1319 
1320     if (month_m > month)
1321         return 1;
1322     if (month_m < month)
1323         return -1;
1324 
1325     if (day_m > day)
1326         return 1;
1327     if (day_m < day)
1328         return -1;
1329     return 0;
1330 }
1331 
set(ObjectValue * value)1332 bool DateObjectValue::set(ObjectValue* value)
1333 {
1334     int day, month, year;
1335     assert(value);
1336     DateObjectValue* val = dynamic_cast<DateObjectValue*>(value);
1337     if (val == 0)
1338         logger_m.errorStream() << "DateObjectValue: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1339     else
1340     {
1341         val->getDateValue(&day, &month, &year);
1342         if ( day_m != day || month_m != month || year_m != year )
1343         {
1344             day_m = day;
1345             month_m = month;
1346             year_m = year;
1347             return true;
1348         }
1349     }
1350     return false;
1351 }
1352 
set(double value)1353 bool DateObjectValue::set(double value)
1354 {
1355     int day, month, year;
1356     if (value < 0)
1357     {
1358         day = -1;
1359         month = -1;
1360         year = -1;
1361     }
1362     else
1363     {
1364         year = value / 400;
1365         value -= year * 400;
1366         month = value / 31;
1367         day = value - month * 31;
1368     }
1369     if ( day_m != day || month_m != month || year_m != year )
1370     {
1371         day_m = day;
1372         month_m = month;
1373         year_m = year;
1374         return true;
1375     }
1376     return false;
1377 }
1378 
getDateValue(int * day,int * month,int * year)1379 void DateObjectValue::getDateValue(int *day, int *month, int *year)
1380 {
1381     if (day_m == -1)
1382     {
1383         time_t t = time(0);
1384         struct tm * timeinfo = localtime(&t);
1385         *day = timeinfo->tm_mday;
1386         *month = timeinfo->tm_mon+1;
1387         *year = timeinfo->tm_year;
1388     }
1389     else
1390     {
1391         *day = day_m;
1392         *month = month_m;
1393         *year = year_m;
1394     }
1395 }
1396 
1397 Logger& DateObject::logger_m(Logger::getInstance("DateObject"));
1398 
DateObject()1399 DateObject::DateObject() : DateObjectValue(0, 0, 0)
1400 {}
1401 
~DateObject()1402 DateObject::~DateObject()
1403 {}
1404 
createObjectValue(const std::string & value)1405 ObjectValue* DateObject::createObjectValue(const std::string& value)
1406 {
1407     return new DateObjectValue(value);
1408 }
1409 
setValue(const std::string & value)1410 void DateObject::setValue(const std::string& value)
1411 {
1412     DateObjectValue val(value);
1413     Object::setValue(&val);
1414 }
1415 
doWrite(const uint8_t * buf,int len,eibaddr_t src)1416 void DateObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
1417 {
1418     if (len < 5)
1419     {
1420         logger_m.errorStream() << "Invalid packet received for DateObject (too short)" << endlog;
1421         return;
1422     }
1423     int day, month, year;
1424 
1425     day = buf[2];
1426     month = buf[3];
1427     year = buf[4];
1428     if (year < 90)
1429         year += 100;
1430     if (forceUpdate() || day != day_m || month != month_m || year != year_m)
1431     {
1432         day_m = day;
1433         month_m = month;
1434         year_m = year;
1435         onUpdate();
1436     }
1437 }
1438 
setDate(time_t time)1439 void DateObject::setDate(time_t time)
1440 {
1441     struct tm * timeinfo = localtime(&time);
1442     setDate(timeinfo->tm_mday, timeinfo->tm_mon+1, timeinfo->tm_year);
1443 }
1444 
doSend(bool isWrite)1445 void DateObject::doSend(bool isWrite)
1446 {
1447     uint8_t buf[5] = { 0,
1448                        (isWrite ? 0x80 : 0x40),
1449                        day_m, month_m,
1450                        (year_m >= 100 && year_m < 190) ? year_m-100 : year_m };
1451     Services::instance()->getKnxConnection()->write(getGad(), buf, 5);
1452 }
1453 
setDate(int day,int month,int year)1454 void DateObject::setDate(int day, int month, int year)
1455 {
1456     if (year >= 1900)
1457         year -= 1900;
1458     DateObjectValue val(day, month, year);
1459     Object::setValue(&val);
1460 }
1461 
getDate(int * day,int * month,int * year)1462 void DateObject::getDate(int *day, int *month, int *year)
1463 {
1464     *day = day_m;
1465     *month = month_m;
1466     if (year_m < 1900)
1467         *year = 1900 + year_m;
1468     else
1469         *year = 1900;
1470 }
1471 
init(const std::string & value)1472 void ValueObjectValue::init(const std::string& value)
1473 {
1474     precision_m = 0;
1475     std::istringstream val(value);
1476     val >> value_m;
1477 
1478     if ( val.fail() ||
1479          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
1480          value_m > getBound(true) ||
1481          value_m < getBound(false))
1482     {
1483         std::stringstream msg;
1484         msg << "ValueObjectValue: Bad value: '" << value << "' for object type " << getType() << std::endl;
1485         throw ticpp::Exception(msg.str());
1486     }
1487 }
1488 
setPrecision(std::string precision)1489 void ValueObjectValue::setPrecision(std::string precision)
1490 {
1491     std::istringstream val(precision);
1492     val >> precision_m;
1493 
1494     if ( val.fail() ||
1495          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
1496     {
1497         std::stringstream msg;
1498         msg << "ValueObjectValue: Bad precision: '" << precision << "'" << std::endl;
1499         throw ticpp::Exception(msg.str());
1500     }
1501 }
1502 
getPrecision()1503 std::string ValueObjectValue::getPrecision()
1504 {
1505     if (precision_m == 0)
1506         return "";
1507     else
1508     {
1509         std::ostringstream out;
1510         out << precision_m;
1511         return out.str();
1512     }
1513 }
1514 
toString()1515 std::string ValueObjectValue::toString()
1516 {
1517     std::ostringstream out;
1518     out.precision(8);
1519     out << value_m;
1520     return out.str();
1521 }
1522 
toNumber()1523 double ValueObjectValue::toNumber()
1524 {
1525     return value_m;
1526 }
1527 
equals(ObjectValue * value)1528 bool ValueObjectValue::equals(ObjectValue* value)
1529 {
1530     assert(value);
1531     ValueObjectValue* val = dynamic_cast<ValueObjectValue*>(value);
1532     if (val == 0)
1533     {
1534         logger_m.errorStream() << "ValueObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1535         return false;
1536     }
1537     logger_m.infoStream() << "ValueObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1538     return value_m == val->value_m;
1539 }
1540 
compare(ObjectValue * value)1541 int ValueObjectValue::compare(ObjectValue* value)
1542 {
1543     assert(value);
1544     ValueObjectValue* val = dynamic_cast<ValueObjectValue*>(value);
1545     if (val == 0)
1546     {
1547         logger_m.errorStream() << "ValueObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1548         return false;
1549     }
1550     logger_m.infoStream() << "ValueObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1551 
1552     if (value_m == val->value_m)
1553         return 0;
1554     if (value_m > val->value_m)
1555         return 1;
1556     else
1557         return -1;
1558 }
1559 
set(ObjectValue * value)1560 bool ValueObjectValue::set(ObjectValue* value)
1561 {
1562     assert(value);
1563     ValueObjectValue* val = dynamic_cast<ValueObjectValue*>(value);
1564     if (val == 0)
1565         logger_m.errorStream() << "ValueObject: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1566     else
1567     {
1568         return set(val->value_m);
1569     }
1570     return false;
1571 }
1572 
roundToKnxPrecision(double value)1573 double ValueObjectValue::roundToKnxPrecision(double value)
1574 {
1575     int ex = 0;
1576     int m = (int)rint(value * 100);
1577     if (m < 0)
1578     {
1579         m = -m;
1580         while (m > 2048)
1581         {
1582             m = m >> 1;
1583             ex++;
1584         }
1585         m = -m;
1586     }
1587     else
1588     {
1589         while (m > 2047)
1590         {
1591             m = m >> 1;
1592             ex++;
1593         }
1594     }
1595     return ((double)m * (1 << ex) / 100);
1596 }
1597 
set(double value)1598 bool ValueObjectValue::set(double value)
1599 {
1600     if (precision_m != 0) {
1601         int div = (int) (value/precision_m + (value >= 0 ? 0.5 : -0.5));
1602         value = div*precision_m;
1603         logger_m.debugStream() << "ValueObject: rounded value "<< value << endlog;
1604     }
1605     else {
1606         value = roundToKnxPrecision(value);
1607     }
1608     if (value_m != value)
1609     {
1610         value_m = value;
1611         return true;
1612     }
1613     return false;
1614 }
1615 
1616 Logger& ValueObject::logger_m(Logger::getInstance("ValueObject"));
1617 
ValueObject()1618 ValueObject::ValueObject()
1619 {}
1620 
~ValueObject()1621 ValueObject::~ValueObject()
1622 {}
1623 /*
1624 ObjectValue* ValueObject::createObjectValue(const std::string& value)
1625 {
1626     return new ValueObjectValue(value);
1627 }
1628 
1629 void ValueObject::setValue(const std::string& value)
1630 {
1631     ValueObjectValue val(value);
1632     Object::setValue(&val);
1633 }
1634 */
doWrite(const uint8_t * buf,int len,eibaddr_t src)1635 void ValueObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
1636 {
1637     if (len < 4)
1638     {
1639         logger_m.errorStream() << "Invalid packet received for ValueObject (too short)" << endlog;
1640         return;
1641     }
1642     double newValue;
1643     int d1 = ((unsigned char) buf[2]) * 256 + (unsigned char) buf[3];
1644     int m = d1 & 0x7ff;
1645     if (d1 & 0x8000)
1646         m |= ~0x7ff;
1647     int ex = (d1 & 0x7800) >> 11;
1648     newValue = ((double)m * (1 << ex) / 100);
1649     if (set(newValue) || forceUpdate())
1650     {
1651         onUpdate();
1652     }
1653 }
1654 
doSend(bool isWrite)1655 void ValueObject::doSend(bool isWrite)
1656 {
1657     uint8_t buf[4] = { 0, (isWrite ? 0x80 : 0x40), 0, 0 };
1658     int ex = 0;
1659     int m = (int)rint(getFloatValue() * 100);
1660     if (m < 0)
1661     {
1662         m = -m;
1663         while (m > 2048)
1664         {
1665             m = m >> 1;
1666             ex++;
1667         }
1668         m = -m;
1669         buf[2] = ((m >> 8) & 0x07) | ((ex << 3) & 0x78) | (1 << 7);
1670     }
1671     else
1672     {
1673         while (m > 2047)
1674         {
1675             m = m >> 1;
1676             ex++;
1677         }
1678         buf[2] = ((m >> 8) & 0x07) | ((ex << 3) & 0x78);
1679     }
1680     buf[3] = (m & 0xff);
1681 
1682     Services::instance()->getKnxConnection()->write(getGad(), buf, 4);
1683 }
1684 /*
1685 void ValueObjectImpl::setFloatValue(double value)
1686 {
1687     ValueObjectValue val(value);
1688     Object::setValue(&val);
1689 }*/
1690 
ValueObject32Value(const std::string & value)1691 ValueObject32Value::ValueObject32Value(const std::string& value)
1692 {
1693     std::istringstream val(value);
1694     val >> value_m;
1695 
1696     if ( val.fail() ||
1697          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
1698     {
1699         std::stringstream msg;
1700         msg << "ValueObject32Value: Bad value: '" << value << "'" << std::endl;
1701         throw ticpp::Exception(msg.str());
1702     }
1703 }
1704 
toString()1705 std::string ValueObject32Value::toString()
1706 {
1707     std::ostringstream out;
1708     out.precision(8);
1709     out << value_m;
1710     return out.str();
1711 }
1712 
1713 Logger& ValueObject32::logger_m(Logger::getInstance("valueObject32"));
1714 
createObjectValue(const std::string & value)1715 ObjectValue* ValueObject32::createObjectValue(const std::string& value)
1716 {
1717     return new ValueObject32Value(value);
1718 }
1719 
setValue(const std::string & value)1720 void ValueObject32::setValue(const std::string& value)
1721 {
1722     ValueObject32Value val(value);
1723     Object::setValue(&val);
1724 }
1725 
doWrite(const uint8_t * buf,int len,eibaddr_t src)1726 void ValueObject32::doWrite(const uint8_t* buf, int len, eibaddr_t src)
1727 {
1728     if (len < 6)
1729     {
1730         logger_m.errorStream() << "Invalid packet received for ValueObject32 (too short)" << endlog;
1731         return;
1732     }
1733 
1734     convfloat tmp;
1735     tmp.u32 = buf[2]<<24 | buf[3]<<16 | buf[4]<<8 | buf[5];
1736 //    logger_m.infoStream() << "New value int tmp " << tmp << " for ValueObject32 " << getID() << endlog;
1737 //    const float* nv = reinterpret_cast<const float*>(&tmp);
1738     double newValue = tmp.fl;
1739     if (set(newValue) || forceUpdate())
1740     {
1741         onUpdate();
1742     }
1743 }
1744 
doSend(bool isWrite)1745 void ValueObject32::doSend(bool isWrite)
1746 {
1747     uint8_t buf[6] = { 0, (isWrite ? 0x80 : 0x40), 0, 0, 0, 0 };
1748     convfloat tmp;
1749     tmp.fl = static_cast<float>(value_m);
1750     buf[5] = static_cast<uint8_t>(tmp.u32 & 0x000000FF);
1751     buf[4] = static_cast<uint8_t>((tmp.u32 & 0x0000FF00) >> 8);
1752     buf[3] = static_cast<uint8_t>((tmp.u32 & 0x00FF0000) >> 16);
1753     buf[2] = static_cast<uint8_t>((tmp.u32 & 0xFF000000) >> 24);
1754 
1755     Services::instance()->getKnxConnection()->write(getGad(), buf, 6);
1756 }
1757 
UIntObjectValue(const std::string & value)1758 UIntObjectValue::UIntObjectValue(const std::string& value)
1759 {
1760     std::istringstream val(value);
1761     val >> value_m;
1762 
1763     if ( val.fail() ||
1764          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
1765     {
1766         std::stringstream msg;
1767         msg << "UIntObjectValue: Bad value: '" << value << "'" << std::endl;
1768         throw ticpp::Exception(msg.str());
1769     }
1770 }
1771 
toString()1772 std::string UIntObjectValue::toString()
1773 {
1774     std::ostringstream out;
1775     out << value_m;
1776     return out.str();
1777 }
1778 
toNumber()1779 double UIntObjectValue::toNumber()
1780 {
1781     return value_m;
1782 }
1783 
equals(ObjectValue * value)1784 bool UIntObjectValue::equals(ObjectValue* value)
1785 {
1786     assert(value);
1787     UIntObjectValue* val = dynamic_cast<UIntObjectValue*>(value);
1788     if (val == 0)
1789     {
1790         logger_m.errorStream() << "UIntObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1791         return false;
1792     }
1793     logger_m.infoStream() << "UIntObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1794     return value_m == val->value_m;
1795 }
1796 
compare(ObjectValue * value)1797 int UIntObjectValue::compare(ObjectValue* value)
1798 {
1799     assert(value);
1800     UIntObjectValue* val = dynamic_cast<UIntObjectValue*>(value);
1801     if (val == 0)
1802     {
1803         logger_m.errorStream() << "UIntObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1804         return false;
1805     }
1806     logger_m.infoStream() << "UIntObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
1807 
1808     if (value_m == val->value_m)
1809         return 0;
1810     if (value_m > val->value_m)
1811         return 1;
1812     else
1813         return -1;
1814 }
1815 
set(ObjectValue * value)1816 bool UIntObjectValue::set(ObjectValue* value)
1817 {
1818     assert(value);
1819     UIntObjectValue* val = dynamic_cast<UIntObjectValue*>(value);
1820     if (val == 0)
1821         logger_m.errorStream() << "UIntObjectValue: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
1822     else
1823     {
1824         if (value_m != val->value_m)
1825         {
1826             value_m = val->value_m;
1827             return true;
1828         }
1829     }
1830     return false;
1831 }
1832 
1833 Logger& UIntObject::logger_m(Logger::getInstance("UIntObject"));
1834 
UIntObject()1835 UIntObject::UIntObject()
1836 {}
1837 
~UIntObject()1838 UIntObject::~UIntObject()
1839 {}
1840 
setIntValue(uint32_t value)1841 void UIntObject::setIntValue(uint32_t value)
1842 {
1843     if (setInt(value) || forceUpdate())
1844         onInternalUpdate();
1845 }
1846 
getIntValue()1847 uint32_t UIntObject::getIntValue()
1848 {
1849     if (!init_m)
1850         read();
1851     return getInt();
1852 }
1853 
1854 Logger& U8ImplObject::logger_m(Logger::getInstance("U8ImplObject"));
1855 
U8ImplObject()1856 U8ImplObject::U8ImplObject()
1857 {}
1858 
~U8ImplObject()1859 U8ImplObject::~U8ImplObject()
1860 {}
1861 
doWrite(const uint8_t * buf,int len,eibaddr_t src)1862 void U8ImplObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
1863 {
1864     uint32_t newValue;
1865     if (len == 2)
1866         newValue = (buf[1] & 0x3F);
1867     else
1868         newValue = buf[2];
1869     if (setInt(newValue) || forceUpdate())
1870         onUpdate();
1871 }
1872 
doSend(bool isWrite)1873 void U8ImplObject::doSend(bool isWrite)
1874 {
1875     uint8_t buf[3] = { 0, (isWrite ? 0x80 : 0x40), (getInt() & 0xff) };
1876     Services::instance()->getKnxConnection()->write(getGad(), buf, 3);
1877 }
1878 
U8ObjectValue(const std::string & value)1879 U8ObjectValue::U8ObjectValue(const std::string& value)
1880 {
1881     std::istringstream val(value);
1882     val >> value_m;
1883 
1884     if ( val.fail() ||
1885          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
1886          value_m > 255 ||
1887          value_m < 0)
1888     {
1889         std::stringstream msg;
1890         msg << "U8ObjectValue: Bad value: '" << value << "'" << std::endl;
1891         throw ticpp::Exception(msg.str());
1892     }
1893 }
1894 
toString()1895 std::string U8ObjectValue::toString()
1896 {
1897     std::ostringstream out;
1898     out << value_m;
1899     return out.str();
1900 }
1901 
1902 Logger& U8Object::logger_m(Logger::getInstance("U8Object"));
1903 
U8Object()1904 U8Object::U8Object()
1905 {}
1906 
~U8Object()1907 U8Object::~U8Object()
1908 {}
1909 
createObjectValue(const std::string & value)1910 ObjectValue* U8Object::createObjectValue(const std::string& value)
1911 {
1912     return new U8ObjectValue(value);
1913 }
1914 
setValue(const std::string & value)1915 void U8Object::setValue(const std::string& value)
1916 {
1917     U8ObjectValue val(value);
1918     Object::setValue(&val);
1919 }
1920 
ScalingObjectValue(const std::string & value)1921 ScalingObjectValue::ScalingObjectValue(const std::string& value)
1922 {
1923     float fvalue;
1924     std::istringstream val(value);
1925     val >> fvalue;
1926 
1927     if ( val.fail() ||
1928          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
1929          fvalue > 100 ||
1930          fvalue < 0)
1931     {
1932         std::stringstream msg;
1933         msg << "ScalingObjectValue: Bad value: '" << value << "'" << std::endl;
1934         throw ticpp::Exception(msg.str());
1935     }
1936     value_m = (int)(fvalue * 255 / 100);
1937 }
1938 
toString()1939 std::string ScalingObjectValue::toString()
1940 {
1941     std::ostringstream out;
1942     out.precision(3);
1943     out << (float)value_m * 100 / 255;
1944     return out.str();
1945 }
1946 
1947 Logger& ScalingObject::logger_m(Logger::getInstance("ScalingObject"));
1948 
ScalingObject()1949 ScalingObject::ScalingObject(): ScalingObjectValue(0)
1950 {}
1951 
~ScalingObject()1952 ScalingObject::~ScalingObject()
1953 {}
1954 
createObjectValue(const std::string & value)1955 ObjectValue* ScalingObject::createObjectValue(const std::string& value)
1956 {
1957     return new ScalingObjectValue(value);
1958 }
1959 
setValue(const std::string & value)1960 void ScalingObject::setValue(const std::string& value)
1961 {
1962     ScalingObjectValue val(value);
1963     Object::setValue(&val);
1964 }
1965 
AngleObjectValue(const std::string & value)1966 AngleObjectValue::AngleObjectValue(const std::string& value)
1967 {
1968     float fvalue;
1969     std::istringstream val(value);
1970     val >> fvalue;
1971 
1972     if ( val.fail() ||
1973          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
1974          fvalue > 360 ||
1975          fvalue < 0)
1976     {
1977         std::stringstream msg;
1978         msg << "AngleObjectValue: Bad value: '" << value << "'" << std::endl;
1979         throw ticpp::Exception(msg.str());
1980     }
1981     value_m = ((int)(fvalue * 256 / 360)) % 256;
1982 }
1983 
toString()1984 std::string AngleObjectValue::toString()
1985 {
1986     std::ostringstream out;
1987     out.precision(4);
1988     out << (float)value_m * 360 / 256;
1989     return out.str();
1990 }
1991 
1992 Logger& AngleObject::logger_m(Logger::getInstance("AngleObject"));
1993 
AngleObject()1994 AngleObject::AngleObject() : AngleObjectValue(0)
1995 {}
1996 
~AngleObject()1997 AngleObject::~AngleObject()
1998 {}
1999 
createObjectValue(const std::string & value)2000 ObjectValue* AngleObject::createObjectValue(const std::string& value)
2001 {
2002     return new AngleObjectValue(value);
2003 }
2004 
setValue(const std::string & value)2005 void AngleObject::setValue(const std::string& value)
2006 {
2007     AngleObjectValue val(value);
2008     Object::setValue(&val);
2009 }
2010 
HeatingModeObjectValue(const std::string & value)2011 HeatingModeObjectValue::HeatingModeObjectValue(const std::string& value)
2012 {
2013     if (value == "comfort")
2014         value_m = 1;
2015     else if (value == "standby")
2016         value_m = 2;
2017     else if (value == "night")
2018         value_m = 3;
2019     else if (value == "frost")
2020         value_m = 4;
2021     else if (value == "auto")
2022         value_m = 0;
2023     else
2024     {
2025         std::stringstream msg;
2026         msg << "HeatingModeObjectValue: Bad value: '" << value << "'" << std::endl;
2027         throw ticpp::Exception(msg.str());
2028     }
2029 }
2030 
toString()2031 std::string HeatingModeObjectValue::toString()
2032 {
2033     switch (value_m)
2034     {
2035     case 0:
2036         return "auto";
2037     case 1:
2038         return "comfort";
2039     case 2:
2040         return "standby";
2041     case 3:
2042         return "night";
2043     case 4:
2044         return "frost";
2045     }
2046     return "frost";
2047 }
2048 
2049 Logger& HeatingModeObject::logger_m(Logger::getInstance("HeatingModeObject"));
2050 
createObjectValue(const std::string & value)2051 ObjectValue* HeatingModeObject::createObjectValue(const std::string& value)
2052 {
2053     return new HeatingModeObjectValue(value);
2054 }
2055 
setValue(const std::string & value)2056 void HeatingModeObject::setValue(const std::string& value)
2057 {
2058     HeatingModeObjectValue val(value);
2059     Object::setValue(&val);
2060 }
2061 
Latin1CharObjectValue(const std::string & value)2062 Latin1CharObjectValue::Latin1CharObjectValue(const std::string& value)
2063 {
2064     unsigned char chvalue;
2065     std::istringstream val(value);
2066     val >> chvalue;
2067 
2068     if ( val.fail() ||
2069          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
2070          chvalue > 255 ||
2071          chvalue < 0)
2072     {
2073         std::stringstream msg;
2074         msg << "Latin1CharObjectValue: Bad value: '" << value << "'" << std::endl;
2075         throw ticpp::Exception(msg.str());
2076     }
2077     value_m = (int)chvalue;
2078 }
2079 
toString()2080 std::string Latin1CharObjectValue::toString()
2081 {
2082     std::ostringstream out;
2083     out << (unsigned char)value_m;
2084     return out.str();
2085 }
2086 
2087 Logger& Latin1CharObject::logger_m(Logger::getInstance("Latin1CharObject"));
2088 
Latin1CharObject()2089 Latin1CharObject::Latin1CharObject() : Latin1CharObjectValue(0)
2090 {}
2091 
~Latin1CharObject()2092 Latin1CharObject::~Latin1CharObject()
2093 {}
2094 
createObjectValue(const std::string & value)2095 ObjectValue* Latin1CharObject::createObjectValue(const std::string& value)
2096 {
2097     return new Latin1CharObjectValue(value);
2098 }
2099 
setValue(const std::string & value)2100 void Latin1CharObject::setValue(const std::string& value)
2101 {
2102     Latin1CharObjectValue val(value);
2103     Object::setValue(&val);
2104 }
2105 
AsciiCharObjectValue(const std::string & value)2106 AsciiCharObjectValue::AsciiCharObjectValue(const std::string& value)
2107 {
2108     unsigned char chvalue;
2109     std::istringstream val(value);
2110     val >> chvalue;
2111 
2112     if ( val.fail() ||
2113          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
2114          chvalue > 127 ||
2115          chvalue < 0)
2116     {
2117         std::stringstream msg;
2118         msg << "AsciiCharObjectValue: Bad value: '" << value << "'" << std::endl;
2119         throw ticpp::Exception(msg.str());
2120     }
2121     value_m = (int)chvalue;
2122 }
2123 
toString()2124 std::string AsciiCharObjectValue::toString()
2125 {
2126     std::ostringstream out;
2127     out << (unsigned char)value_m;
2128     return out.str();
2129 }
2130 
2131 Logger& AsciiCharObject::logger_m(Logger::getInstance("AsciiCharObject"));
2132 
AsciiCharObject()2133 AsciiCharObject::AsciiCharObject() : AsciiCharObjectValue(0)
2134 {}
2135 
~AsciiCharObject()2136 AsciiCharObject::~AsciiCharObject()
2137 {}
2138 
createObjectValue(const std::string & value)2139 ObjectValue* AsciiCharObject::createObjectValue(const std::string& value)
2140 {
2141     return new AsciiCharObjectValue(value);
2142 }
2143 
setValue(const std::string & value)2144 void AsciiCharObject::setValue(const std::string& value)
2145 {
2146     AsciiCharObjectValue val(value);
2147     Object::setValue(&val);
2148 }
2149 
U16ObjectValue(const std::string & value)2150 U16ObjectValue::U16ObjectValue(const std::string& value)
2151 {
2152     std::istringstream val(value);
2153     val >> value_m;
2154 
2155     if ( val.fail() ||
2156          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
2157          value_m > 65535 ||
2158          value_m < 0)
2159     {
2160         std::stringstream msg;
2161         msg << "U16ObjectValue: Bad value: '" << value << "'" << std::endl;
2162         throw ticpp::Exception(msg.str());
2163     }
2164 }
2165 
toString()2166 std::string U16ObjectValue::toString()
2167 {
2168     std::ostringstream out;
2169     out << value_m;
2170     return out.str();
2171 }
2172 
2173 Logger& U16Object::logger_m(Logger::getInstance("U16Object"));
2174 
U16Object()2175 U16Object::U16Object()
2176 {}
2177 
~U16Object()2178 U16Object::~U16Object()
2179 {}
2180 
createObjectValue(const std::string & value)2181 ObjectValue* U16Object::createObjectValue(const std::string& value)
2182 {
2183     return new U16ObjectValue(value);
2184 }
2185 
setValue(const std::string & value)2186 void U16Object::setValue(const std::string& value)
2187 {
2188     U16ObjectValue val(value);
2189     Object::setValue(&val);
2190 }
2191 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2192 void U16Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2193 {
2194     unsigned int newValue;
2195     newValue = (buf[2]<<8) | buf[3];
2196     if (forceUpdate() || newValue != value_m)
2197     {
2198         value_m = newValue;
2199         onUpdate();
2200     }
2201 }
2202 
doSend(bool isWrite)2203 void U16Object::doSend(bool isWrite)
2204 {
2205     uint8_t buf[4] = { 0, (isWrite ? 0x80 : 0x40), ((value_m & 0xff00)>>8), (value_m & 0xff) };
2206     Services::instance()->getKnxConnection()->write(getGad(), buf, 4);
2207 }
2208 
U32ObjectValue(const std::string & value)2209 U32ObjectValue::U32ObjectValue(const std::string& value)
2210 {
2211     std::istringstream val(value);
2212     val >> value_m;
2213 
2214     if ( val.fail() ||
2215          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
2216     {
2217         std::stringstream msg;
2218         msg << "U32ObjectValue: Bad value: '" << value << "'" << std::endl;
2219         throw ticpp::Exception(msg.str());
2220     }
2221 }
2222 
toString()2223 std::string U32ObjectValue::toString()
2224 {
2225     std::ostringstream out;
2226     out << value_m;
2227     return out.str();
2228 }
2229 
2230 Logger& U32Object::logger_m(Logger::getInstance("U32Object"));
2231 
U32Object()2232 U32Object::U32Object()
2233 {}
2234 
~U32Object()2235 U32Object::~U32Object()
2236 {}
2237 
createObjectValue(const std::string & value)2238 ObjectValue* U32Object::createObjectValue(const std::string& value)
2239 {
2240     return new U32ObjectValue(value);
2241 }
2242 
setValue(const std::string & value)2243 void U32Object::setValue(const std::string& value)
2244 {
2245     U32ObjectValue val(value);
2246     Object::setValue(&val);
2247 }
2248 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2249 void U32Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2250 {
2251     unsigned int newValue;
2252     newValue = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
2253     if (forceUpdate() || newValue != value_m)
2254     {
2255         value_m = newValue;
2256         onUpdate();
2257     }
2258 }
2259 
doSend(bool isWrite)2260 void U32Object::doSend(bool isWrite)
2261 {
2262     uint8_t buf[6] = { 0, (isWrite ? 0x80 : 0x40), ((value_m & 0xff000000)>>24), ((value_m & 0xff0000)>>16), ((value_m & 0xff00)>>8), (value_m & 0xff) };
2263     Services::instance()->getKnxConnection()->write(getGad(), buf, 6);
2264 }
2265 
RGBObjectValue(const std::string & value)2266 RGBObjectValue::RGBObjectValue(const std::string& value)
2267 {
2268     std::istringstream val(value);
2269     val.setf(std::ios::hex, std::ios::basefield);
2270     val >> value_m;
2271 
2272     if ( val.fail() ||
2273          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
2274     {
2275         std::stringstream msg;
2276         msg << "RGBObjectValue: Bad value: '" << value << "'" << std::endl;
2277         throw ticpp::Exception(msg.str());
2278     }
2279 }
2280 
toString()2281 std::string RGBObjectValue::toString()
2282 {
2283     std::ostringstream out;
2284     out.setf(std::ios::hex, std::ios::basefield);
2285     out.fill('0');
2286     out << std::setw(6) << value_m;
2287     return out.str();
2288 }
2289 
2290 Logger& RGBObject::logger_m(Logger::getInstance("RGBObject"));
2291 
RGBObject()2292 RGBObject::RGBObject()
2293 {}
2294 
~RGBObject()2295 RGBObject::~RGBObject()
2296 {}
2297 
createObjectValue(const std::string & value)2298 ObjectValue* RGBObject::createObjectValue(const std::string& value)
2299 {
2300     return new RGBObjectValue(value);
2301 }
2302 
setValue(const std::string & value)2303 void RGBObject::setValue(const std::string& value)
2304 {
2305     RGBObjectValue val(value);
2306     Object::setValue(&val);
2307 }
2308 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2309 void RGBObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2310 {
2311     unsigned int newValue;
2312     newValue = (buf[2]<<16) | (buf[3]<<8) | buf[4];
2313     if (forceUpdate() || newValue != value_m)
2314     {
2315         value_m = newValue;
2316         onUpdate();
2317     }
2318 }
2319 
doSend(bool isWrite)2320 void RGBObject::doSend(bool isWrite)
2321 {
2322     uint8_t buf[5] = { 0, (isWrite ? 0x80 : 0x40), ((value_m & 0xff0000)>>16), ((value_m & 0xff00)>>8), (value_m & 0xff) };
2323     Services::instance()->getKnxConnection()->write(getGad(), buf, 5);
2324 }
2325 
IntObjectValue(const std::string & value)2326 IntObjectValue::IntObjectValue(const std::string& value)
2327 {
2328     std::istringstream val(value);
2329     val >> value_m;
2330 
2331     if ( val.fail() ||
2332          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
2333     {
2334         std::stringstream msg;
2335         msg << "IntObjectValue: Bad value: '" << value << "'" << std::endl;
2336         throw ticpp::Exception(msg.str());
2337     }
2338 }
2339 
toString()2340 std::string IntObjectValue::toString()
2341 {
2342     std::ostringstream out;
2343     out << value_m;
2344     return out.str();
2345 }
2346 
toNumber()2347 double IntObjectValue::toNumber()
2348 {
2349     return value_m;
2350 }
2351 
equals(ObjectValue * value)2352 bool IntObjectValue::equals(ObjectValue* value)
2353 {
2354     assert(value);
2355     IntObjectValue* val = dynamic_cast<IntObjectValue*>(value);
2356     if (val == 0)
2357     {
2358         logger_m.errorStream() << "IntObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2359         return false;
2360     }
2361     logger_m.infoStream() << "IntObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
2362     return value_m == val->value_m;
2363 }
2364 
compare(ObjectValue * value)2365 int IntObjectValue::compare(ObjectValue* value)
2366 {
2367     assert(value);
2368     IntObjectValue* val = dynamic_cast<IntObjectValue*>(value);
2369     if (val == 0)
2370     {
2371         logger_m.errorStream() << "IntObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2372         return false;
2373     }
2374     logger_m.infoStream() << "IntObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
2375 
2376     if (value_m == val->value_m)
2377         return 0;
2378     if (value_m > val->value_m)
2379         return 1;
2380     else
2381         return -1;
2382 }
2383 
set(ObjectValue * value)2384 bool IntObjectValue::set(ObjectValue* value)
2385 {
2386     assert(value);
2387     IntObjectValue* val = dynamic_cast<IntObjectValue*>(value);
2388     if (val == 0)
2389         logger_m.errorStream() << "IntObjectValue: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2390     else
2391     {
2392         if (value_m != val->value_m)
2393         {
2394             value_m = val->value_m;
2395             return true;
2396         }
2397     }
2398     return false;
2399 }
2400 
2401 Logger& IntObject::logger_m(Logger::getInstance("IntObject"));
2402 
IntObject()2403 IntObject::IntObject()
2404 {}
2405 
~IntObject()2406 IntObject::~IntObject()
2407 {}
2408 
setIntValue(int32_t value)2409 void IntObject::setIntValue(int32_t value)
2410 {
2411     if (setInt(value) || forceUpdate())
2412         onInternalUpdate();
2413 }
2414 
getIntValue()2415 int32_t IntObject::getIntValue()
2416 {
2417     if (!init_m)
2418         read();
2419     return getInt();
2420 }
2421 
S8ObjectValue(const std::string & value)2422 S8ObjectValue::S8ObjectValue(const std::string& value)
2423 {
2424     std::istringstream val(value);
2425     val >> value_m;
2426 
2427     if ( val.fail() ||
2428          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
2429          value_m > 127 ||
2430          value_m < -128)
2431     {
2432         std::stringstream msg;
2433         msg << "S8ObjectValue: Bad value: '" << value << "'" << std::endl;
2434         throw ticpp::Exception(msg.str());
2435     }
2436 }
2437 
toString()2438 std::string S8ObjectValue::toString()
2439 {
2440     std::ostringstream out;
2441     out << value_m;
2442     return out.str();
2443 }
2444 
2445 Logger& S8Object::logger_m(Logger::getInstance("S8Object"));
2446 
S8Object()2447 S8Object::S8Object()
2448 {}
2449 
~S8Object()2450 S8Object::~S8Object()
2451 {}
2452 
createObjectValue(const std::string & value)2453 ObjectValue* S8Object::createObjectValue(const std::string& value)
2454 {
2455     return new S8ObjectValue(value);
2456 }
2457 
setValue(const std::string & value)2458 void S8Object::setValue(const std::string& value)
2459 {
2460     S8ObjectValue val(value);
2461     Object::setValue(&val);
2462 }
2463 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2464 void S8Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2465 {
2466     int32_t newValue;
2467     if (len == 2)
2468         newValue = (buf[1] & 0x3F);
2469     else
2470         newValue = buf[2];
2471     if (newValue > 127)
2472         newValue -= 256;
2473     if (forceUpdate() || newValue != value_m)
2474     {
2475         value_m = newValue;
2476         onUpdate();
2477     }
2478 }
2479 
doSend(bool isWrite)2480 void S8Object::doSend(bool isWrite)
2481 {
2482     uint8_t buf[3] = { 0, (isWrite ? 0x80 : 0x40), (value_m & 0xff) };
2483     Services::instance()->getKnxConnection()->write(getGad(), buf, 3);
2484 }
2485 
S16ObjectValue(const std::string & value)2486 S16ObjectValue::S16ObjectValue(const std::string& value)
2487 {
2488     std::istringstream val(value);
2489     val >> value_m;
2490 
2491     if ( val.fail() ||
2492          val.peek() != std::char_traits<char>::eof() || // workaround for wrong val.eof() flag in uClibc++
2493          value_m > 32767 ||
2494          value_m < -32768)
2495     {
2496         std::stringstream msg;
2497         msg << "S16ObjectValue: Bad value: '" << value << "'" << std::endl;
2498         throw ticpp::Exception(msg.str());
2499     }
2500 }
2501 
toString()2502 std::string S16ObjectValue::toString()
2503 {
2504     std::ostringstream out;
2505     out << value_m;
2506     return out.str();
2507 }
2508 
2509 Logger& S16Object::logger_m(Logger::getInstance("S16Object"));
2510 
S16Object()2511 S16Object::S16Object()
2512 {}
2513 
~S16Object()2514 S16Object::~S16Object()
2515 {}
2516 
createObjectValue(const std::string & value)2517 ObjectValue* S16Object::createObjectValue(const std::string& value)
2518 {
2519     return new S16ObjectValue(value);
2520 }
2521 
setValue(const std::string & value)2522 void S16Object::setValue(const std::string& value)
2523 {
2524     S16ObjectValue val(value);
2525     Object::setValue(&val);
2526 }
2527 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2528 void S16Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2529 {
2530     int32_t newValue;
2531     newValue = (buf[2]<<8) | buf[3];
2532     if (newValue > 32767)
2533         newValue -= 65536;
2534     if (forceUpdate() || newValue != value_m)
2535     {
2536         value_m = newValue;
2537         onUpdate();
2538     }
2539 }
2540 
doSend(bool isWrite)2541 void S16Object::doSend(bool isWrite)
2542 {
2543     uint8_t buf[4] = { 0, (isWrite ? 0x80 : 0x40), ((value_m & 0xff00)>>8), (value_m & 0xff) };
2544     Services::instance()->getKnxConnection()->write(getGad(), buf, 4);
2545 }
2546 
S32ObjectValue(const std::string & value)2547 S32ObjectValue::S32ObjectValue(const std::string& value)
2548 {
2549     std::istringstream val(value);
2550     val >> value_m;
2551 
2552     if ( val.fail() ||
2553          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
2554     {
2555         std::stringstream msg;
2556         msg << "S32ObjectValue: Bad value: '" << value << "'" << std::endl;
2557         throw ticpp::Exception(msg.str());
2558     }
2559 }
2560 
toString()2561 std::string S32ObjectValue::toString()
2562 {
2563     std::ostringstream out;
2564     out << value_m;
2565     return out.str();
2566 }
2567 
2568 Logger& S32Object::logger_m(Logger::getInstance("S32Object"));
2569 
S32Object()2570 S32Object::S32Object()
2571 {}
2572 
~S32Object()2573 S32Object::~S32Object()
2574 {}
2575 
createObjectValue(const std::string & value)2576 ObjectValue* S32Object::createObjectValue(const std::string& value)
2577 {
2578     return new S32ObjectValue(value);
2579 }
2580 
setValue(const std::string & value)2581 void S32Object::setValue(const std::string& value)
2582 {
2583     S32ObjectValue val(value);
2584     Object::setValue(&val);
2585 }
2586 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2587 void S32Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2588 {
2589     int32_t newValue;
2590     newValue = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
2591     if (forceUpdate() || newValue != value_m)
2592     {
2593         value_m = newValue;
2594         onUpdate();
2595     }
2596 }
2597 
doSend(bool isWrite)2598 void S32Object::doSend(bool isWrite)
2599 {
2600     uint8_t buf[6] = { 0, (isWrite ? 0x80 : 0x40), ((value_m & 0xff000000)>>24), ((value_m & 0xff0000)>>16), ((value_m & 0xff00)>>8), (value_m & 0xff) };
2601     Services::instance()->getKnxConnection()->write(getGad(), buf, 6);
2602 }
2603 
2604 #ifdef STL_STREAM_SUPPORT_INT64
S64ObjectValue(const std::string & value)2605 S64ObjectValue::S64ObjectValue(const std::string& value)
2606 {
2607     std::istringstream val(value);
2608     val >> value_m;
2609 
2610     if ( val.fail() ||
2611          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
2612     {
2613         std::stringstream msg;
2614         msg << "S64ObjectValue: Bad value: '" << value << "'" << std::endl;
2615         throw ticpp::Exception(msg.str());
2616     }
2617 }
2618 
toString()2619 std::string S64ObjectValue::toString()
2620 {
2621     std::ostringstream out;
2622     out << value_m;
2623     return out.str();
2624 }
2625 
toNumber()2626 double S64ObjectValue::toNumber()
2627 {
2628     return value_m;
2629 }
2630 
equals(ObjectValue * value)2631 bool S64ObjectValue::equals(ObjectValue* value)
2632 {
2633     assert(value);
2634     S64ObjectValue* val = dynamic_cast<S64ObjectValue*>(value);
2635     if (val == 0)
2636     {
2637         logger_m.errorStream() << "S64ObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2638         return false;
2639     }
2640     logger_m.infoStream() << "S64ObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
2641     return value_m == val->value_m;
2642 }
2643 
compare(ObjectValue * value)2644 int S64ObjectValue::compare(ObjectValue* value)
2645 {
2646     assert(value);
2647     S64ObjectValue* val = dynamic_cast<S64ObjectValue*>(value);
2648     if (val == 0)
2649     {
2650         logger_m.errorStream() << "S64ObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2651         return false;
2652     }
2653     logger_m.infoStream() << "S64ObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
2654 
2655     if (value_m == val->value_m)
2656         return 0;
2657     if (value_m > val->value_m)
2658         return 1;
2659     else
2660         return -1;
2661 }
2662 
set(ObjectValue * value)2663 bool S64ObjectValue::set(ObjectValue* value)
2664 {
2665     assert(value);
2666     S64ObjectValue* val = dynamic_cast<S64ObjectValue*>(value);
2667     if (val == 0)
2668         logger_m.errorStream() << "S64ObjectValue: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2669     else
2670     {
2671         if (value_m != val->value_m)
2672         {
2673             value_m = val->value_m;
2674             return true;
2675         }
2676     }
2677     return false;
2678 }
2679 
2680 Logger& S64Object::logger_m(Logger::getInstance("S64Object"));
2681 
S64Object()2682 S64Object::S64Object()
2683 {}
2684 
~S64Object()2685 S64Object::~S64Object()
2686 {}
2687 
createObjectValue(const std::string & value)2688 ObjectValue* S64Object::createObjectValue(const std::string& value)
2689 {
2690     return new S64ObjectValue(value);
2691 }
2692 
setIntValue(int64_t value)2693 void S64Object::setIntValue(int64_t value)
2694 {
2695     if (setInt(value) || forceUpdate())
2696         onInternalUpdate();
2697 }
2698 
getIntValue()2699 int64_t S64Object::getIntValue()
2700 {
2701     if (!init_m)
2702         read();
2703     return getInt();
2704 }
2705 
setValue(const std::string & value)2706 void S64Object::setValue(const std::string& value)
2707 {
2708     S64ObjectValue val(value);
2709     if (set(&val) || forceUpdate())
2710         onInternalUpdate();
2711 }
2712 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2713 void S64Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2714 {
2715     int64_t newValue;
2716     newValue = ((int64_t)buf[2]<<56) | ((int64_t)buf[3]<<48) | ((int64_t)buf[4]<<40) | ((int64_t)buf[5]<<32) | (buf[6]<<24) | (buf[7]<<16) | (buf[8]<<8) | buf[9];
2717     if (forceUpdate() || newValue != value_m)
2718     {
2719         value_m = newValue;
2720         onUpdate();
2721     }
2722 }
2723 
doSend(bool isWrite)2724 void S64Object::doSend(bool isWrite)
2725 {
2726     uint8_t buf[10] = { 0, (isWrite ? 0x80 : 0x40), ((value_m & 0xff00000000000000LL)>>56), ((value_m & 0xff000000000000LL)>>48), ((value_m & 0xff0000000000LL)>>40), ((value_m & 0xff00000000LL)>>32),
2727                                                     ((value_m & 0xff000000LL)>>24), ((value_m & 0xff0000LL)>>16), ((value_m & 0xff00LL)>>8), (value_m & 0xffLL) };
2728     Services::instance()->getKnxConnection()->write(getGad(), buf, 10);
2729 }
2730 #endif
2731 
StringObjectValue(const std::string & value)2732 StringObjectValue::StringObjectValue(const std::string& value)
2733 {
2734     value_m = value;
2735 //    logger_m.debugStream() << "StringObjectValue: Value: '" << value_m << "'" << endlog;
2736 }
2737 
toString()2738 std::string StringObjectValue::toString()
2739 {
2740     return value_m;
2741 }
2742 
toNumber()2743 double StringObjectValue::toNumber()
2744 {
2745     std::istringstream val(value_m);
2746     double value;
2747     val >> value;
2748 
2749     if ( val.fail() ||
2750          val.peek() != std::char_traits<char>::eof()) // workaround for wrong val.eof() flag in uClibc++
2751     {
2752         value = 0;
2753     }
2754     return value;
2755 }
2756 
equals(ObjectValue * value)2757 bool StringObjectValue::equals(ObjectValue* value)
2758 {
2759     assert(value);
2760     StringObjectValue* val = dynamic_cast<StringObjectValue*>(value);
2761     if (val == 0)
2762     {
2763         logger_m.errorStream() << "StringObjectValue: ERROR, equals() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2764         return false;
2765     }
2766     logger_m.infoStream() << "StringObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
2767     return value_m == val->value_m;
2768 }
2769 
compare(ObjectValue * value)2770 int StringObjectValue::compare(ObjectValue* value)
2771 {
2772     assert(value);
2773     StringObjectValue* val = dynamic_cast<StringObjectValue*>(value);
2774     if (val == 0)
2775     {
2776         logger_m.errorStream() << "StringObjectValue: ERROR, compare() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2777         return -1;
2778     }
2779     logger_m.infoStream() << "StringObjectValue: Compare value_m='" << value_m << "' to value='" << val->value_m << "'" << endlog;
2780 
2781     if (value_m == val->value_m)
2782         return 0;
2783     if (value_m < val->value_m)
2784         return -1;
2785     else
2786         return 1;
2787 }
2788 
set(ObjectValue * value)2789 bool StringObjectValue::set(ObjectValue* value)
2790 {
2791     assert(value);
2792     StringObjectValue* val = dynamic_cast<StringObjectValue*>(value);
2793     if (val == 0)
2794         logger_m.errorStream() << "StringObject: ERROR, setValue() received invalid class object (typeid=" << typeid(*value).name() << ")" << endlog;
2795     else
2796     {
2797         if (value_m != val->value_m)
2798         {
2799             value_m = val->value_m;
2800             return true;
2801         }
2802     }
2803     return false;
2804 }
2805 
set(double value)2806 bool StringObjectValue::set(double value)
2807 {
2808     std::ostringstream out;
2809     out << value;
2810     if (value_m != out.str())
2811     {
2812         value_m = out.str();
2813         return true;
2814     }
2815     return false;
2816 }
2817 
2818 Logger& StringObject::logger_m(Logger::getInstance("StringObject"));
2819 
StringObject()2820 StringObject::StringObject()
2821 {}
2822 
~StringObject()2823 StringObject::~StringObject()
2824 {}
2825 
createObjectValue(const std::string & value)2826 ObjectValue* StringObject::createObjectValue(const std::string& value)
2827 {
2828     return new StringObjectValue(value);
2829 }
2830 
setValue(const std::string & value)2831 void StringObject::setValue(const std::string& value)
2832 {
2833     StringObjectValue val(value);
2834     Object::setValue(&val);
2835 }
2836 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2837 void StringObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2838 {
2839     if (len < 2)
2840     {
2841         logger_m.errorStream() << "Invalid packet received for StringObject (too short)" << endlog;
2842         return;
2843     }
2844     std::string value;
2845     for(int j=2; j<len && buf[j]!=0; j++)
2846         value.push_back(buf[j]);
2847     StringObjectValue val(value);
2848 
2849     if (set(&val) || forceUpdate())
2850         onUpdate();
2851 }
2852 
doSend(bool isWrite)2853 void StringObject::doSend(bool isWrite)
2854 {
2855     logger_m.debugStream() << "StringObject: Value: " << value_m << endlog;
2856     uint bufsz = value_m.size()+3;
2857     uint8_t *buf = new uint8_t[bufsz];
2858     memset(buf,0,bufsz);
2859     buf[1] = (isWrite ? 0x80 : 0x40);
2860     // Convert to hex
2861     for(uint j=2;j<bufsz;j++)
2862         buf[j] = static_cast<uint8_t>(value_m[j-2]);
2863 
2864     Services::instance()->getKnxConnection()->write(getGad(), buf, bufsz);
2865     delete buf;
2866 }
2867 
setStringValue(const std::string & value)2868 void StringObject::setStringValue(const std::string& value)
2869 {
2870     StringObjectValue val(value);
2871     Object::setValue(&val);
2872 }
2873 
String14ObjectValue(const std::string & value)2874 String14ObjectValue::String14ObjectValue(const std::string& value): StringObjectValue(value)
2875 {
2876     if ( value.length() > 14)
2877     {
2878         std::stringstream msg;
2879         msg << "String14ObjectValue: Bad value (too long): '" << value << "'" << std::endl;
2880         throw ticpp::Exception(msg.str());
2881     }
2882 }
2883 
String14AsciiObjectValue(const std::string & value)2884 String14AsciiObjectValue::String14AsciiObjectValue(const std::string& value): StringObjectValue(value)
2885 {
2886     if ( value.length() > 14)
2887     {
2888         std::stringstream msg;
2889         msg << "String14AsciiObjectValue: Bad value (too long): '" << value << "'" << std::endl;
2890         throw ticpp::Exception(msg.str());
2891     }
2892     std::string::const_iterator it = value.begin();
2893     while ( it != value.end())
2894     {
2895         if (*it < 0 || *it > 127)
2896         {
2897             std::stringstream msg;
2898             msg << "String14AsciiObjectValue: Bad value (invalid character): '" << value << "'" << std::endl;
2899             throw ticpp::Exception(msg.str());
2900         }
2901         ++it;
2902     }
2903 }
2904 
2905 Logger& String14Object::logger_m(Logger::getInstance("String14Object"));
2906 
String14Object()2907 String14Object::String14Object()
2908 {}
2909 
~String14Object()2910 String14Object::~String14Object()
2911 {}
2912 
createObjectValue(const std::string & value)2913 ObjectValue* String14Object::createObjectValue(const std::string& value)
2914 {
2915     return new String14ObjectValue(value);
2916 }
2917 
setValue(const std::string & value)2918 void String14Object::setValue(const std::string& value)
2919 {
2920     String14ObjectValue val(value);
2921     Object::setValue(&val);
2922 }
2923 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2924 void String14Object::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2925 {
2926     if (len < 2)
2927     {
2928         logger_m.errorStream() << "Invalid packet received for String14Object (too short)" << endlog;
2929         return;
2930     }
2931     std::string value;
2932     for(int j=2; j<len && buf[j]!=0; j++)
2933         value.push_back(buf[j]);
2934     String14ObjectValue val(value);
2935 
2936     if (set(&val) || forceUpdate())
2937         onUpdate();
2938 }
2939 
doSend(bool isWrite)2940 void String14Object::doSend(bool isWrite)
2941 {
2942     logger_m.debugStream() << "String14Object: Value: " << value_m << endlog;
2943     uint8_t buf[16];
2944     memset(buf,0,sizeof(buf));
2945     buf[1] = (isWrite ? 0x80 : 0x40);
2946     // Convert to hex
2947     for(uint j=0;j<value_m.size();j++)
2948         buf[j+2] = static_cast<uint8_t>(value_m[j]);
2949 
2950     Services::instance()->getKnxConnection()->write(getGad(), buf, sizeof(buf));
2951 }
2952 
setStringValue(const std::string & value)2953 void String14Object::setStringValue(const std::string& value)
2954 {
2955     String14ObjectValue val(value);
2956     Object::setValue(&val);
2957 }
2958 
2959 Logger& String14AsciiObject::logger_m(Logger::getInstance("String14AsciiObject"));
2960 
String14AsciiObject()2961 String14AsciiObject::String14AsciiObject()
2962 {}
2963 
~String14AsciiObject()2964 String14AsciiObject::~String14AsciiObject()
2965 {}
2966 
createObjectValue(const std::string & value)2967 ObjectValue* String14AsciiObject::createObjectValue(const std::string& value)
2968 {
2969     return new String14AsciiObjectValue(value);
2970 }
2971 
setValue(const std::string & value)2972 void String14AsciiObject::setValue(const std::string& value)
2973 {
2974     String14AsciiObjectValue val(value);
2975     Object::setValue(&val);
2976 }
2977 
doWrite(const uint8_t * buf,int len,eibaddr_t src)2978 void String14AsciiObject::doWrite(const uint8_t* buf, int len, eibaddr_t src)
2979 {
2980     if (len < 2)
2981     {
2982         logger_m.errorStream() << "Invalid packet received for String14AsciiObject (too short)" << endlog;
2983         return;
2984     }
2985     std::string value;
2986     for(int j=2; j<len && buf[j]!=0; j++)
2987         value.push_back(buf[j]);
2988     String14AsciiObjectValue val(value);
2989 
2990     if (set(&val) || forceUpdate())
2991         onUpdate();
2992 }
2993 
doSend(bool isWrite)2994 void String14AsciiObject::doSend(bool isWrite)
2995 {
2996     logger_m.debugStream() << "String14AsciiObject: Value: " << value_m << endlog;
2997     uint8_t buf[16];
2998     memset(buf,0,sizeof(buf));
2999     buf[1] = (isWrite ? 0x80 : 0x40);
3000     // Convert to hex
3001     for(uint j=0;j<value_m.size();j++)
3002         buf[j+2] = static_cast<uint8_t>(value_m[j]);
3003 
3004     Services::instance()->getKnxConnection()->write(getGad(), buf, sizeof(buf));
3005 }
3006 
setStringValue(const std::string & value)3007 void String14AsciiObject::setStringValue(const std::string& value)
3008 {
3009     String14AsciiObjectValue val(value);
3010     Object::setValue(&val);
3011 }
3012 
3013 Logger& ObjectController::logger_m(Logger::getInstance("ObjectController"));
3014 
ObjectController()3015 ObjectController::ObjectController()
3016 {}
3017 
~ObjectController()3018 ObjectController::~ObjectController()
3019 {
3020     ObjectIdMap_t::iterator it;
3021     for (it = objectIdMap_m.begin(); it != objectIdMap_m.end(); it++)
3022         delete (*it).second;
3023 }
3024 
instance()3025 ObjectController* ObjectController::instance()
3026 {
3027     if (instance_m == 0)
3028         instance_m = new ObjectController();
3029     return instance_m;
3030 }
3031 
onWrite(eibaddr_t src,eibaddr_t dest,const uint8_t * buf,int len)3032 void ObjectController::onWrite(eibaddr_t src, eibaddr_t dest, const uint8_t* buf, int len)
3033 {
3034     std::pair<ObjectMap_t::iterator, ObjectMap_t::iterator> range;
3035     range = objectMap_m.equal_range(dest);
3036     ObjectMap_t::iterator it;
3037     for (it = range.first; it != range.second; it++)
3038         (*it).second->onWrite(buf, len, src);
3039     if (range.first == range.second)
3040         logger_m.debugStream() << "onWrite - dest eibaddr not found: "
3041             << Object::WriteGroupAddr(dest)
3042             << " sender=" << Object::WriteAddr( src ) << endlog;
3043 }
3044 
onRead(eibaddr_t src,eibaddr_t dest,const uint8_t * buf,int len)3045 void ObjectController::onRead(eibaddr_t src, eibaddr_t dest, const uint8_t* buf, int len)
3046 {
3047     std::pair<ObjectMap_t::iterator, ObjectMap_t::iterator> range;
3048     range = objectMap_m.equal_range(dest);
3049     ObjectMap_t::iterator it;
3050     for (it = range.first; it != range.second; it++)
3051         (*it).second->onRead(buf, len, src);
3052     if (range.first == range.second)
3053         logger_m.debugStream() << "onRead - dest eibaddr not found: "
3054             << Object::WriteGroupAddr(dest)
3055             << " sender=" << Object::WriteAddr( src ) << endlog;
3056 }
3057 
onResponse(eibaddr_t src,eibaddr_t dest,const uint8_t * buf,int len)3058 void ObjectController::onResponse(eibaddr_t src, eibaddr_t dest, const uint8_t* buf, int len)
3059 {
3060     std::pair<ObjectMap_t::iterator, ObjectMap_t::iterator> range;
3061     range = objectMap_m.equal_range(dest);
3062     ObjectMap_t::iterator it;
3063     for (it = range.first; it != range.second; it++)
3064         (*it).second->onResponse(buf, len, src);
3065     if (range.first == range.second)
3066         logger_m.debugStream() << "onResponse - dest eibaddr not found: "
3067             << Object::WriteGroupAddr(dest)
3068             << " sender=" << Object::WriteAddr( src ) << endlog;
3069 }
3070 
getObject(const std::string & id)3071 Object* ObjectController::getObject(const std::string& id)
3072 {
3073     ObjectIdMap_t::iterator it = objectIdMap_m.find(id);
3074     if (it == objectIdMap_m.end())
3075     {
3076         std::stringstream msg;
3077         msg << "ObjectController: Object ID not found: '" << id << "'" << std::endl;
3078         throw ticpp::Exception(msg.str());
3079     }
3080     it->second->incRefCount();
3081     return (*it).second;
3082 }
3083 
addObject(Object * object)3084 void ObjectController::addObject(Object* object)
3085 {
3086     if (!objectIdMap_m.insert(ObjectIdPair_t(object->getID(), object)).second)
3087         throw ticpp::Exception("Object ID already exists");
3088     if (object->getGad())
3089         objectMap_m.insert(ObjectPair_t(object->getGad(), object));
3090     std::list<eibaddr_t>::iterator it2, it_end;
3091     it_end = object->getListenerGadEnd();
3092     for (it2=object->getListenerGad(); it2!=it_end; it2++)
3093         objectMap_m.insert(ObjectPair_t((*it2), object));
3094 }
3095 
removeObjectFromAddressMap(eibaddr_t gad,Object * object)3096 void ObjectController::removeObjectFromAddressMap(eibaddr_t gad, Object* object)
3097 {
3098     if (gad == 0)
3099         return;
3100     std::pair<ObjectMap_t::iterator, ObjectMap_t::iterator> range =
3101         objectMap_m.equal_range(gad);
3102     ObjectMap_t::iterator it = range.first;
3103     while(it != range.second) {
3104         if ((*it).second == object)
3105             objectMap_m.erase(it++);
3106         else
3107             ++it;
3108     }
3109 }
3110 
removeObject(Object * object)3111 void ObjectController::removeObject(Object* object)
3112 {
3113     ObjectIdMap_t::iterator it = objectIdMap_m.find(object->getID());
3114     if (it != objectIdMap_m.end())
3115     {
3116         eibaddr_t gad = it->second->getGad();
3117         removeObjectFromAddressMap(gad, object);
3118 
3119         std::list<eibaddr_t>::iterator it2, it_end;
3120         it_end = object->getListenerGadEnd();
3121         for (it2=object->getListenerGad(); it2!=it_end; it2++)
3122             removeObjectFromAddressMap((*it2), object);
3123 
3124         if (it->second->inUse())
3125             throw ticpp::Exception("Delete failed! Object still in use.");
3126         delete it->second;
3127         objectIdMap_m.erase(it);
3128     }
3129 }
3130 
importXml(ticpp::Element * pConfig)3131 void ObjectController::importXml(ticpp::Element* pConfig)
3132 {
3133     ticpp::Iterator< ticpp::Element > child("object");
3134     for ( child = pConfig->FirstChildElement("object", false); child != child.end(); child++ )
3135     {
3136         std::string id = child->GetAttribute("id");
3137         bool del = child->GetAttribute("delete") == "true";
3138         ObjectIdMap_t::iterator it = objectIdMap_m.find(id);
3139         if (it != objectIdMap_m.end())
3140         {
3141             Object* object = it->second;
3142 
3143             removeObjectFromAddressMap(object->getGad(), object);
3144             std::list<eibaddr_t>::iterator it2, it_end;
3145             it_end = object->getListenerGadEnd();
3146             for (it2=object->getListenerGad(); it2!=it_end; it2++)
3147                 removeObjectFromAddressMap((*it2), object);
3148 
3149             if (del)
3150             {
3151                 if (object->inUse())
3152                     throw ticpp::Exception("Delete failed! Object still in use.");
3153                 delete object;
3154                 objectIdMap_m.erase(it);
3155             }
3156             else
3157             {
3158                 object->importXml(&(*child));
3159                 if (object->getGad())
3160                     objectMap_m.insert(ObjectPair_t(object->getGad(), object));
3161                 std::list<eibaddr_t>::iterator it2, it_end;
3162                 it_end = object->getListenerGadEnd();
3163                 for (it2=object->getListenerGad(); it2!=it_end; it2++)
3164                     objectMap_m.insert(ObjectPair_t((*it2), object));
3165                 objectIdMap_m.insert(ObjectIdPair_t(id, object));
3166             }
3167         }
3168         else
3169         {
3170             if (del)
3171                 throw ticpp::Exception("Object not found");
3172             Object* object = Object::create(&(*child));
3173             if (object->getGad())
3174                 objectMap_m.insert(ObjectPair_t(object->getGad(), object));
3175             std::list<eibaddr_t>::iterator it2, it_end;
3176             it_end = object->getListenerGadEnd();
3177             for (it2=object->getListenerGad(); it2!=it_end; it2++)
3178                 objectMap_m.insert(ObjectPair_t((*it2), object));
3179             objectIdMap_m.insert(ObjectIdPair_t(id, object));
3180         }
3181     }
3182 
3183 }
3184 
exportXml(ticpp::Element * pConfig)3185 void ObjectController::exportXml(ticpp::Element* pConfig)
3186 {
3187     ObjectIdMap_t::iterator it;
3188     for (it = objectIdMap_m.begin(); it != objectIdMap_m.end(); it++)
3189     {
3190         ticpp::Element pElem("object");
3191         (*it).second->exportXml(&pElem);
3192         pConfig->LinkEndChild(&pElem);
3193     }
3194 }
3195 
exportObjectValues(ticpp::Element * pObjects)3196 void ObjectController::exportObjectValues(ticpp::Element* pObjects)
3197 {
3198     ObjectIdMap_t::iterator it;
3199     for (it = objectIdMap_m.begin(); it != objectIdMap_m.end(); it++)
3200     {
3201         ticpp::Element pElem("object");
3202         pElem.SetAttribute("id", (*it).second->getID());
3203         pElem.SetAttribute("value", (*it).second->getValue());
3204         pObjects->LinkEndChild(&pElem);
3205     }
3206 }
3207 
3208 // Delivers all objects
getObjects()3209 std::list<Object*> ObjectController::getObjects()
3210 {
3211     std::list<Object*> objects;
3212     ObjectIdMap_t::iterator it;
3213     for (it = objectIdMap_m.begin(); it != objectIdMap_m.end(); it++)
3214     {
3215       it->second->incRefCount();
3216       objects.push_back((*it).second);
3217     }
3218     return objects;
3219 }
3220