Repository navigation
Expand file tree
/
Copy pathEnOceanESP2.cpp
More file actions
1817 lines (1674 loc) · 60.4 KB
/
Copy pathEnOceanESP2.cpp
File metadata and controls
1817 lines (1674 loc) · 60.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "stdafx.h"
#include "EnOceanESP2.h"
#include "../main/Logger.h"
#include "../main/Helper.h"
#include "../main/RFXtrx.h"
#include "../main/SQLHelper.h"
#include <string>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include "hardwaretypes.h"
#include "../main/localtime_r.h"
#include <ctime>
#define ENOCEAN_RETRY_DELAY 30
#define round(a) ( int ) ( a + .5 )
//Acknowledgments:
//Part of this code it based on the work of Daniel Lechner, Andreas Dielacher
//Note: This is for the ESP 2.0 protocol !!!
struct _tTableLookup2
{
unsigned long ID;
const char* Label;
};
struct _tTableLookup3
{
unsigned long ID1;
unsigned long ID2;
const char* Label;
};
const char *LookupTable2(const _tTableLookup2 *pOrgTable, unsigned long ID)
{
while (pOrgTable->Label)
{
if (pOrgTable->ID == ID)
return pOrgTable->Label;
pOrgTable++;
}
return ">>Unkown... Please report!<<";
}
const char *LookupTable3(const _tTableLookup3 *pOrgTable, unsigned long ID1, unsigned long ID2)
{
while (pOrgTable->Label)
{
if ((pOrgTable->ID1 == ID1)&&(pOrgTable->ID2 == ID2))
return pOrgTable->Label;
pOrgTable++;
}
return ">>Unkown... Please report!<<";
}
const char* Get_EnoceanManufacturer(unsigned long ID)
{
const _tTableLookup2 TTable[]=
{
{ 0x001, "Peha" },
{ 0x002, "Thermokon" },
{ 0x003, "Servodan" },
{ 0x004, "EchoFlex Solutions" },
{ 0x005, "Omnio AG" },
{ 0x006, "Hardmeier electronics" },
{ 0x007, "Regulvar Inc" },
{ 0x008, "Ad Hoc Electronics" },
{ 0x009, "Distech Controls" },
{ 0x00A, "Kieback + Peter" },
{ 0x00B, "EnOcean GmbH" },
{ 0x00C, "Probare" },
{ 0x00D, "Eltako" },
{ 0x00E, "Leviton" },
{ 0x00F, "Honeywell" },
{ 0x010, "Spartan Peripheral Devices" },
{ 0x011, "Siemens" },
{ 0x012, "T-Mac" },
{ 0x013, "Reliable Controls Corporation" },
{ 0x014, "Elsner Elektronik GmbH" },
{ 0x015, "Diehl Controls" },
{ 0x016, "BSC Computer" },
{ 0x017, "S+S Regeltechnik GmbH" },
{ 0x018, "Masco Corporation" },
{ 0x019, "Intesis Software SL" },
{ 0x01A, "Res." },
{ 0x01B, "Lutuo Technology" },
{ 0x01C, "CAN2GO" },
{ 0x01D, "SAUTER" },
{ 0x01E, "BOOT_UP" },
{ 0x01F, "OSRAM SYLVANIA" },
{ 0x020, "UNOTECH" },
{ 0x021, "DELTA_CONTROLS_INC" },
{ 0x022, "UNITRONIC_AG" },
{ 0x023, "NANOSENSE" },
{ 0x024, "THE_S4_GROUP" },
{ 0x025, "MSR_SOLUTIONS" },
{ 0x026, "GE" },
{ 0x027, "MAICO" },
{ 0x028, "RUSKIN_COMPANY" },
{ 0x029, "MAGNUM_ENERGY_SOLUTIONS" },
{ 0x02A, "KMC_CONTROLS" },
{ 0x02B, "ECOLOGIX_CONTROLS" },
{ 0x02C, "TRIO_2_SYS" },
{ 0x02D, "AFRISO_EURO_INDEX" },
{ 0x030, "NEC_ACCESSTECHNICA_LTD" },
{ 0x031, "ITEC_CORPORATION" },
{ 0x032, "SIMICX_CO_LTD" },
{ 0x034, "EUROTRONIC_TECHNOLOGY_GMBH" },
{ 0x035, "ART_JAPAN_CO_LTD" },
{ 0x036, "TIANSU_AUTOMATION_CONTROL_SYSTE_CO_LTD" },
{ 0x038, "GRUPPO_GIORDANO_IDEA_SPA" },
{ 0x039, "ALPHAEOS_AG" },
{ 0x03A, "TAG_TECHNOLOGIES" },
{ 0x03C, "CLOUD_BUILDINGS_LTD" },
{ 0x03E, "GIGA_CONCEPT" },
{ 0x03F, "SENSORTEC" },
{ 0x040, "JAEGER_DIREKT" },
{ 0x041, "AIR_SYSTEM_COMPONENTS_INC" },
{ 0x046, "NodOn" },
{ 0x048, "Ewattch" },
{ 0x7FF, "Multi user Manufacturer ID" },
{ 0, NULL }
};
return LookupTable2(TTable,ID);
}
//EEP 2.5
struct _t4BSLookup
{
const int Org;
const int Func;
const int Type;
const char *Description;
const char *Label;
};
const _t4BSLookup T4BSTable[]=
{
//A5-02: Temperature Sensors
{ 0xA5, 0x02, 0x01, "Temperature Sensor Range -40C to 0C", "Temperature.01" },
{ 0xA5, 0x02, 0x02, "Temperature Sensor Range -30C to +10C", "Temperature.02" },
{ 0xA5, 0x02, 0x03, "Temperature Sensor Range -20C to +20C", "Temperature.03" },
{ 0xA5, 0x02, 0x04, "Temperature Sensor Range -10C to +30C", "Temperature.04" },
{ 0xA5, 0x02, 0x05, "Temperature Sensor Range 0C to +40C", "Temperature.05" },
{ 0xA5, 0x02, 0x06, "Temperature Sensor Range +10C to +50C", "Temperature.06" },
{ 0xA5, 0x02, 0x07, "Temperature Sensor Range +20C to +60C", "Temperature.07" },
{ 0xA5, 0x02, 0x08, "Temperature Sensor Range +30C to +70C", "Temperature.08" },
{ 0xA5, 0x02, 0x09, "Temperature Sensor Range +40C to +80C", "Temperature.09" },
{ 0xA5, 0x02, 0x0A, "Temperature Sensor Range +50C to +90C", "Temperature.0A" },
{ 0xA5, 0x02, 0x0B, "Temperature Sensor Range +60C to +100C", "Temperature.0B" },
{ 0xA5, 0x02, 0x10, "Temperature Sensor Range -60C to +20C", "Temperature.10" },
{ 0xA5, 0x02, 0x11, "Temperature Sensor Range -50C to +30C", "Temperature.11" },
{ 0xA5, 0x02, 0x12, "Temperature Sensor Range -40C to +40C", "Temperature.12" },
{ 0xA5, 0x02, 0x13, "Temperature Sensor Range -30C to +50C", "Temperature.13" },
{ 0xA5, 0x02, 0x14, "Temperature Sensor Range -20C to +60C", "Temperature.14" },
{ 0xA5, 0x02, 0x15, "Temperature Sensor Range -10C to +70C", "Temperature.15" },
{ 0xA5, 0x02, 0x16, "Temperature Sensor Range 0C to +80C", "Temperature.16" },
{ 0xA5, 0x02, 0x17, "Temperature Sensor Range +10C to +90C", "Temperature.17" },
{ 0xA5, 0x02, 0x18, "Temperature Sensor Range +20C to +100C", "Temperature.18" },
{ 0xA5, 0x02, 0x19, "Temperature Sensor Range +30C to +110C", "Temperature.19" },
{ 0xA5, 0x02, 0x1A, "Temperature Sensor Range +40C to +120C", "Temperature.1A" },
{ 0xA5, 0x02, 0x1B, "Temperature Sensor Range +50C to +130C", "Temperature.1B" },
{ 0xA5, 0x02, 0x20, "10 Bit Temperature Sensor Range -10C to +41.2C", "Temperature.20" },
{ 0xA5, 0x02, 0x30, "10 Bit Temperature Sensor Range -40C to +62.3C", "Temperature.30" },
//A5-04: Temperature and Humidity Sensor
{ 0xA5, 0x04, 0x01, "Range 0C to +40C and 0% to 100%", "TempHum.01" },
{ 0xA5, 0x04, 0x02, "Range -20C to +60C and 0% to 100%", "TempHum.02" },
//A5-06: Light Sensor
{ 0xA5, 0x06, 0x01, "Range 300lx to 60.000lx", "LightSensor.01" },
{ 0xA5, 0x06, 0x02, "Range 0lx to 1.020lx", "LightSensor.02" },
{ 0xA5, 0x06, 0x03, "10-bit measurement (1-Lux resolution) with range 0lx to 1000lx", "LightSensor.03" },
//A5-07: Occupancy Sensor
{ 0xA5, 0x07, 0x01, "Occupancy with Supply voltage monitor", "OccupancySensor.01" },
{ 0xA5, 0x07, 0x02, "Occupancy with Supply voltage monitor", "OccupancySensor.02" },
{ 0xA5, 0x07, 0x03, "Occupancy with Supply voltage monitor and 10-bit illumination measurement", "OccupancySensor.03" },
//A5-08: Light, Temperature and Occupancy Sensor
{ 0xA5, 0x08, 0x01, "Range 0lx to 510lx, 0C to +51C and Occupancy Button", "TempOccupancySensor.01" },
{ 0xA5, 0x08, 0x02, "Range 0lx to 1020lx, 0C to +51C and Occupancy Button", "TempOccupancySensor.02" },
{ 0xA5, 0x08, 0x03, "Range 0lx to 1530lx, -30C to +50C and Occupancy Button", "TempOccupancySensor.03" },
//A5-09: Gas Sensor
{ 0xA5, 0x09, 0x01, "CO Sensor (not in use)", "GasSensor.01" },
{ 0xA5, 0x09, 0x02, "CO-Sensor 0 ppm to 1020 ppm", "GasSensor.02" },
{ 0xA5, 0x09, 0x04, "CO2 Sensor", "GasSensor.04" },
{ 0xA5, 0x09, 0x05, "VOC Sensor", "GasSensor.05" },
{ 0xA5, 0x09, 0x06, "Radon", "GasSensor.06" },
{ 0xA5, 0x09, 0x07, "Particles", "GasSensor.07" },
//7. A5-10: Room Operating Panel
{ 0xA5, 0x10, 0x01, "Temperature Sensor, Set Point, Fan Speed and Occupancy Control", "RoomOperatingPanel.01" },
{ 0xA5, 0x10, 0x02, "Temperature Sensor, Set Point, Fan Speed and Day/Night Control", "RoomOperatingPanel.02" },
{ 0xA5, 0x10, 0x03, "Temperature Sensor, Set Point Control", "RoomOperatingPanel.03" },
{ 0xA5, 0x10, 0x04, "Temperature Sensor, Set Point and Fan Speed Control", "RoomOperatingPanel.04" },
{ 0xA5, 0x10, 0x05, "Temperature Sensor, Set Point and Occupancy Control", "RoomOperatingPanel.05" },
{ 0xA5, 0x10, 0x06, "Temperature Sensor, Set Point and Day/Night Control", "RoomOperatingPanel.06" },
{ 0xA5, 0x10, 0x07, "Temperature Sensor, Fan Speed Control", "RoomOperatingPanel.07" },
{ 0xA5, 0x10, 0x08, "Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.08" },
{ 0xA5, 0x10, 0x09, "Temperature Sensor, Fan Speed and Day/Night Control", "RoomOperatingPanel.09" },
{ 0xA5, 0x10, 0x0A, "Temperature Sensor, Set Point Adjust and Single Input Contact", "RoomOperatingPanel.0A" },
{ 0xA5, 0x10, 0x0B, "Temperature Sensor and Single Input Contact", "RoomOperatingPanel.0B" },
{ 0xA5, 0x10, 0x0C, "Temperature Sensor and Occupancy Control", "RoomOperatingPanel.0C" },
{ 0xA5, 0x10, 0x0D, "Temperature Sensor and Day/Night Control", "RoomOperatingPanel.0D" },
{ 0xA5, 0x10, 0x10, "Temperature and Humidity Sensor, Set Point and Occupancy Control", "RoomOperatingPanel.10" },
{ 0xA5, 0x10, 0x11, "Temperature and Humidity Sensor, Set Point and Day/Night Control", "RoomOperatingPanel.11" },
{ 0xA5, 0x10, 0x12, "Temperature and Humidity Sensor and Set Point", "RoomOperatingPanel.12" },
{ 0xA5, 0x10, 0x13, "Temperature and Humidity Sensor, Occupancy Control", "RoomOperatingPanel.13" },
{ 0xA5, 0x10, 0x14, "Temperature and Humidity Sensor, Day/Night Control", "RoomOperatingPanel.14" },
{ 0xA5, 0x10, 0x15, "10 Bit Temperature Sensor, 6 bit Set Point Control", "RoomOperatingPanel.15" },
{ 0xA5, 0x10, 0x16, "10 Bit Temperature Sensor, 6 bit Set Point Control;Occupancy Control", "RoomOperatingPanel.16" },
{ 0xA5, 0x10, 0x17, "10 Bit Temperature Sensor, Occupancy Control", "RoomOperatingPanel.17" },
{ 0xA5, 0x10, 0x18, "Illumination, Temperature Set Point, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.18" },
{ 0xA5, 0x10, 0x19, "Humidity, Temperature Set Point, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.19" },
{ 0xA5, 0x10, 0x1A, "Supply voltage monitor, Temperature Set Point, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.1A" },
{ 0xA5, 0x10, 0x1B, "Supply Voltage Monitor, Illumination, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.1B" },
{ 0xA5, 0x10, 0x1C, "Illumination, Illumination Set Point, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.1C" },
{ 0xA5, 0x10, 0x1D, "Humidity, Humidity Set Point, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.1D" },
{ 0xA5, 0x10, 0x1E, "Supply Voltage Monitor, Illumination, Temperature Sensor, Fan Speed and Occupancy Control", "RoomOperatingPanel.1B" },//same as 1B
{ 0xA5, 0x10, 0x1F, "Temperature Sensor, Set Point, Fan Speed, Occupancy and Un-Occupancy Control", "RoomOperatingPanel.1F" },
//A5-11: Controller Status
{ 0xA5, 0x11, 0x01, "Lighting Controller", "ControllerStatus.01" },
{ 0xA5, 0x11, 0x02, "Temperature Controller Output", "ControllerStatus.02" },
{ 0xA5, 0x11, 0x03, "Blind Status", "ControllerStatus.03" },
{ 0xA5, 0x11, 0x04, "Extended Lighting Status", "ControllerStatus.04" },
//A5-12: Automated meter reading (AMR)
{ 0xA5, 0x12, 0x00, "Counter", "AMR.Counter" },
{ 0xA5, 0x12, 0x01, "Electricity", "AMR.Electricity" },
{ 0xA5, 0x12, 0x02, "Gas", "AMR.Gas" },
{ 0xA5, 0x12, 0x03, "Water", "AMR.Water" },
//A5-13: Environmental Applications
{ 0xA5, 0x13, 0x01, "Weather Station", "EnvironmentalApplications.01" },
{ 0xA5, 0x13, 0x02, "Sun Intensity", "EnvironmentalApplications.02" },
{ 0xA5, 0x13, 0x03, "Date Exchange", "EnvironmentalApplications.03" },
{ 0xA5, 0x13, 0x04, "Time and Day Exchange", "EnvironmentalApplications.04" },
{ 0xA5, 0x13, 0x05, "Direction Exchange", "EnvironmentalApplications.05" },
{ 0xA5, 0x13, 0x06, "Geographic Position Exchange", "EnvironmentalApplications.06" },
{ 0xA5, 0x13, 0x10, "Sun position and radiation", "EnvironmentalApplications.10" },
//A5-14: Multi-Func Sensor
{ 0xA5, 0x14, 0x01, "Single Input Contact (Window/Door), Supply voltage monitor", "MultiFuncSensor.01" },
{ 0xA5, 0x14, 0x02, "Single Input Contact (Window/Door), Supply voltage monitor and Illumination", "MultiFuncSensor.02" },
{ 0xA5, 0x14, 0x03, "Single Input Contact (Window/Door), Supply voltage monitor and Vibration", "MultiFuncSensor.03" },
{ 0xA5, 0x14, 0x04, "Single Input Contact (Window/Door), Supply voltage monitor, Vibration and Illumination", "MultiFuncSensor.04" },
{ 0xA5, 0x14, 0x05, "Vibration/Tilt, Supply voltage monitor", "MultiFuncSensor.05" },
{ 0xA5, 0x14, 0x06, "Vibration/Tilt, Illumination and Supply voltage monitor", "MultiFuncSensor.06" },
//A5-20: HVAC Components
{ 0xA5, 0x20, 0x01, "Battery Powered Actuator (BI-DIR)", "HVAC.01" },
{ 0xA5, 0x20, 0x02, "Basic Actuator (BI-DIR)", "HVAC.02" },
{ 0xA5, 0x20, 0x03, "Line powered Actuator (BI-DIR)", "HVAC.03" },
{ 0xA5, 0x20, 0x10, "Generic HVAC Interface (BI-DIR)", "HVAC.10" },
{ 0xA5, 0x20, 0x11, "Generic HVAC Interface - Error Control (BI-DIR)", "HVAC.11" },
{ 0xA5, 0x20, 0x12, "Temperature Controller Input", "HVAC.12" },
//A5-30: Digital Input
{ 0xA5, 0x30, 0x01, "Single Input Contact, Battery Monitor", "DigitalInput.01" },
{ 0xA5, 0x30, 0x02, "Single Input Contact", "DigitalInput.02" },
//A5-37: Energy Management
{ 0xA5, 0x37, 0x01, "Demand Response", "EnergyManagement.01" },
//A5-38: Central Command
{ 0xA5, 0x38, 0x08, "Gateway", "CentralCommand.01" },
{ 0xA5, 0x38, 0x09, "Extended Lighting-Control", "CentralCommand.02" },
//A5-3F: Universal
{ 0xA5, 0x3F, 0x00, "Radio Link Test (BI-DIR)", "Universal.01" },
//End of table
{ 0, 0, 0, 0, 0 }
};
const char* Get_Enocean4BSType(const int Org, const int Func, const int Type)
{
const _t4BSLookup *pOrgTable=(const _t4BSLookup *)&T4BSTable;
while (pOrgTable->Label)
{
if (
(pOrgTable->Org == Org)&&
(pOrgTable->Func == Func)&&
(pOrgTable->Type == Type)
)
return pOrgTable->Label;
pOrgTable++;
}
return ">>Unkown... Please report!<<";
}
const char* Get_Enocean4BSDesc(const int Org, const int Func, const int Type)
{
const _t4BSLookup *pOrgTable=(const _t4BSLookup *)&T4BSTable;
while (pOrgTable->Label)
{
if (
(pOrgTable->Org == Org)&&
(pOrgTable->Func == Func)&&
(pOrgTable->Type == Type)
)
return pOrgTable->Description;
pOrgTable++;
}
return ">>Unkown... Please report!<<";
}
/**
* \brief The default structure for EnOcean packets
*
* Data structure for RPS, 1BS, 4BS and HRC packages
* Since most of the packages are in this format, this
* is taken as default. Packages of other structure have
* to be converted with the appropriate functions.
**/
typedef struct enocean_data_structure {
unsigned char SYNC_BYTE1; ///< Synchronization Byte 1
unsigned char SYNC_BYTE2; ///< Synchronization Byte 2
unsigned char H_SEQ_LENGTH; ///< Header identification and number of octets following the header octet
unsigned char ORG; ///< Type of telegram
unsigned char DATA_BYTE3; ///< Data Byte 3
unsigned char DATA_BYTE2; ///< Data Byte 2
unsigned char DATA_BYTE1; ///< Data Byte 1
unsigned char DATA_BYTE0; ///< Data Byte 0
unsigned char ID_BYTE3; ///< Transmitter ID Byte 3
unsigned char ID_BYTE2; ///< Transmitter ID Byte 2
unsigned char ID_BYTE1; ///< Transmitter ID Byte 1
unsigned char ID_BYTE0; ///< Transmitter ID Byte 0
unsigned char STATUS; ///< Status field
unsigned char CHECKSUM; ///< Checksum of the packet
} enocean_data_structure;
/// 6DT Package structure
/** Data structure for 6DT packages
**/
typedef struct enocean_data_structure_6DT {
unsigned char SYNC_BYTE1; ///< Synchronization Byte 1
unsigned char SYNC_BYTE2; ///< Synchronization Byte 2
unsigned char H_SEQ_LENGTH; ///< Header identification and number of octets following the header octet
unsigned char ORG; ///< Type of telegram
unsigned char DATA_BYTE5; ///< Data Byte 5
unsigned char DATA_BYTE4; ///< Data Byte 4
unsigned char DATA_BYTE3; ///< Data Byte 3
unsigned char DATA_BYTE2; ///< Data Byte 2
unsigned char DATA_BYTE1; ///< Data Byte 1
unsigned char DATA_BYTE0; ///< Data Byte 0
unsigned char ADDRESS1; ///< Address Byte 1
unsigned char ADDRESS0; ///< Address Byte 0
unsigned char STATUS; ///< Status field
unsigned char CHECKSUM; ///< Checksum of the packet
} enocean_data_structure_6DT;
/// MDA Package structure
/** Data structure for MDA packages
**/
typedef struct enocean_data_structure_MDA {
unsigned char SYNC_BYTE1; ///< Synchronization Byte 1
unsigned char SYNC_BYTE2; ///< Synchronization Byte 2
unsigned char H_SEQ_LENGTH; ///< Header identification and number of octets following the header octet
unsigned char ORG; ///< Type of telegram
unsigned char DATA_UNUSED5; ///< Data Byte 5 (unused)
unsigned char DATA_UNUSED4; ///< Data Byte 4 (unused)
unsigned char DATA_UNUSED3; ///< Data Byte 3 (unused)
unsigned char DATA_UNUSED2; ///< Data Byte 2 (unused)
unsigned char ADDRESS1; ///< Address Byte 1
unsigned char ADDRESS0; ///< Address Byte 0
unsigned char DATA_UNUSED1; ///< Data Byte 1 (unused)
unsigned char DATA_UNUSED0; ///< Data Byte 0 (unused)
unsigned char STATUS; ///< Status field
unsigned char CHECKSUM; ///< Checksum of the packet
} enocean_data_structure_MDA;
#define C_S_BYTE1 0xA5
#define C_S_BYTE2 0x5A
/**
* @defgroup h_seq Header identification
* The definitions for the header identification. This field is contained
* contains the highest 3 bits of the H_SEQ_LENGTH byte.
* @{
*/
/**
* \brief RRT
*
* Header identification says receive radio telegram (RRT)
*/
#define C_H_SEQ_RRT 0x00
/**
* \brief TRT
*
* Header identification says transmit radio telegram (TRT)
*/
#define C_H_SEQ_TRT 0x60
/**
* \brief RMT
*
* Header identification says receive message telegram (RMT)
*/
#define C_H_SEQ_RMT 0x80
/**
* \brief TCT
*
* Header identification says transmit command telegram (TCT)
*/
#define C_H_SEQ_TCT 0xA0
/**
* \brief OK
*
* Standard message to confirm that an action was performed correctly by the TCM
*/
#define H_SEQ_OK 0x80
/**
* \brief ERR
*
* Standard error message response if an action was not performed correctly by the TCM
*/
#define H_SEQ_ERR 0x80
/*@}*/
/**
* @defgroup length Length byte
* Number of octets following the header octed.
* Is contained in the last 5 bits of the H_SEQ_LENGTH byte.
* @{
*/
/**
* \brief Fixed length
*
* Every packet has the same length: 0x0B
*/
#define C_LENGTH 0x0B
/*@}*/
/**
* @defgroup org Type of telegram
* Type definition of the telegram.
* @{
*/
/**
* \brief PTM telegram
*
* Telegram from a PTM switch module received (original or repeated message)
*/
#define C_ORG_RPS 0x05
/**
* \brief 1 byte data telegram
*
* Detailed 1 byte data telegram from a STM sensor module received (original or repeated message)
*/
#define C_ORG_1BS 0x06
/**
* \brief 4 byte data telegram
*
* Detailed 4 byte data telegram from a STM sensor module received (original or repeated message)
*/
#define C_ORG_4BS 0x07
/**
* \brief CTM telegram
*
* Telegram from a CTM module received (original or repeated message)
*/
#define C_ORG_HRC 0x08
/**
* \brief Modem telegram
*
* 6byte Modem Telegram (original or repeated)
*/
#define C_ORG_6DT 0x0A
/**
* \brief Modem ack
*
* Modem Acknowledge Telegram
*/
#define C_ORG_MDA 0x0B
/*@}*/
/**
* \brief ID-range telegram
*
* When this command is sent to the TCM, the base ID range number is retrieved though an INF_IDBASE telegram.
*/
#define C_ORG_RD_IDBASE 0x58
/**
* \brief Reset the TCM 120 module
*
* Performs a reset of the TCM microcontroller. When the TCM is
* ready to operate again, it sends an ASCII message (INF_INIT)
* containing the current settings.
*/
#define C_ORG_RESET 0x0A
/**
* \brief Actual ID range base
*
* This message informs the user about the ID range base number.
* IDBaseByte3 is the most significant byte.
*/
#define C_ORG_INF_IDBASE 0x98
#define C_ORG_RD_SW_VER 0x4B
#define C_ORG_INF_SW_VER 0x8C
/**
* @defgroup bitmasks Bitmasks for various fields.
* There are two definitions for every bit mask. First, the bit mask itself
* and also the number of necessary shifts.
* @{
*/
/**
* @defgroup status_rps Status of telegram (for RPS telegrams)
* Bitmasks for the status-field, if ORG = RPS.
* @{
*/
#define S_RPS_T21 0x20
#define S_RPS_T21_SHIFT 5
#define S_RPS_NU 0x10
#define S_RPS_NU_SHIFT 4
#define S_RPS_RPC 0x0F
#define S_RPS_RPC_SHIFT 0
/*@}*/
/**
* @defgroup status_rpc Status of telegram (for 1BS, 4BS, HRC or 6DT telegrams)
* Bitmasks for the status-field, if ORG = 1BS, 4BS, HRC or 6DT.
* @{
*/
#define S_RPC 0x0F
#define S_RPC_SHIFT 0
/*@}*/
/**
* @defgroup data3 Meaning of data_byte 3 (for RPS telegrams, NU = 1)
* Bitmasks for the data_byte3-field, if ORG = RPS and NU = 1.
* @{
*/
#define DB3_RPS_NU_RID 0xC0
#define DB3_RPS_NU_RID_SHIFT 6
#define DB3_RPS_NU_UD 0x20
#define DB3_RPS_NU_UD_SHIFT 5
#define DB3_RPS_NU_PR 0x10
#define DB3_RPS_NU_PR_SHIFT 4
#define DB3_RPS_NU_SRID 0x0C
#define DB3_RPS_NU_SRID_SHIFT 2
#define DB3_RPS_NU_SUD 0x02
#define DB3_RPS_NU_SUD_SHIFT 1
#define DB3_RPS_NU_SA 0x01
#define DB3_RPS_NU_SA_SHIFT 0
/*@}*/
/**
* @defgroup data3_1 Meaning of data_byte 3 (for RPS telegrams, NU = 0)
* Bitmasks for the data_byte3-field, if ORG = RPS and NU = 0.
* @{
*/
#define DB3_RPS_BUTTONS 0xE0
#define DB3_RPS_BUTTONS_SHIFT 4
#define DB3_RPS_PR 0x10
#define DB3_RPS_PR_SHIFT 3
/*@}*/
/**
* @defgroup data0 Meaning of data_byte 0 (for 4BS telegrams)
* Bitmasks for the data_byte0-field, if ORG = 4BS.
* @{
*/
#define DB0_4BS_DI_3 0x08
#define DB0_4BS_DI_3_SHIFT 3
#define DB0_4BS_DI_2 0x04
#define DB0_4BS_DI_2_SHIFT 2
#define DB0_4BS_DI_1 0x02
#define DB0_4BS_DI_1_SHIFT 1
#define DB0_4BS_DI_0 0x01
#define DB0_4BS_DI_0_SHIFT 0
/*@}*/
/**
* @defgroup data3_hrc Meaning of data_byte 3 (for HRC telegrams)
* Bitmasks for the data_byte3-field, if ORG = HRC.
* @{
*/
#define DB3_HRC_RID 0xC0
#define DB3_HRC_RID_SHIFT 6
#define DB3_HRC_UD 0x20
#define DB3_HRC_UD_SHIFT 5
#define DB3_HRC_PR 0x10
#define DB3_HRC_PR_SHIFT 4
#define DB3_HRC_SR 0x08
#define DB3_HRC_SR_SHIFT 3
/**
* @defgroup Definitions for the string representation
* The definitions for the human-readable string representation
* @{
*/
#define HR_TYPE "Type: "
#define HR_RPS "RPS "
#define HR_1BS "1BS "
#define HR_4BS "4BS "
#define HR_HRC "HRC "
#define HR_6DT "6DT "
#define HR_MDA "MDA "
#define HR_DATA " Data: "
#define HR_SENDER "Sender: "
#define HR_STATUS " Status: "
#define HR_IDBASE "ID_Base: "
#define HR_SOFTWAREVERSION "Software: "
#define HR_TYPEUNKN "unknown "
/**
* @}
*/
CEnOceanESP2::CEnOceanESP2(const int ID, const std::string& devname, const int type)
{
m_HwdID=ID;
m_szSerialPort=devname;
m_Type = type;
m_bufferpos=0;
memset(&m_buffer,0,sizeof(m_buffer));
m_id_base=0;
m_receivestate=ERS_SYNC1;
m_stoprequested=false;
}
CEnOceanESP2::~CEnOceanESP2()
{
}
bool CEnOceanESP2::StartHardware()
{
m_retrycntr=ENOCEAN_RETRY_DELAY*5; //will force reconnect first thing
//Start worker thread
m_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&CEnOceanESP2::Do_Work, this)));
return (m_thread!=NULL);
}
bool CEnOceanESP2::StopHardware()
{
m_stoprequested=true;
if (m_thread)
{
m_thread->join();
// Wait a while. The read thread might be reading. Adding this prevents a pointer error in the async serial class.
sleep_milliseconds(10);
}
terminate();
m_bIsStarted=false;
return true;
}
void CEnOceanESP2::Do_Work()
{
int msec_counter = 0;
int sec_counter = 0;
while (!m_stoprequested)
{
sleep_milliseconds(200);
if (m_stoprequested)
break;
msec_counter++;
if (msec_counter == 5)
{
msec_counter = 0;
sec_counter++;
if (sec_counter % 12 == 0)
{
m_LastHeartbeat = mytime(NULL);
}
}
if (!isOpen())
{
if (m_retrycntr==0)
{
_log.Log(LOG_STATUS,"EnOcean: serial retrying in %d seconds...", ENOCEAN_RETRY_DELAY);
}
m_retrycntr++;
if (m_retrycntr/5>=ENOCEAN_RETRY_DELAY)
{
m_retrycntr=0;
m_bufferpos=0;
OpenSerialDevice();
}
}
if (m_sendqueue.size()>0)
{
boost::lock_guard<boost::mutex> l(m_sendMutex);
std::vector<std::string>::iterator itt=m_sendqueue.begin();
if (itt!=m_sendqueue.end())
{
std::string sBytes=*itt;
write(sBytes.c_str(),sBytes.size());
m_sendqueue.erase(itt);
}
}
}
_log.Log(LOG_STATUS,"EnOcean: Serial Worker stopped...");
}
void CEnOceanESP2::Add2SendQueue(const char* pData, const size_t length)
{
std::string sBytes;
sBytes.insert(0,pData,length);
boost::lock_guard<boost::mutex> l(m_sendMutex);
m_sendqueue.push_back(sBytes);
}
/**
* returns a clean data structure, filled with 0
*/
enocean_data_structure enocean_clean_data_structure() {
int i = 0;
enocean_data_structure ds;
for (i=0;i < sizeof(ds);i++) {
BYTE* b = (BYTE*) &ds + i;
*b = 0x00;
}
return ds;
}
/**
* Convert a data_structure into a data_structure_6DT
* Note: There will be no copy of the passed data_structure.
* So if you change data in the returned new structure, also
* data in the original struct will be changed (pointers!)
*/
enocean_data_structure_6DT* enocean_convert_to_6DT(const enocean_data_structure* in) {
enocean_data_structure_6DT* out;
// no conversion necessary - just overlay the other struct
out = (enocean_data_structure_6DT*) in;
return out;
}
/**
* Convert a data_structure into a data_structure_MDA
* Note: There will be no copy of the passed data_structure.
* So if you change data in the returned new structure, also
* data in the original struct will be changed (pointers!)
*/
enocean_data_structure_MDA* enocean_convert_to_MDA(const enocean_data_structure* in) {
enocean_data_structure_MDA* out;
// no conversion necessary - just overlay the other struct
out = (enocean_data_structure_MDA*) in;
return out;
}
unsigned char enocean_calc_checksum(const enocean_data_structure *input_data) {
unsigned char checksum = 0;
checksum += input_data->H_SEQ_LENGTH;
checksum += input_data->ORG;
checksum += input_data->DATA_BYTE3;
checksum += input_data->DATA_BYTE2;
checksum += input_data->DATA_BYTE1;
checksum += input_data->DATA_BYTE0;
checksum += input_data->ID_BYTE3;
checksum += input_data->ID_BYTE2;
checksum += input_data->ID_BYTE1;
checksum += input_data->ID_BYTE0;
checksum += input_data->STATUS;
return checksum;
}
char* enocean_gethex_internal(BYTE* in, const int framesize) {
char* hexstr = (char*) malloc ((framesize*2)+1); // because every hex-byte needs 2 characters
if (!hexstr)
return NULL;
char* tempstr = hexstr;
int i;
BYTE* bytearray;
bytearray = in;
for (i=0;i<framesize;i++) {
sprintf(tempstr,"%02x",bytearray[i]);
tempstr += 2;
}
return hexstr;
}
char* enocean_hexToHuman(const enocean_data_structure *pFrame)
{
const int framesize = sizeof(enocean_data_structure);
// every byte of the frame takes 2 characters in the human representation + the length of the text blocks (without trailing '\0');
const int stringsize = (framesize*2)+1+sizeof(HR_TYPE)-1+sizeof(HR_RPS)-1+sizeof(HR_DATA)-1+sizeof(HR_SENDER)-1+sizeof(HR_STATUS)-1;
char *humanString = (char*) malloc (stringsize);
if (!humanString)
return NULL;
char *tempstring = humanString;
char *temphexstring;
sprintf(tempstring,HR_TYPE);
tempstring += sizeof(HR_TYPE)-1;
enocean_data_structure_6DT* frame_6DT;
enocean_data_structure_MDA* frame_MDA;
// Now it depends on ORG what to do
switch (pFrame->ORG) {
case C_ORG_INF_IDBASE:
sprintf(tempstring,HR_IDBASE);
tempstring += sizeof(HR_IDBASE)-1;
sprintf(tempstring,"0x%02x%02x%02x%02x",pFrame->DATA_BYTE3,pFrame->DATA_BYTE2,pFrame->DATA_BYTE1,pFrame->DATA_BYTE0);
tempstring += 10;
break;
case C_ORG_INF_SW_VER:
sprintf(tempstring,HR_SOFTWAREVERSION);
tempstring += sizeof(HR_SOFTWAREVERSION)-1;
sprintf(tempstring,"0x%02x%02x%02x%02x",pFrame->ID_BYTE3,pFrame->ID_BYTE2,pFrame->ID_BYTE1,pFrame->ID_BYTE0);
tempstring += 10;
break;
case C_ORG_RPS: // RBS received
case C_ORG_4BS:
case C_ORG_1BS:
case C_ORG_HRC:
switch (pFrame->ORG) {
case C_ORG_RPS: // RBS received
sprintf(tempstring,HR_RPS);
tempstring += sizeof(HR_RPS)-1;
break;
case C_ORG_4BS:
sprintf(tempstring,HR_4BS);
tempstring += sizeof(HR_4BS)-1;
break;
case C_ORG_1BS:
sprintf(tempstring,HR_1BS);
tempstring += sizeof(HR_1BS)-1;
break;
case C_ORG_HRC:
sprintf(tempstring,HR_HRC);
tempstring += sizeof(HR_HRC)-1;
break;
}
sprintf(tempstring,HR_SENDER);
tempstring += sizeof(HR_SENDER)-1;
temphexstring = enocean_gethex_internal((BYTE*)&(pFrame->ID_BYTE3), 4);
if (temphexstring)
{
strcpy(tempstring, temphexstring);
free(temphexstring);
tempstring += 8; // we converted 4 bytes and each one takes 2 chars
}
sprintf(tempstring,HR_DATA);
tempstring += sizeof(HR_DATA)-1;
temphexstring = enocean_gethex_internal((BYTE*)&(pFrame->DATA_BYTE3), 4);
if (temphexstring)
{
strcpy(tempstring, temphexstring);
free(temphexstring);
tempstring += 8; // we converted 4 bytes and each one takes 2 chars
}
break;
case C_ORG_6DT:
sprintf(tempstring,HR_6DT);
frame_6DT = enocean_convert_to_6DT(pFrame);
tempstring += sizeof(HR_6DT)-1;
sprintf(tempstring,HR_SENDER);
tempstring += sizeof(HR_SENDER)-1;
temphexstring = enocean_gethex_internal((BYTE*)&(frame_6DT->ADDRESS1), 2);
if (temphexstring)
{
strcpy(tempstring, temphexstring);
free(temphexstring);
tempstring += 4;
}
sprintf(tempstring,HR_DATA);
tempstring += sizeof(HR_DATA)-1;
temphexstring = enocean_gethex_internal((BYTE*)&(frame_6DT->DATA_BYTE5), 6);
if (temphexstring)
{
strcpy(tempstring, temphexstring);
free(temphexstring);
tempstring += 12;
}
break;
case C_ORG_MDA:
sprintf(tempstring,HR_MDA);
frame_MDA = enocean_convert_to_MDA(pFrame);
tempstring += sizeof(HR_MDA)-1;
sprintf(tempstring,HR_SENDER);
tempstring += sizeof(HR_SENDER)-1;
temphexstring = enocean_gethex_internal((BYTE*)&(frame_MDA->ADDRESS1), 2);
if (temphexstring)
{
strcpy(tempstring, temphexstring);
free(temphexstring);
tempstring += 4;
}
break;
default:
sprintf(tempstring,HR_TYPEUNKN);
tempstring += sizeof(HR_TYPEUNKN)-1;
break;
}
sprintf(tempstring,HR_STATUS);
tempstring += sizeof(HR_STATUS)-1;
temphexstring = enocean_gethex_internal((BYTE*)&(pFrame->STATUS), 1);
if (temphexstring)
{
strcpy(tempstring, temphexstring);
free(temphexstring);
tempstring += 2;
}
return humanString;
}
enocean_data_structure create_base_frame() {
enocean_data_structure returnvalue = enocean_clean_data_structure();
returnvalue.SYNC_BYTE1 = C_S_BYTE1;
returnvalue.SYNC_BYTE2 = C_S_BYTE2;
returnvalue.H_SEQ_LENGTH = C_H_SEQ_TCT | C_LENGTH;
return returnvalue;
}
enocean_data_structure tcm120_reset() {
enocean_data_structure returnvalue = create_base_frame();
returnvalue.ORG = C_ORG_RESET;
returnvalue.CHECKSUM = enocean_calc_checksum(&returnvalue);
return returnvalue;
}
enocean_data_structure tcm120_rd_idbase() {
enocean_data_structure returnvalue = create_base_frame();
returnvalue.ORG = C_ORG_RD_IDBASE;
returnvalue.CHECKSUM = enocean_calc_checksum(&returnvalue);
return returnvalue;
}
enocean_data_structure tcm120_rd_sw_ver() {
enocean_data_structure returnvalue = create_base_frame();
returnvalue.ORG = C_ORG_RD_SW_VER;
returnvalue.CHECKSUM = enocean_calc_checksum(&returnvalue);
return returnvalue;
}
enocean_data_structure tcm120_create_inf_packet() {
enocean_data_structure returnvalue = create_base_frame();
returnvalue.H_SEQ_LENGTH = 0x8B;
returnvalue.ORG = 0x89;
returnvalue.CHECKSUM = enocean_calc_checksum(&returnvalue);
return returnvalue;
}
bool CEnOceanESP2::OpenSerialDevice()
{
//Try to open the Serial Port
try
{
open(m_szSerialPort, 9600); //ECP2 open with 9600
_log.Log(LOG_STATUS,"EnOcean: Using serial port: %s", m_szSerialPort.c_str());
}
catch (boost::exception & e)
{
_log.Log(LOG_ERROR,"EnOcean: Error opening serial port!");
#ifdef _DEBUG
_log.Log(LOG_ERROR,"-----------------\n%s\n----------------", boost::diagnostic_information(e).c_str());
#else
(void)e;
#endif
return false;
}
catch ( ... )
{
_log.Log(LOG_ERROR,"EnOcean: Error opening serial port!!!");
return false;
}
m_bIsStarted=true;
m_receivestate=ERS_SYNC1;
setReadCallback(boost::bind(&CEnOceanESP2::readCallback, this, _1, _2));
sOnConnected(this);
enocean_data_structure iframe;
/*
//Send Initial Reset
iframe = tcm120_reset();
write((const char*)&iframe,sizeof(enocean_data_structure));
sleep_seconds(1);
*/
iframe = tcm120_rd_idbase();
write((const char*)&iframe,sizeof(enocean_data_structure));
return true;
}