1 /*
2  * File:   Events.cpp
3  * ONLY for usage with eHouse system controllers | Intellectual property of iSys.Pl
4  * eHouse4Ethernet Server - described in UdpListener.cpp
5  * eHouse1 (RS-485) Server  //described in rs485.cpp
6  * eHouse1 under CommManager Supervision Server - described in UdpListener.cpp
7  * TCP Client for submitting events to Ethernet eHouse Controllers and eHouse 1 via CommManager in case of eHouse under CM supervision version described in TcpClient.c
8  *
9  * EventQueue Process
10  *
11  * Author: Robert Jarzabek, iSys.Pl
12  * http://en.isys.pl/          eHouse Home automation Producer Web Page
13  * http://eHouse.biz/      eHouse Home automation SHOP
14  * http://smart.ehouse.pro/   eHouse Home Automation - Do it yourself, programming examples, designing
15  * Recently updated 11.11.2017
16  * globals.h - global configuration / main settings
17  * most important params for eHouse events manager
18  *
19  * COMMANAGER_IP_HIGH - set CommManager Ip addr h if differs from 192.168.0.254 (192.168.%COMMANAGER_IP_HIGH%.%COMMANAGER_IP_LOW%)
20  * COMMANAGER_IP_LOW - set CommManager Ip addr l
21  * EHOUSE_PRO_HIGH - default eHouse Pro Server IP addr h (0)
22  * EHOUSE_PRO_LOW  - default eHouse Pro Server IP addr l (150)
23  * RE_SEND_RETRIES - No of retries in case of execution failure
24  * RE_TIME_REPLAY  - Timer for retry in (RE_TIME_RETRY-RE_SEND_RETRIES) *0.1s
25  *
26  * Events.cpp - Event Queue processing
27  Recent update: 2018-08-16
28  */
29 
30 #include "stdafx.h"
31 #include "../../main/Logger.h"
32 #include "../eHouseTCP.h"
33 #ifndef WIN32
34 #else
35 #endif
36 #include "globals.h"
37 #include "status.h"
38 
39  /////////////////////////////////////////////////////////////////////////////////
GetIndexOfEvent(unsigned char * TempEvent)40 signed int eHouseTCP::GetIndexOfEvent(unsigned char *TempEvent)
41 {
42 	unsigned int i;
43 	for (i = 0; i < EVENT_QUEUE_MAX; i++)
44 	{
45 		if (memcmp(TempEvent, (struct EventQueueT *) &m_EvQ[i]->LocalEventsToRun, EVENT_SIZE) == 0)
46 			return i;	//Exist on Event Queue
47 	}
48 	return -1;
49 }
50 
51 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
ExecQueuedEvents(void)52 void eHouseTCP::ExecQueuedEvents(void)
53 {
54 	unsigned int i;
55 	unsigned char localy = 1;
56 	m_DisablePerformEvent = 0;
57 	if (!m_EventsCountInQueue) return;	//nothing availabla - we don't waste time here
58 	m_EventsCountInQueue = 0;
59 	for (i = 0; i < EVENT_QUEUE_MAX; i++)
60 	{
61 		if (m_EvQ[i]->LocalEventsToRun[2])	//not empty event
62 		{
63 			m_EventsCountInQueue++;
64 			if (m_EvQ[i]->LocalEventsTimeOuts == RUN_NOW)				//Should be Performed Right Now !!!
65 			{
66 				if (m_EvQ[i]->LocalEventsDrop) _log.Log(LOG_STATUS, "[Perform Queue Event] Q[%d] Now -> Retry: %d", i, m_EvQ[i]->LocalEventsDrop);
67 				m_EvQ[i]->LocalEventsDrop++;						//retries in case of failure
68 				if (m_EvQ[i]->LocalEventsDrop > RE_SEND_RETRIES)	//to much retries (no controller or no communication)
69 				{
70 					if (m_DEBUG_TCPCLIENT) _log.Log(LOG_STATUS, "[Exec Event] Q[%d] Drop Event", i);
71 					memset(m_EvQ[i], 0, sizeof(EventQueueT));		//delete event permanently and immediatelly
72 				}
73 				else
74 				{
75 					ExecEvent(i);								//Send event to hardware
76 					break;
77 				}
78 			}
79 			else
80 				if (m_EvQ[i]->LocalEventsTimeOuts)			//scheduled event
81 					m_EvQ[i]->LocalEventsTimeOuts--;		//decrement timer
82 				else										//Timer reach 0 - remove event from Queue
83 				{
84 					memset(m_EvQ[i], 0, sizeof(EventQueueT));
85 					if (m_DEBUG_TCPCLIENT) _log.Log(LOG_STATUS, "[Exec Event] Remove Event");
86 				}
87 		}
88 	}
89 }
90 //////////////////////////////////////////////////////////////////////////////////
91 /*
92  * Exec Event from EventsQueue EvQ[i]
93  *
94  *
95  */
ExecEvent(unsigned int i)96 void eHouseTCP::ExecEvent(unsigned int i)
97 {
98 	unsigned char devh, devl;
99 	unsigned char EventBuff[255];
100 	unsigned int EventBuffSize;
101 	unsigned int EventSize;
102 	unsigned char EventsToRun[MAX_EVENTS_IN_PACK + 10];
103 	unsigned int m = 0;
104 	EventBuffSize = 0;
105 	EventSize = 0;
106 	devh = m_EvQ[i]->LocalEventsToRun[0];                        //get address from DirectEvent
107 	devl = m_EvQ[i]->LocalEventsToRun[1];
108 	int ind = IndexOfEthDev(devh, devl);						//should be transmited directly to controller or not?
109 	if (ind == 0)											//Via eHouse Pro Server
110 	{
111 		//printf("[Exec Event] RS-485, CAN, RF via PRO \r\n");
112 		int mmm = 0;
113 		for (m = 0; m < EVENT_QUEUE_MAX; m++)					//for all events in queue
114 		{
115 			if ((IndexOfEthDev(devh, devl) == 0) && (m_EvQ[m]->LocalEventsTimeOuts == RUN_NOW))	//group all events in the queue for the same controller scheduled for sending
116 			{
117 				m_EvQ[m]->LocalEventsTimeOuts = RE_TIME_REPLAY;      //Retry timer interval - next time if failed
118 				memcpy(&EventBuff[EventBuffSize], m_EvQ[m]->LocalEventsToRun, EVENT_SIZE);   //Add to send buffer
119 		//        printf("[ via PRO ] %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\r\n",EvQ[m].LocalEventsToRun[0],EvQ[m].LocalEventsToRun[1],EvQ[m].LocalEventsToRun[2],EvQ[m].LocalEventsToRun[3],EvQ[m].LocalEventsToRun[4],EvQ[m].LocalEventsToRun[5],EvQ[m].LocalEventsToRun[6],EvQ[m].LocalEventsToRun[7],EvQ[m].LocalEventsToRun[8],EvQ[m].LocalEventsToRun[9]);
120 				EventBuffSize += EVENT_SIZE;
121 				EventsToRun[EventSize] = m;
122 				EventSize++;
123 				if (EventSize >= MAX_EVENTS_IN_PACK) break;       //As many events as possible
124 			}
125 		}
126 		SendTCPEvent(EventBuff, EventSize, m_SrvAddrH, m_SrvAddrL, EventsToRun);       //Submit via tcp client to desired Ethernet eHouse controller
127 		return;
128 	}
129 	else
130 	{
131 		//  printf("[Exec Event] Ethernet \r\n");
132 		memset(&EventBuff, 0, sizeof(EventBuff));
133 		EventSize = 0;
134 		memset(EventsToRun, 0, sizeof(EventsToRun));
135 		int mmm = 0;
136 		for (m = 0; m < EVENT_QUEUE_MAX; m++)
137 		{
138 			if ((m_EvQ[m]->LocalEventsToRun[0] == devh) && (m_EvQ[m]->LocalEventsToRun[1] == devl) && (m_EvQ[m]->LocalEventsTimeOuts == RUN_NOW))
139 			{
140 				//          printf("[Directly ] %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\r\n",EvQ[m].LocalEventsToRun[0],EvQ[m].LocalEventsToRun[1],EvQ[m].LocalEventsToRun[2],EvQ[m].LocalEventsToRun[3],EvQ[m].LocalEventsToRun[4],EvQ[m].LocalEventsToRun[5],EvQ[m].LocalEventsToRun[6],EvQ[m].LocalEventsToRun[7],EvQ[m].LocalEventsToRun[8],EvQ[m].LocalEventsToRun[9]);
141 				m_EvQ[m]->LocalEventsTimeOuts = RE_TIME_REPLAY;								 //Retry timer interval
142 				memcpy(&EventBuff[EventBuffSize], m_EvQ[m]->LocalEventsToRun, EVENT_SIZE);   //Add to send buffer
143 				EventBuffSize += EVENT_SIZE;
144 				EventsToRun[EventSize] = m;			//We store index of events to control it
145 				EventSize++;
146 				if (EventSize >= MAX_EVENTS_IN_PACK) break;								//As many events as possible
147 			}
148 		}
149 		SendTCPEvent(EventBuff, EventSize, devh, devl, EventsToRun);       //Submit via tcp client to desired Ethernet eHouse controller
150 	}
151 }
152 ///////////////////////////////////////////////////////////////////////////////////////////
153 //
154 //      convert hex string to unsigned char with offset and value checking for text events
155 //
156 ///////////////////////////////////////////////////////////////////////////////////////////
hex2bin(const unsigned char * st,int offset)157 signed int eHouseTCP::hex2bin(const unsigned char *st, int offset)
158 {
159 	char i;
160 	int  tmp = 0;
161 	for (i = 0; i < 2; i++)
162 	{
163 		tmp = tmp << 4;
164 		i = st[offset];
165 		if ((i >= 'A') && (i <= 'F')) tmp += i - 'A' + 10;
166 		else  if ((i >= 'a') && (i <= 'f')) tmp += i - 'a' + 10;
167 		else  if ((i >= '0') && (i <= '9')) tmp += i - '0';
168 		else return -1;
169 		offset++;
170 	}
171 	return tmp;
172 }
173 
174 /////////////////////////////////////////////////////////////////////////////////
175 // add multiple events to event queue - stored in text format with validation
176 ////////////////////////////////////////////////////////////////////////////////
AddTextEvents(unsigned char * ev,int size)177 void eHouseTCP::AddTextEvents(unsigned char *ev, int size)
178 {
179 	unsigned char i = 0;
180 	unsigned char offset = 0;
181 	unsigned char evnt[EVENT_SIZE + 1];
182 	if (size < 20) return;						//ignore if tho short
183 	while (offset < size - 1)
184 	{
185 		int tmp = hex2bin(ev, offset);			// decode Text Hex Coded Event
186 		if (tmp >= 0)						// valid hex char
187 			evnt[i] = (unsigned char)tmp;	// construct binary
188 		else
189 			return;		//ignore if wrong data (non hex digit)
190 		i++;
191 		if (i == 10)		//only if valid eHouse text event 10 binary = 20 hex char event
192 		{
193 			i = 0;
194 			AddToLocalEvent(evnt, 0);	//add to queue
195 		}
196 		offset += 2;
197 	}
198 }
199 
200 
201 
202 /**
203  * AddEvent To Event Queue
204  * param: Even buffer of events - offset shift in buffer to copy
205  */
206 
207 
208  ///////////////////////////////////////////////////////////////////////////////////
209  //  Add Event to Queue for Buffering and Multiple Event Submissions - binary mode
210  //////////////////////////////////////////////////////////////////////////////////
AddToLocalEvent(unsigned char * Even,unsigned char offset)211 signed int eHouseTCP::AddToLocalEvent(unsigned char *Even, unsigned char offset)
212 { //start
213 	signed int i;
214 	//signed int k;
215 	unsigned char Event[EVENT_SIZE + 1];
216 	memcpy(Event, (unsigned char *)&Even[offset], EVENT_SIZE); //copy event from selected offset
217 	if (Event[2] == 0)  return 0;
218 	if (Event[2] == 0xff)  return 0;
219 	i = GetIndexOfEvent(Event);
220 	_log.Log(LOG_STATUS, "[Add Event]: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", Event[0], Event[1], Event[2], Event[3], Event[4], Event[5], Event[6], Event[7], Event[8], Event[9]);
221 
222 	if (i >= 0)       //event already exists in EventQueue
223 	{
224 		if (m_EvQ[i]->LocalEventsTimeOuts >= RUN_NOW)                //Wasn't confirmed - No Successful Execution so far
225 		{
226 
227 		}
228 		else 	m_EvQ[i]->LocalEventsTimeOuts = RUN_NOW - 1;		//Increase time of event not to disappear from queue if it recently run
229 		m_EventsCountInQueue++;
230 		if (m_DEBUG_TCPCLIENT) _log.Log(LOG_STATUS, "[Add Event] Already Exists Q[%d]", i);
231 		return i;
232 	}
233 	//Event was not found in event Queue
234 	for (i = 0; i < EVENT_QUEUE_MAX; i++)
235 	{
236 		if (!m_EvQ[i]->LocalEventsToRun[2])	// Free space then add
237 		{
238 			if (m_DEBUG_TCPCLIENT) _log.Log(LOG_STATUS, "[Add Event] Adding Q[%d]", i);
239 			memcpy(&m_EvQ[i]->LocalEventsToRun, Event, EVENT_SIZE);
240 			m_EventsCountInQueue++;                     //Event count in queue to perform EventQueue
241 			m_EvQ[i]->LocalEventsTimeOuts = RUN_NOW;     //Immediate Run
242 			m_EvQ[i]->LocalEventsDrop = 0;               //First try
243 			m_EvQ[i]->iface = 0;                         //local interface not a gateway
244 			if (m_EvQ[i]->LocalEventsToRun[0] == m_SrvAddrH)
245 				m_EvQ[i]->iface = EV_ETHERNET_EVENT;
246 			else m_EvQ[i]->iface = EV_VIA_EHOUSE_PRO;
247 			return i;
248 		}
249 	}
250 	if (m_DEBUG_TCPCLIENT)  _log.Log(LOG_STATUS, "[Add Event] End of proc");
251 	return -1;
252 }
253