1 #include "stdafx.h"
2 #include "MochadTCP.h"
3 #include "../main/Logger.h"
4 #include "../main/Helper.h"
5 #include "../main/localtime_r.h"
6 #include "../main/RFXtrx.h"
7 #include <iostream>
8
9 #include "hardwaretypes.h"
10 #include "../main/Logger.h"
11
12 #define RETRY_DELAY 30
13
14 enum _eMochadMatchType {
15 ID=0,
16 STD,
17 LINE17,
18 LINE18,
19 EXCLMARK
20 };
21
22 enum _eMochadType {
23 MOCHAD_STATUS=0,
24 MOCHAD_UNIT,
25 MOCHAD_ACTION,
26 MOCHAD_RFSEC
27 };
28
29 typedef struct {
30 _eMochadMatchType matchtype;
31 _eMochadType type;
32 const char* key;
33 int start;
34 int width;
35 } MochadMatch;
36
37 static MochadMatch matchlist[] = {
38 {STD, MOCHAD_STATUS, "House ", 6, 255},
39 {STD, MOCHAD_UNIT, "Tx PL HouseUnit: ", 17, 9},
40 {STD, MOCHAD_UNIT, "Rx PL HouseUnit: ", 17, 9},
41 {STD, MOCHAD_UNIT, "Tx RF HouseUnit: ", 17, 9},
42 {STD, MOCHAD_UNIT, "Rx RF HouseUnit: ", 17, 9},
43 {STD, MOCHAD_ACTION, "Tx PL House: ", 13, 9},
44 {STD, MOCHAD_ACTION, "Rx PL House: ", 13, 9},
45 {STD, MOCHAD_ACTION, "Tx RF House: ", 13, 9},
46 {STD, MOCHAD_ACTION, "Rx RF House: ", 13, 9},
47 {STD, MOCHAD_RFSEC, "Rx RFSEC Addr: ", 15, 8 }
48 };
49
50 //end
51
MochadTCP(const int ID,const std::string & IPAddress,const unsigned short usIPPort)52 MochadTCP::MochadTCP(const int ID, const std::string &IPAddress, const unsigned short usIPPort):
53 m_szIPAddress(IPAddress)
54 {
55 m_HwdID=ID;
56 m_usIPPort=usIPPort;
57 m_linecount=0;
58 m_exclmarkfound=0;
59 m_bufferpos=0;
60
61 memset(&m_mochadbuffer,0,sizeof(m_mochadbuffer));
62 memset(&m_mochadsec, 0, sizeof(m_mochadsec));
63 memset(&m_mochad,0,sizeof(m_mochad));
64
65 m_mochad.LIGHTING1.packetlength = sizeof(m_mochad) - 1;
66 m_mochad.LIGHTING1.packettype = pTypeLighting1;
67 m_mochad.LIGHTING1.subtype = sTypeX10;
68 m_mochad.LIGHTING1.housecode = 0;
69 m_mochad.LIGHTING1.unitcode = 0;
70 m_mochad.LIGHTING1.cmnd = 0;
71
72 m_mochadsec.SECURITY1.packetlength = sizeof(m_mochadsec) - 1;
73 m_mochadsec.SECURITY1.packettype = pTypeSecurity1;
74 m_mochadsec.SECURITY1.subtype = 0;
75 m_mochadsec.SECURITY1.id1 = 0;
76 m_mochadsec.SECURITY1.id2 = 0;
77 m_mochadsec.SECURITY1.id3 = 0;
78 m_mochadsec.SECURITY1.status = sStatusNormal;
79 m_mochadsec.SECURITY1.rssi = 12;
80 m_mochadsec.SECURITY1.battery_level = 0;
81
82 memset(&selected, 0, sizeof(selected));
83 currentHouse=0;
84 currentUnit=0;
85 }
86
~MochadTCP(void)87 MochadTCP::~MochadTCP(void)
88 {
89 }
90
StartHardware()91 bool MochadTCP::StartHardware()
92 {
93 RequestStart();
94
95 //force connect the next first time
96 // m_retrycntr=RETRY_DELAY;
97 // m_bIsStarted=true;
98
99 //Start worker thread
100 m_thread = std::make_shared<std::thread>(&MochadTCP::Do_Work, this);
101 SetThreadNameInt(m_thread->native_handle());
102 return (m_thread != nullptr);
103 }
104
StopHardware()105 bool MochadTCP::StopHardware()
106 {
107 if (m_thread)
108 {
109 RequestStop();
110 m_thread->join();
111 m_thread.reset();
112 }
113 m_bIsStarted=false;
114 return true;
115 }
116
117
OnConnect()118 void MochadTCP::OnConnect()
119 {
120 _log.Log(LOG_STATUS, "Mochad: connected to: %s:%d", m_szIPAddress.c_str(), m_usIPPort);
121 m_bIsStarted = true;
122
123 sOnConnected(this);
124 }
125
OnDisconnect()126 void MochadTCP::OnDisconnect()
127 {
128 _log.Log(LOG_STATUS, "Mochad: disconnected");
129 }
130
OnData(const unsigned char * pData,size_t length)131 void MochadTCP::OnData(const unsigned char *pData, size_t length)
132 {
133 ParseData(pData, length);
134 }
135
Do_Work()136 void MochadTCP::Do_Work()
137 {
138 _log.Log(LOG_STATUS, "Mochad: trying to connect to %s:%d", m_szIPAddress.c_str(), m_usIPPort);
139 int sec_counter = 0;
140 connect(m_szIPAddress, m_usIPPort);
141 while (!IsStopRequested(1000))
142 {
143 sleep_seconds(1);
144 sec_counter++;
145
146 if (sec_counter % 12 == 0) {
147 m_LastHeartbeat = mytime(NULL);
148 }
149 }
150 terminate();
151
152 _log.Log(LOG_STATUS,"Mochad: TCP/IP Worker stopped...");
153 }
154
OnError(const boost::system::error_code & error)155 void MochadTCP::OnError(const boost::system::error_code& error)
156 {
157 if (
158 (error == boost::asio::error::address_in_use) ||
159 (error == boost::asio::error::connection_refused) ||
160 (error == boost::asio::error::access_denied) ||
161 (error == boost::asio::error::host_unreachable) ||
162 (error == boost::asio::error::timed_out)
163 )
164 {
165 _log.Log(LOG_ERROR, "Mochad: Can not connect to: %s:%d", m_szIPAddress.c_str(), m_usIPPort);
166 }
167 else if (
168 (error == boost::asio::error::eof) ||
169 (error == boost::asio::error::connection_reset)
170 )
171 {
172 _log.Log(LOG_STATUS, "Mochad: Connection reset!");
173 }
174 else
175 _log.Log(LOG_ERROR, "Mochad: %s", error.message().c_str());
176 }
177
WriteToHardware(const char * pdata,const unsigned char)178 bool MochadTCP::WriteToHardware(const char *pdata, const unsigned char /*length*/)
179 {
180 //RBUF *m_mochad = (RBUF *)pdata;
181 if (!isConnected())
182 return false;
183 if (pdata[1] == pTypeInterfaceControl && pdata[2] == sTypeInterfaceCommand && pdata[4] == cmdSTATUS) {
184 sprintf (s_buffer,"ST\n");
185 } else if (pdata[1] == pTypeLighting1 && pdata[2] == sTypeX10 && pdata[6] == light1_sOn) {
186 sprintf (s_buffer,"RF %c%d on\n",(char)(pdata[4]), pdata[5]);
187 } else if (pdata[1] == pTypeLighting1 && pdata[2] == sTypeX10 && pdata[6] == light1_sOff) {
188 sprintf (s_buffer,"RF %c%d off\n",(char)(pdata[4]), pdata[5]);
189 } else {
190 // case light1_sDim:
191 // case light1_sBright:
192 // case light1_sAllOn:
193 // case light1_sAllOff:
194 _log.Log(LOG_STATUS, "Mochad: Unknown command %d:%d:%d", pdata[1],pdata[2],pdata[6]);
195 return false;
196 }
197 // _log.Log(LOG_STATUS, "Mochad: send '%s'", s_buffer);
198 write((const unsigned char *)s_buffer, strlen(s_buffer));
199 return true;
200 }
201
MatchLine()202 void MochadTCP::MatchLine()
203 {
204 if ((strlen((const char*)&m_mochadbuffer)<1)||(m_mochadbuffer[0]==0x0a))
205 return; //null value (startup)
206 uint8_t i;
207 int j,k;
208 uint8_t found=0;
209 MochadMatch t;
210 char value[20]="";
211 std::string vString;
212
213
214
215 for(i=0;(i<sizeof(matchlist)/sizeof(MochadMatch))&(!found);i++)
216 {
217 t = matchlist[i];
218 switch(t.matchtype)
219 {
220 case ID:
221 if(strncmp(t.key, (const char*)&m_mochadbuffer, strlen(t.key)) == 0) {
222 m_linecount=1;
223 found=1;
224 }
225 else
226 continue;
227 break;
228 case STD:
229 if(strncmp(t.key, (const char*)&m_mochadbuffer, strlen(t.key)) == 0) {
230 found=1;
231 }
232 else
233 continue;
234 break;
235 case LINE17:
236 if(strncmp(t.key, (const char*)&m_mochadbuffer, strlen(t.key)) == 0) {
237 m_linecount = 17;
238 found=1;
239 }
240 else
241 continue;
242 break;
243 case LINE18:
244 if((m_linecount == 18)&&(strncmp(t.key, (const char*)&m_mochadbuffer, strlen(t.key)) == 0)) {
245 found=1;
246 }
247 break;
248 case EXCLMARK:
249 if(strncmp(t.key, (const char*)&m_mochadbuffer, strlen(t.key)) == 0) {
250 m_exclmarkfound=1;
251 found=1;
252 }
253 else
254 continue;
255 break;
256 default:
257 continue;
258 } //switch
259 }
260 if(!found)
261 goto onError;
262
263 switch (t.type)
264 {
265 case MOCHAD_STATUS:
266 j = t.start;
267 if (!('A'<= m_mochadbuffer[j] && m_mochadbuffer[j] <='Z'))
268 goto onError;
269 m_mochad.LIGHTING1.housecode = m_mochadbuffer[j++];
270 if (!(':'== m_mochadbuffer[j++])) goto onError;
271 if (!(' '== m_mochadbuffer[j++])) goto onError;
272 while ('1' <= m_mochadbuffer[j] && m_mochadbuffer[j] <= '9') {
273 m_mochad.LIGHTING1.unitcode = m_mochadbuffer[j++] - '0';
274 if ('0' <= m_mochadbuffer[j] && m_mochadbuffer[j] <= '9') {
275 m_mochad.LIGHTING1.unitcode = m_mochad.LIGHTING1.unitcode*10 + m_mochadbuffer[j++] - '0';
276 }
277 if (!('='== m_mochadbuffer[j++]))
278 return;
279 if (!('0' <= m_mochadbuffer[j] && m_mochadbuffer[j] <= '1')) goto onError;
280 m_mochad.LIGHTING1.cmnd = m_mochadbuffer[j++] - '0';
281 sDecodeRXMessage(this, (const unsigned char *)&m_mochad, NULL, 255);
282 if (!(','== m_mochadbuffer[j++])) return;
283 }
284 break;
285 case MOCHAD_UNIT:
286 j = t.start;
287 if (!('A'<= m_mochadbuffer[j] && m_mochadbuffer[j] <='Z')) goto onError;
288 currentHouse = m_mochadbuffer[j++]-'A';
289 if (!('0' <= m_mochadbuffer[j] && m_mochadbuffer[j] <= '9')) goto onError;
290 currentUnit = m_mochadbuffer[j++] - '0';
291 if (('0' <= m_mochadbuffer[j] && m_mochadbuffer[j] <= '9'))
292 currentUnit = currentUnit*10 + m_mochadbuffer[j++] - '0';
293 selected[currentHouse][currentUnit] = 1;
294 if (!(' '== m_mochadbuffer[j++])) return;
295 goto checkFunc;
296 break;
297 case MOCHAD_ACTION:
298 j = t.start;
299 if (!('A'<= m_mochadbuffer[j] && m_mochadbuffer[j] <='Z'))
300 goto onError;
301 currentHouse = m_mochadbuffer[j++]-'A';
302 if (!(' '== m_mochadbuffer[j++])) goto onError;
303 checkFunc:
304 if (!('F'== m_mochadbuffer[j++])) goto onError;
305 if (!('u'== m_mochadbuffer[j++])) goto onError;
306 if (!('n'== m_mochadbuffer[j++])) goto onError;
307 if (!('c'== m_mochadbuffer[j++])) goto onError;
308 if (!(':'== m_mochadbuffer[j++])) goto onError;
309 if (!(' '== m_mochadbuffer[j++])) goto onError;
310 if (!('O'== m_mochadbuffer[j++])) goto onError;
311 if ('f'== m_mochadbuffer[j]) m_mochad.LIGHTING1.cmnd = 0;
312 else
313 if ('n'== m_mochadbuffer[j]) m_mochad.LIGHTING1.cmnd = 1;
314 else goto onError;
315 for (k=1;k<=16;k++) {
316 if (selected[currentHouse][k] >0) {
317 m_mochad.LIGHTING1.housecode = (BYTE)(currentHouse+'A');
318 m_mochad.LIGHTING1.unitcode = (BYTE)k;
319 sDecodeRXMessage(this, (const unsigned char *)&m_mochad, NULL, 255);
320 selected[currentHouse][k] = 0;
321 }
322 }
323 break;
324 case MOCHAD_RFSEC:
325 j = t.start;
326 char *pchar;
327 char tempRFSECbuf[50];
328
329 if (strstr((const char*)&m_mochadbuffer[j], "DS10A"))
330 {
331 m_mochadsec.SECURITY1.subtype = sTypeSecX10;
332 setSecID(&m_mochadbuffer[t.start]);
333 m_mochadsec.SECURITY1.battery_level = 0x0f;
334
335 // parse sensor conditions, e.g. "Contact_alert_min_DS10A" or "'Contact_normal_max_low_DS10A"
336 strcpy(tempRFSECbuf, (const char *)&m_mochadbuffer[t.start + t.width + 7]);
337 pchar = strtok(tempRFSECbuf, " _");
338 while (pchar != NULL)
339 {
340 if (strcmp(pchar, "alert") == 0)
341 m_mochadsec.SECURITY1.status = sStatusAlarm;
342 else if (strcmp(pchar, "normal") == 0)
343 m_mochadsec.SECURITY1.status = sStatusNormal;
344 else if (strcmp(pchar, "max") == 0)
345 {
346 if (m_mochadsec.SECURITY1.status == sStatusAlarm)
347 m_mochadsec.SECURITY1.status = sStatusAlarmDelayed;
348 else if (m_mochadsec.SECURITY1.status == sStatusNormal)
349 m_mochadsec.SECURITY1.status = sStatusNormalDelayed;
350 }
351 else if (strcmp(pchar, "low") == 0)
352 m_mochadsec.SECURITY1.battery_level = 1;
353 pchar = strtok(NULL, " _");
354 }
355 m_mochadsec.SECURITY1.rssi = 12; // signal strength ?? 12 = no signal strength
356 }
357 else if (strstr((const char *)&m_mochadbuffer[j], "KR10A"))
358 {
359 m_mochadsec.SECURITY1.subtype = sTypeSecX10R;
360 setSecID(&m_mochadbuffer[t.start]);
361 m_mochadsec.SECURITY1.battery_level = 0x0f;
362
363 // parse remote conditions, e.g. "Panic_KR10A" "Lights_On_KR10A" "Lights_Off_KR10A" "Disarm_KR10A" "Arm_KR10A"
364 strcpy(tempRFSECbuf, (const char *)&m_mochadbuffer[t.start + t.width + 7]);
365 pchar = strtok(tempRFSECbuf, " _");
366 while (pchar != NULL)
367 {
368 if (strcmp(pchar, "Panic") == 0)
369 m_mochadsec.SECURITY1.status = sStatusPanic;
370 else if (strcmp(pchar, "Disarm") == 0)
371 m_mochadsec.SECURITY1.status = sStatusDisarm;
372 else if (strcmp(pchar, "Arm") == 0)
373 m_mochadsec.SECURITY1.status = sStatusArmAway;
374 else if (strcmp(pchar, "On") == 0)
375 m_mochadsec.SECURITY1.status = sStatusLightOn;
376 else if (strcmp(pchar, "Off") == 0)
377 m_mochadsec.SECURITY1.status = sStatusLightOff;
378 pchar = strtok(NULL, " _");
379 }
380 m_mochadsec.SECURITY1.rssi = 12;
381 }
382 else if (strstr((const char *)&m_mochadbuffer[j], "MS10A"))
383 {
384 m_mochadsec.SECURITY1.subtype = sTypeSecX10M;
385 setSecID(&m_mochadbuffer[t.start]);
386 m_mochadsec.SECURITY1.battery_level = 0x0f;
387
388 // parse remote conditions, "Motion_alert_MS10A" and "Motion_normal_MS10A"
389 strcpy(tempRFSECbuf, (const char *)&m_mochadbuffer[t.start + t.width + 7]);
390 pchar = strtok(tempRFSECbuf, " _");
391 while (pchar != NULL)
392 {
393 if (strcmp(pchar, "alert") == 0)
394 m_mochadsec.SECURITY1.status = sStatusMotion;
395 else if (strcmp(pchar, "normal") == 0)
396 m_mochadsec.SECURITY1.status = sStatusNoMotion;
397 else if (strcmp(pchar, "low") == 0)
398 m_mochadsec.SECURITY1.battery_level = 1;
399 pchar = strtok(NULL, " _");
400 }
401 m_mochadsec.SECURITY1.rssi = 12;
402 }
403 else
404 goto onError;
405
406 sDecodeRXMessage(this, (const unsigned char *)&m_mochadsec, NULL, 255);
407 break;
408 }
409 return;
410 onError:
411 _log.Log(LOG_ERROR, "Mochad: Cannot decode '%s'", m_mochadbuffer);
412
413 }
414
ParseData(const unsigned char * pData,int Len)415 void MochadTCP::ParseData(const unsigned char *pData, int Len)
416 {
417 int ii=0;
418 while (ii<Len)
419 {
420 const unsigned char c = pData[ii];
421 if(c == 0x0d)
422 {
423 ii++;
424 continue;
425 }
426
427 m_mochadbuffer[m_bufferpos] = c;
428 if(c == 0x0a || m_bufferpos == sizeof(m_mochadbuffer) - 1)
429 {
430 // discard newline, close string, parse line and clear it.
431 if(m_bufferpos > 0) m_mochadbuffer[m_bufferpos] = 0;
432 m_linecount++;
433 if (strlen((const char *)m_mochadbuffer) > 14) {
434 int i = 0;
435 while (m_mochadbuffer[i+15] != 0) {
436 m_mochadbuffer[i] = m_mochadbuffer[i+15];
437 i++;
438 }
439 m_mochadbuffer[i] = 0;
440 // _log.Log(LOG_STATUS, "Mochad: recv '%s'", m_mochadbuffer);
441 MatchLine();
442 }
443 m_bufferpos = 0;
444 }
445 else
446 {
447 m_bufferpos++;
448 }
449 ii++;
450 }
451 }
452
setSecID(unsigned char * p)453 void MochadTCP::setSecID(unsigned char *p)
454 {
455 int j = 0;
456 m_mochadsec.SECURITY1.id1 = (hex2bin(p[j++]) << 4);
457 m_mochadsec.SECURITY1.id1 |= hex2bin(p[j++]);
458 j++; // skip the ":"
459 m_mochadsec.SECURITY1.id2 = (hex2bin(p[j++]) << 4);
460 m_mochadsec.SECURITY1.id2 |= hex2bin(p[j++]);
461 j++; // skip the ":"
462 m_mochadsec.SECURITY1.id3 = (hex2bin(p[j++]) << 4);
463 m_mochadsec.SECURITY1.id3 |= hex2bin(p[j]);
464 }
465
hex2bin(char h)466 unsigned char MochadTCP::hex2bin(char h)
467 {
468 if (h >= '0' && h <= '9')
469 return h - '0';
470 if (h >= 'A' && h <= 'F')
471 return h - 'A' + 10;
472 // handle lower-case hex letter
473 return h - 'a' + 10;
474 }
475