1 #include "stdafx.h"
2 #include "DavisLoggerSerial.h"
3 #include "../main/Logger.h"
4 #include "hardwaretypes.h"
5 #include "../main/RFXtrx.h"
6 #include "../main/Helper.h"
7 
8 #include <string>
9 #include <algorithm>
10 #include <iostream>
11 #include <boost/bind.hpp>
12 
13 #include "../main/localtime_r.h"
14 #include "../main/mainworker.h"
15 
16 #include <ctime>
17 
18 #ifdef _DEBUG
19 //#define DEBUG_DAVIS
20 #endif
21 
22 #define RETRY_DELAY 30
23 #define DAVIS_READ_INTERVAL 30
24 
25 #define round(a) ( int ) ( a + .5 )
26 
CDavisLoggerSerial(const int ID,const std::string & devname,unsigned int baud_rate)27 CDavisLoggerSerial::CDavisLoggerSerial(const int ID, const std::string& devname, unsigned int baud_rate) :
28 	m_szSerialPort(devname)
29 {
30 	m_HwdID = ID;
31 	m_iBaudRate = baud_rate;
32 	m_retrycntr = RETRY_DELAY;
33 	m_statecounter = 0;
34 	m_state = DSTATE_WAKEUP;
35 }
36 
~CDavisLoggerSerial(void)37 CDavisLoggerSerial::~CDavisLoggerSerial(void)
38 {
39 
40 }
41 
StartHardware()42 bool CDavisLoggerSerial::StartHardware()
43 {
44 	StopHardware();
45 
46 	RequestStart();
47 
48 	m_retrycntr = RETRY_DELAY; //will force reconnect first thing
49 	//Start worker thread
50 	m_thread = std::make_shared<std::thread>(&CDavisLoggerSerial::Do_Work, this);
51 	SetThreadNameInt(m_thread->native_handle());
52 	return (m_thread != nullptr);
53 
54 }
55 
StopHardware()56 bool CDavisLoggerSerial::StopHardware()
57 {
58 	if (m_thread)
59 	{
60 		RequestStop();
61 		m_thread->join();
62 		m_thread.reset();
63 	}
64 	m_bIsStarted = false;
65 	return true;
66 }
67 
OpenSerialDevice()68 bool CDavisLoggerSerial::OpenSerialDevice()
69 {
70 	//Try to open the Serial Port
71 	try
72 	{
73 		open(m_szSerialPort, m_iBaudRate);
74 		Log(LOG_STATUS, "Using serial port: %s", m_szSerialPort.c_str());
75 		m_statecounter = 0;
76 		m_state = DSTATE_WAKEUP;
77 	}
78 	catch (boost::exception & e)
79 	{
80 		Log(LOG_ERROR, "Error opening serial port!");
81 #ifdef _DEBUG
82 		Log(LOG_ERROR, "-----------------\n%s\n----------------", boost::diagnostic_information(e).c_str());
83 #else
84 		(void)e;
85 #endif
86 		return false;
87 	}
88 	catch (...)
89 	{
90 		Log(LOG_ERROR, "Error opening serial port!!!");
91 		return false;
92 	}
93 	m_bIsStarted = true;
94 	setReadCallback(boost::bind(&CDavisLoggerSerial::readCallback, this, _1, _2));
95 	sOnConnected(this);
96 	return true;
97 }
98 
WriteToHardware(const char *,const unsigned char)99 bool CDavisLoggerSerial::WriteToHardware(const char* /*pdata*/, const unsigned char /*length*/)
100 {
101 	return false;
102 }
103 
Do_Work()104 void CDavisLoggerSerial::Do_Work()
105 {
106 	Log(LOG_STATUS, "Worker started...");
107 
108 	int sec_counter = 0;
109 	while (!IsStopRequested(1000))
110 	{
111 		sec_counter++;
112 		if (sec_counter % 12 == 0) {
113 			mytime(&m_LastHeartbeat);
114 		}
115 		if (!isOpen())
116 		{
117 			if (m_retrycntr == 0)
118 			{
119 				Log(LOG_STATUS, "serial setup retry in %d seconds...", RETRY_DELAY);
120 			}
121 			m_retrycntr++;
122 			if (m_retrycntr >= RETRY_DELAY)
123 			{
124 				m_retrycntr = 0;
125 				OpenSerialDevice();
126 			}
127 		}
128 		else
129 		{
130 			switch (m_state)
131 			{
132 			case DSTATE_WAKEUP:
133 				m_statecounter++;
134 				if (m_statecounter < 5) {
135 					write("\n", 1);
136 				}
137 				else {
138 					m_retrycntr = 0;
139 					//still did not receive a wakeup, lets try again
140 					terminate();
141 				}
142 				break;
143 			case DSTATE_LOOP:
144 				m_statecounter++;
145 				if (m_statecounter >= DAVIS_READ_INTERVAL)
146 				{
147 					m_statecounter = 0;
148 					write("LOOP 1\n", 7);
149 				}
150 				break;
151 			}
152 		}
153 	}
154 	terminate();
155 
156 	Log(LOG_STATUS, "Worker stopped...");
157 }
158 
readCallback(const char * data,size_t len)159 void CDavisLoggerSerial::readCallback(const char *data, size_t len)
160 {
161 	try
162 	{
163 		//Log(LOG_NORM,"received %ld bytes",len);
164 
165 		switch (m_state)
166 		{
167 		case DSTATE_WAKEUP:
168 			if (len == 2) {
169 				Log(LOG_NORM, "System is Awake...");
170 				m_state = DSTATE_LOOP;
171 				m_statecounter = DAVIS_READ_INTERVAL - 1;
172 			}
173 			break;
174 		case DSTATE_LOOP:
175 			if (len == 2)
176 				break; //could be a left over from the awake
177 			if (len != 100) {
178 				Log(LOG_ERROR, "Invalid bytes received!...");
179 				//lets try again
180 				terminate();
181 			}
182 			else {
183 				if (!HandleLoopData((const unsigned char*)data, len))
184 				{
185 					//error in data, try again...
186 					terminate();
187 				}
188 			}
189 			break;
190 		}
191 	}
192 	catch (...)
193 	{
194 
195 	}
196 }
197 
HandleLoopData(const unsigned char * data,size_t len)198 bool CDavisLoggerSerial::HandleLoopData(const unsigned char *data, size_t len)
199 {
200 	const uint8_t *pData = data + 1;
201 
202 #ifndef DEBUG_DAVIS
203 	if (len != 100)
204 		return false;
205 
206 	if (
207 		(data[1] != 'L') ||
208 		(data[2] != 'O') ||
209 		(data[3] != 'O') ||
210 		(data[96] != 0x0a) ||
211 		(data[97] != 0x0d)
212 		)
213 		return false;
214 	//bool bIsRevA = (data[4]=='P');
215 #else
216 	//	FILE *fOut=fopen("davisrob.bin","wb+");
217 	//	fwrite(data,1,len,fOut);
218 	//	fclose(fOut);
219 	unsigned char szBuffer[200];
220 	FILE *fIn = fopen("E:\\davis2.bin", "rb+");
221 	//FILE *fIn=fopen("davisrob.bin","rb+");
222 	fread(&szBuffer, 1, 100, fIn);
223 	fclose(fIn);
224 	pData = szBuffer + 1;
225 	//bool bIsRevA(szBuffer[4]=='P');
226 #endif
227 
228 	RBUF tsen;
229 	memset(&tsen, 0, sizeof(RBUF));
230 
231 
232 	unsigned char tempIdx = 1;
233 
234 	bool bBaroValid = false;
235 	float BaroMeter = 0;
236 	bool bInsideTemperatureValid = false;
237 	float InsideTemperature = 0;
238 	bool bInsideHumidityValid = false;
239 	int InsideHumidity = 0;
240 	bool bOutsideTemperatureValid = false;
241 	float OutsideTemperature = 0;
242 	bool bOutsideHumidityValid = false;
243 	int OutsideHumidity = 0;
244 
245 	bool bWindDirectionValid = false;
246 	int WindDirection = 0;
247 
248 	bool bWindSpeedValid = false;
249 	float WindSpeed = 0;
250 	//bool bWindSpeedAVR10Valid=false;
251 	//float WindSpeedAVR10=0;
252 
253 	bool bUVValid = false;
254 	float UV = 0;
255 
256 	//Barometer
257 	if ((pData[7] != 0xFF) && (pData[8] != 0xFF))
258 	{
259 		bBaroValid = true;
260 		BaroMeter = ((unsigned int)((pData[8] << 8) | pData[7])) / 29.53f; //in hPa
261 	}
262 	//Inside Temperature
263 	if ((pData[9] != 0xFF) || (pData[10] != 0x7F))
264 	{
265 		bInsideTemperatureValid = true;
266 		InsideTemperature = ((unsigned int)((pData[10] << 8) | pData[9])) / 10.f;
267 		InsideTemperature = (InsideTemperature - 32.0f) * 5.0f / 9.0f;
268 	}
269 	//Inside Humidity
270 	if (pData[11] != 0xFF)
271 	{
272 		InsideHumidity = pData[11];
273 		if (InsideHumidity < 101)
274 			bInsideHumidityValid = true;
275 	}
276 
277 	if (bBaroValid&&bInsideTemperatureValid&&bInsideHumidityValid)
278 	{
279 		uint8_t forecastitem = pData[89];
280 		uint8_t forecast = 0;
281 
282 		if ((forecastitem & 0x01) == 0x01)
283 			forecast = wsbaroforecast_rain;
284 		else if ((forecastitem & 0x02) == 0x02)
285 			forecast = wsbaroforecast_cloudy;
286 		else if ((forecastitem & 0x04) == 0x04)
287 			forecast = wsbaroforecast_some_clouds;
288 		else if ((forecastitem & 0x08) == 0x08)
289 			forecast = wsbaroforecast_sunny;
290 		else if ((forecastitem & 0x10) == 0x10)
291 			forecast = wsbaroforecast_snow;
292 
293 		SendTempHumBaroSensorFloat(tempIdx++, 255, InsideTemperature, InsideHumidity, BaroMeter, forecast, "THB");
294 	}
295 
296 	//Outside Temperature
297 	if ((pData[12] != 0xFF) || (pData[13] != 0x7F))
298 	{
299 		bOutsideTemperatureValid = true;
300 		//OutsideTemperature=((unsigned int)((pData[13] << 8) | pData[12])) / 10.f;
301 		//OutsideTemperature = (OutsideTemperature - 32.0f) * 5.0f / 9.0f;
302 
303 		uint8_t msb = pData[13];
304 		uint8_t lsb = pData[12];
305 
306 		uint16_t temp16 = ((msb << 8) | lsb);
307 		if (temp16 > 0x800) {
308 			// Negative values, convert to float from two complements int
309 			int temp_int = (temp16 | ~((1 << 16) - 1));
310 			OutsideTemperature = (float)temp_int / 10.0f;
311 		}
312 		else {
313 			OutsideTemperature = (float)temp16 / 10.0f;
314 		}
315 
316 		// Convert to celsius
317 		OutsideTemperature = (OutsideTemperature - 32.0f) * 5.0f / 9.0f;
318 	}
319 	//Outside Humidity
320 	if (pData[33] != 0xFF)
321 	{
322 		OutsideHumidity = pData[33];
323 		if (OutsideHumidity < 101)
324 			bOutsideHumidityValid = true;
325 	}
326 	if (bOutsideTemperatureValid || bOutsideHumidityValid)
327 	{
328 		if ((bOutsideTemperatureValid) && (bOutsideHumidityValid))
329 		{
330 			//Temp+hum
331 			SendTempHumSensor(tempIdx++, 255, OutsideTemperature, OutsideHumidity, "Outside TempHum");
332 		}
333 		else if (bOutsideTemperatureValid)
334 		{
335 			//Temp
336 			SendTempSensor(tempIdx++, 255, OutsideTemperature, "Outside Temp");
337 		}
338 		else if (bOutsideHumidityValid)
339 		{
340 			//hum
341 			SendHumiditySensor(tempIdx++, 255, OutsideHumidity, "Outside Humidity");
342 		}
343 	}
344 
345 	tempIdx = 10;
346 	//Add Extra Temp/Hum Sensors
347 	int iTmp;
348 	for (iTmp = 0; iTmp < 7; iTmp++)
349 	{
350 		bool bTempValid = false;
351 		bool bHumValid = false;
352 		float temp = 0;
353 		uint8_t hum = 0;
354 
355 		if (pData[18 + iTmp] != 0xFF)
356 		{
357 			bTempValid = true;
358 			temp = pData[18 + iTmp] - 90.0f;
359 			temp = (temp - 32.0f) * 5.0f / 9.0f;
360 		}
361 		if (pData[34 + iTmp] != 0xFF)
362 		{
363 			bHumValid = true;
364 			hum = pData[34 + iTmp];
365 		}
366 		if ((bTempValid) && (bHumValid))
367 		{
368 			//Temp+hum
369 			SendTempHumSensor(tempIdx++, 255, temp, hum, "Extra TempHum");
370 		}
371 		else if (bTempValid)
372 		{
373 			//Temp
374 			SendTempSensor(tempIdx++, 255, temp, "Extra Temp");
375 		}
376 		else if (bHumValid)
377 		{
378 			//hum
379 			SendHumiditySensor(tempIdx++, 255, hum, "Extra Humidity");
380 		}
381 	}
382 
383 	tempIdx = 20;
384 	//Add Extra Soil Temp Sensors
385 	for (iTmp = 0; iTmp < 4; iTmp++)
386 	{
387 		bool bTempValid = false;
388 		float temp = 0;
389 
390 		if (pData[25 + iTmp] != 0xFF)
391 		{
392 			bTempValid = true;
393 			temp = pData[25 + iTmp] - 90.0f;
394 			temp = (temp - 32.0f) * 5.0f / 9.0f;
395 		}
396 		if (bTempValid)
397 		{
398 			SendTempSensor(tempIdx++, 255, temp, "Soil Temp");
399 		}
400 	}
401 
402 	tempIdx = 30;
403 	//Add Extra Leaf Temp Sensors
404 	for (iTmp = 0; iTmp < 4; iTmp++)
405 	{
406 		bool bTempValid = false;
407 		float temp = 0;
408 
409 		if (pData[29 + iTmp] != 0xFF)
410 		{
411 			bTempValid = true;
412 			temp = pData[29 + iTmp] - 90.0f;
413 			temp = (temp - 32.0f) * 5.0f / 9.0f;
414 		}
415 		if (bTempValid)
416 		{
417 			SendTempSensor(tempIdx++, 255, temp, "Leaf Temp");
418 		}
419 	}
420 
421 	//Wind Speed
422 	if (pData[14] != 0xFF)
423 	{
424 		bWindSpeedValid = true;
425 		WindSpeed = (pData[14])*(4.0f / 9.0f);
426 	}
427 	//Wind Speed AVR 10 minutes
428 	if (pData[15] != 0xFF)
429 	{
430 		//bWindSpeedAVR10Valid=true;
431 		//WindSpeedAVR10=(pData[15])*(4.0f/9.0f);
432 	}
433 	//Wind Direction
434 	if ((pData[16] != 0xFF) && (pData[17] != 0x7F))
435 	{
436 		bWindDirectionValid = true;
437 		WindDirection = ((unsigned int)((pData[17] << 8) | pData[16]));
438 	}
439 
440 	if ((bWindSpeedValid) && (bWindDirectionValid))
441 	{
442 		memset(&tsen, 0, sizeof(RBUF));
443 		tsen.WIND.packetlength = sizeof(tsen.WIND) - 1;
444 		tsen.WIND.packettype = pTypeWIND;
445 		tsen.WIND.subtype = sTypeWINDNoTemp;
446 		tsen.WIND.battery_level = 9;
447 		tsen.WIND.rssi = 12;
448 		tsen.WIND.id1 = 0;
449 		tsen.WIND.id2 = 1;
450 
451 		int aw = round(WindDirection);
452 		tsen.WIND.directionh = (BYTE)(aw / 256);
453 		aw -= (tsen.WIND.directionh * 256);
454 		tsen.WIND.directionl = (BYTE)(aw);
455 
456 		tsen.WIND.av_speedh = 0;
457 		tsen.WIND.av_speedl = 0;
458 		int sw = round(WindSpeed*10.0f);
459 		tsen.WIND.av_speedh = (BYTE)(sw / 256);
460 		sw -= (tsen.WIND.av_speedh * 256);
461 		tsen.WIND.av_speedl = (BYTE)(sw);
462 
463 		tsen.WIND.gusth = 0;
464 		tsen.WIND.gustl = 0;
465 
466 		//this is not correct, why no wind temperature? and only chill?
467 		tsen.WIND.chillh = 0;
468 		tsen.WIND.chilll = 0;
469 		tsen.WIND.temperatureh = 0;
470 		tsen.WIND.temperaturel = 0;
471 		if (bOutsideTemperatureValid)
472 		{
473 			tsen.WIND.tempsign = (OutsideTemperature >= 0) ? 0 : 1;
474 			tsen.WIND.chillsign = (OutsideTemperature >= 0) ? 0 : 1;
475 			int at10 = round(std::abs(OutsideTemperature*10.0f));
476 			tsen.WIND.temperatureh = (BYTE)(at10 / 256);
477 			tsen.WIND.chillh = (BYTE)(at10 / 256);
478 			at10 -= (tsen.WIND.chillh * 256);
479 			tsen.WIND.temperaturel = (BYTE)(at10);
480 			tsen.WIND.chilll = (BYTE)(at10);
481 		}
482 
483 		sDecodeRXMessage(this, (const unsigned char *)&tsen.WIND, NULL, 255);
484 	}
485 
486 	//UV
487 	if (pData[43] != 0xFF)
488 	{
489 		UV = (pData[43]) / 10.0f;
490 		if (UV < 100)
491 			bUVValid = true;
492 	}
493 	if (bUVValid)
494 	{
495 		SendUVSensor(0, 1, 255, UV, "UV");
496 	}
497 
498 	//Rain Rate
499 	if ((pData[41] != 0xFF) && (pData[42] != 0xFF))
500 	{
501 		//float rainRate=((unsigned int)((pData[42] << 8) | pData[41])) / 100.0f; //inches
502 		//rainRate*=25.4f; //mm
503 	}
504 	//Rain Day
505 	if ((pData[50] != 0xFF) && (pData[51] != 0xFF))
506 	{
507 		//float rainDay=((unsigned int)((pData[51] << 8) | pData[50])) / 100.0f; //inches
508 		//rainDay*=25.4f; //mm
509 	}
510 	//Rain Year
511 	if ((pData[54] != 0xFF) && (pData[55] != 0xFF))
512 	{
513 		float rainYear = ((unsigned int)((pData[55] << 8) | pData[54])) / 100.0f; //inches
514 		rainYear *= 25.4f; //mm
515 
516 		SendRainSensor(1, 255, rainYear, "Rain");
517 	}
518 
519 	//Solar Radiation
520 	if ((pData[44] != 0xFF) && (pData[45] != 0x7F))
521 	{
522 		unsigned int solarRadiation = ((unsigned int)((pData[45] << 8) | pData[44]));//Watt/M2
523 		_tGeneralDevice gdevice;
524 		gdevice.subtype = sTypeSolarRadiation;
525 		gdevice.floatval1 = float(solarRadiation);
526 		sDecodeRXMessage(this, (const unsigned char *)&gdevice, NULL, 255);
527 
528 	}
529 
530 	//Soil Moistures
531 	for (int iMoister = 0; iMoister < 4; iMoister++)
532 	{
533 		if (pData[62 + iMoister] != 0xFF)
534 		{
535 			int moister = pData[62 + iMoister];
536 			SendMoistureSensor(1 + iMoister, 255, moister, "Moisture");
537 		}
538 	}
539 
540 	//Leaf Wetness
541 	for (int iLeaf = 0; iLeaf < 4; iLeaf++)
542 	{
543 		if (pData[66 + iLeaf] != 0xFF)
544 		{
545 			int leaf_wetness = pData[66 + iLeaf];
546 
547 			_tGeneralDevice gdevice;
548 			gdevice.subtype = sTypeLeafWetness;
549 			gdevice.intval1 = leaf_wetness;
550 			gdevice.id = (uint8_t)(1 + iLeaf);
551 			sDecodeRXMessage(this, (const unsigned char *)&gdevice, NULL, 255);
552 		}
553 	}
554 
555 	return true;
556 }
557 
558