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