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