1 #include "stdafx.h"
2 #include "1Wire.h"
3 #include "hardwaretypes.h"
4 #include "1Wire/1WireByOWFS.h"
5 #include "1Wire/1WireByKernel.h"
6 #ifdef WIN32
7 #include "1Wire/1WireForWindows.h"
8 #endif // WIN32
9 #include "../main/Logger.h"
10 #include "../main/RFXtrx.h"
11 #include "../main/Helper.h"
12 #include "../main/localtime_r.h"
13 #include "../main/mainworker.h"
14 
15 #include <set>
16 #include <cmath>
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 
21 #define round(a) ( int ) ( a + .5 )
22 
C1Wire(const int ID,const int sensorThreadPeriod,const int switchThreadPeriod,const std::string & path)23 C1Wire::C1Wire(const int ID, const int sensorThreadPeriod, const int switchThreadPeriod, const std::string& path) :
24 	m_system(NULL),
25 	m_sensorThreadPeriod(sensorThreadPeriod),
26 	m_switchThreadPeriod(switchThreadPeriod),
27 	m_path(path),
28 	m_bSensorFirstTime(true),
29 	m_bSwitchFirstTime(true)
30 {
31 	m_HwdID = ID;
32 
33 	// Defaults for pre-existing 1wire instances
34 	if (0 == m_sensorThreadPeriod)
35 		m_sensorThreadPeriod = 5 * 60 * 1000;
36 
37 	if (0 == m_switchThreadPeriod)
38 		m_switchThreadPeriod = 100;
39 
40 	DetectSystem();
41 }
42 
~C1Wire()43 C1Wire::~C1Wire()
44 {
45 }
46 
DetectSystem()47 void C1Wire::DetectSystem()
48 {
49 	// Using the both systems at same time results in conflicts,
50 	// see http://owfs.org/index.php?page=w1-project.
51 	if (m_path.length() != 0)
52 	{
53 		m_system = new C1WireByOWFS(m_path);
54 	}
55 	else
56 	{
57 #ifdef WIN32
58 		if (C1WireForWindows::IsAvailable())
59 			m_system = new C1WireForWindows();
60 #else // WIN32
61 		if (C1WireByKernel::IsAvailable())
62 			m_system = new C1WireByKernel();
63 #endif // WIN32
64 	}
65 }
66 
StartHardware()67 bool C1Wire::StartHardware()
68 {
69 	if (!m_system)
70 		return false;
71 
72 	RequestStart();
73 	m_TaskSwitches.RequestStart();
74 
75 	m_system->PrepareDevices();
76 
77 	// Start worker thread
78 	if (m_sensorThreadPeriod != 0) {
79 		m_threadSensors = std::make_shared<std::thread>(&C1Wire::SensorThread, this);
80 		SetThreadName(m_threadSensors->native_handle(), "1WireSensors");
81 	}
82 	if (m_switchThreadPeriod != 0) {
83 		m_threadSwitches = std::make_shared<std::thread>(&C1Wire::SwitchThread, this);
84 		SetThreadName(m_threadSwitches->native_handle(), "1WireSwitches");
85 	}
86 	m_bIsStarted = true;
87 	sOnConnected(this);
88 	StartHeartbeatThread();
89 	return (m_threadSensors != NULL && m_threadSwitches != NULL);
90 }
91 
StopHardware()92 bool C1Wire::StopHardware()
93 {
94 	if (m_threadSensors)
95 	{
96 		RequestStop();
97 		m_threadSensors->join();
98 		m_threadSensors.reset();
99 	}
100 
101 	if (m_threadSwitches)
102 	{
103 		m_TaskSwitches.RequestStop();
104 		m_threadSwitches->join();
105 		m_threadSwitches.reset();
106 	}
107 
108 	m_bIsStarted = false;
109 	if (m_system)
110 	{
111 		delete m_system;
112 		m_system = NULL;
113 	}
114 	StopHeartbeatThread();
115 	return true;
116 }
117 
IsTemperatureValid(_e1WireFamilyType deviceFamily,float temperature)118 bool IsTemperatureValid(_e1WireFamilyType deviceFamily, float temperature)
119 {
120 	if (temperature <= -300 || temperature >= 381)
121 		return false;
122 
123 	// Some devices has a power-on value at 85C and -127C, we have to filter it
124 	switch (deviceFamily)
125 	{
126 	case high_precision_digital_thermometer:
127 	case Econo_Digital_Thermometer:
128 	case programmable_resolution_digital_thermometer:
129 	case Temperature_memory:
130 	case Temperature_IO:
131 		if ((temperature == 85) || (temperature == -127))
132 			return false;
133 	}
134 
135 	return true;
136 }
137 
SensorThread()138 void C1Wire::SensorThread()
139 {
140 	int pollIterations = 1, pollPeriod, afterIterations = 0, i;
141 
142 	BuildSensorList();
143 	m_bSensorFirstTime = true;
144 
145 	if (m_sensors.size() == 0) return;  // quit if no sensors
146 
147 	pollPeriod = m_sensorThreadPeriod / m_sensors.size();
148 
149 	if (pollPeriod > 1000)
150 	{
151 		pollIterations = pollPeriod / 1000;
152 		pollPeriod = 1000;
153 		afterIterations = (m_sensorThreadPeriod / 1000) - (pollIterations*m_sensors.size());
154 	}
155 
156 	// initial small delay
157 	sleep_milliseconds(1000);
158 
159 	while (!IsStopRequested(0))
160 	{
161 		if (m_sensors.size() > 2)
162 		{
163 			m_system->StartSimultaneousTemperatureRead(); // this can take upto 1sec
164 		}
165 
166 		// Parse our devices
167 		std::set<_t1WireDevice>::const_iterator itt;
168 		for (itt = m_sensors.begin(); itt != m_sensors.end() && !IsStopRequested(0); ++itt)
169 		{
170 			const _t1WireDevice& device = *itt;
171 
172 			// Manage families specificities
173 			switch (device.family)
174 			{
175 			case high_precision_digital_thermometer:
176 			case Thermachron:
177 			case Econo_Digital_Thermometer:
178 			case Temperature_memory:
179 			case programmable_resolution_digital_thermometer:
180 			case Temperature_IO:
181 			{
182 				float temperature = m_system->GetTemperature(device);
183 				if (IsTemperatureValid(device.family, temperature))
184 				{
185 					ReportTemperature(device.devid, temperature);
186 				}
187 				break;
188 			}
189 
190 			case Environmental_Monitors:
191 			{
192 				float temperature = m_system->GetTemperature(device);
193 				if (IsTemperatureValid(device.family, temperature))
194 				{
195 					ReportTemperatureHumidity(device.devid, temperature, m_system->GetHumidity(device));
196 				}
197 				ReportPressure(device.devid, m_system->GetPressure(device));
198 				break;
199 			}
200 
201 			case _4k_ram_with_counter:
202 			{
203 				ReportCounter(device.devid, 0, m_system->GetCounter(device, 0));
204 				ReportCounter(device.devid, 1, m_system->GetCounter(device, 1));
205 				break;
206 			}
207 
208 			case quad_ad_converter:
209 			{
210 				ReportVoltage(device.devid, 0, m_system->GetVoltage(device, 0));
211 				ReportVoltage(device.devid, 1, m_system->GetVoltage(device, 1));
212 				ReportVoltage(device.devid, 2, m_system->GetVoltage(device, 2));
213 				ReportVoltage(device.devid, 3, m_system->GetVoltage(device, 3));
214 				break;
215 			}
216 
217 			case smart_battery_monitor:
218 			{
219 				float temperature = m_system->GetTemperature(device);
220 				if (IsTemperatureValid(device.family, temperature))
221 				{
222 					ReportTemperature(device.devid, temperature);
223 				}
224 				ReportHumidity(device.devid, m_system->GetHumidity(device));
225 				ReportVoltage(device.devid, 0, m_system->GetVoltage(device, 0));   // VAD
226 				ReportVoltage(device.devid, 1, m_system->GetVoltage(device, 1));   // VDD
227 				ReportVoltage(device.devid, 2, m_system->GetVoltage(device, 2));   // vis
228 				ReportPressure(device.devid, m_system->GetPressure(device));
229 				// Commonly used as Illuminance sensor, see http://www.hobby-boards.com/store/products/Solar-Radiation-Detector.html
230 				ReportIlluminance(device.devid, m_system->GetIlluminance(device));
231 				break;
232 			}
233 			default: // not a supported sensor
234 				break;
235 			}
236 
237 			if (!IsStopRequested(0) && !m_bSensorFirstTime)
238 				for (i = 0; i < pollIterations; i++)
239 					sleep_milliseconds(pollPeriod);
240 		}
241 		m_bSensorFirstTime = false;
242 		if (!IsStopRequested(0))
243 			for (i = 0; i < afterIterations; i++)
244 				sleep_milliseconds(pollPeriod);
245 	}
246 
247 	_log.Log(LOG_STATUS, "1-Wire: Sensor thread terminating");
248 }
249 
SwitchThread()250 void C1Wire::SwitchThread()
251 {
252 	int pollPeriod = m_switchThreadPeriod;
253 
254 	// Rescan the bus once every 10 seconds if requested
255 #define HARDWARE_RESCAN_PERIOD 10000
256 	int rescanIterations = HARDWARE_RESCAN_PERIOD / pollPeriod;
257 	if (0 == rescanIterations)
258 		rescanIterations = 1;
259 
260 	int iteration = 0;
261 
262 	m_bSwitchFirstTime = true;
263 
264 	while (!m_TaskSwitches.IsStopRequested(pollPeriod))
265 	{
266 		if (0 == iteration++ % rescanIterations) // may glitch on overflow, not disastrous
267 		{
268 			if (m_bSwitchFirstTime)
269 			{
270 				m_bSwitchFirstTime = false;
271 				BuildSwitchList();
272 			}
273 		}
274 
275 		PollSwitches();
276 	}
277 
278 	_log.Log(LOG_STATUS, "1-Wire: Switch thread terminating");
279 }
280 
281 
WriteToHardware(const char * pdata,const unsigned char)282 bool C1Wire::WriteToHardware(const char *pdata, const unsigned char /*length*/)
283 {
284 	const tRBUF *pSen = reinterpret_cast<const tRBUF*>(pdata);
285 
286 	if (!m_system)
287 		return false;//no 1-wire support
288 
289 	if (pSen->ICMND.packettype == pTypeLighting2 && pSen->LIGHTING2.subtype == sTypeAC)
290 	{
291 		//light command
292 		unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
293 		deviceIdByteArray[0] = pSen->LIGHTING2.id1;
294 		deviceIdByteArray[1] = pSen->LIGHTING2.id2;
295 		deviceIdByteArray[2] = pSen->LIGHTING2.id3;
296 		deviceIdByteArray[3] = pSen->LIGHTING2.id4;
297 
298 		m_system->SetLightState(ByteArrayToDeviceId(deviceIdByteArray), pSen->LIGHTING2.unitcode, pSen->LIGHTING2.cmnd == light2_sOn, pSen->LIGHTING2.level);
299 		return true;
300 	}
301 	return false;
302 }
303 
BuildSensorList()304 void C1Wire::BuildSensorList() {
305 	if (!m_system)
306 		return;
307 
308 	std::vector<_t1WireDevice> devices;
309 
310 	_log.Debug(DEBUG_HARDWARE, "1-Wire: Searching sensors");
311 
312 	m_sensors.clear();
313 	m_system->GetDevices(devices);
314 
315 	for (const auto & device : devices)
316 	{
317 		switch (device.family)
318 		{
319 		case high_precision_digital_thermometer:
320 		case Thermachron:
321 		case Econo_Digital_Thermometer:
322 		case Temperature_memory:
323 		case programmable_resolution_digital_thermometer:
324 		case Temperature_IO:
325 		case Environmental_Monitors:
326 		case _4k_ram_with_counter:
327 		case quad_ad_converter:
328 		case smart_battery_monitor:
329 			m_sensors.insert(device);
330 			break;
331 		default:
332 			break;
333 		}
334 
335 	}
336 	devices.clear();
337 }
338 
BuildSwitchList()339 void C1Wire::BuildSwitchList() {
340 	if (!m_system)
341 		return;
342 
343 	std::vector<_t1WireDevice> devices;
344 
345 	_log.Debug(DEBUG_HARDWARE, "1-Wire: Searching switches");
346 
347 	m_switches.clear();
348 	m_system->GetDevices(devices);
349 
350 	for (const auto & device : devices)
351 	{
352 		switch (device.family)
353 		{
354 		case Addresable_Switch:
355 		case microlan_coupler:
356 		case dual_addressable_switch_plus_1k_memory:
357 		case _8_channel_addressable_switch:
358 		case Temperature_IO:
359 		case dual_channel_addressable_switch:
360 		case _4k_EEPROM_with_PIO:
361 		case digital_potentiometer:
362 			m_switches.insert(device);
363 			break;
364 		default:
365 			break;
366 		}
367 
368 	}
369 	devices.clear();
370 }
371 
372 
PollSwitches()373 void C1Wire::PollSwitches()
374 {
375 	if (!m_system)
376 		return;
377 
378 	// Parse our devices (have to test if m_TaskSwitches.IsStopRequested because it can take some time in case of big networks)
379 	for (const auto & itt : m_switches)
380 	{
381 		const _t1WireDevice& device = itt;
382 
383 		// Manage families specificities
384 		switch (device.family)
385 		{
386 		case Addresable_Switch:
387 		case microlan_coupler:
388 		{
389 			ReportLightState(device.devid, 0, m_system->GetLightState(device, 0));
390 			break;
391 		}
392 
393 		case dual_addressable_switch_plus_1k_memory:
394 		{
395 			ReportLightState(device.devid, 0, m_system->GetLightState(device, 0));
396 			if (m_system->GetNbChannels(device) == 2)
397 				ReportLightState(device.devid, 1, m_system->GetLightState(device, 1));
398 			break;
399 		}
400 
401 		case _8_channel_addressable_switch:
402 		{
403 			ReportLightState(device.devid, 0, m_system->GetLightState(device, 0));
404 			ReportLightState(device.devid, 1, m_system->GetLightState(device, 1));
405 			ReportLightState(device.devid, 2, m_system->GetLightState(device, 2));
406 			ReportLightState(device.devid, 3, m_system->GetLightState(device, 3));
407 			ReportLightState(device.devid, 4, m_system->GetLightState(device, 4));
408 			ReportLightState(device.devid, 5, m_system->GetLightState(device, 5));
409 			ReportLightState(device.devid, 6, m_system->GetLightState(device, 6));
410 			ReportLightState(device.devid, 7, m_system->GetLightState(device, 7));
411 			break;
412 		}
413 
414 		case Temperature_IO:
415 		{
416 			ReportLightState(device.devid, 0, m_system->GetLightState(device, 0));
417 			ReportLightState(device.devid, 1, m_system->GetLightState(device, 1));
418 			break;
419 		}
420 
421 		case dual_channel_addressable_switch:
422 		case _4k_EEPROM_with_PIO:
423 		{
424 			ReportLightState(device.devid, 0, m_system->GetLightState(device, 0));
425 			ReportLightState(device.devid, 1, m_system->GetLightState(device, 1));
426 			break;
427 		}
428 
429 		case digital_potentiometer:
430 		{
431 			int wiper = m_system->GetWiper(device);
432 			ReportWiper(device.devid, wiper);
433 			break;
434 		}
435 
436 		default: // Not a supported switch
437 			break;
438 		}
439 	}
440 }
441 
ReportWiper(const std::string & deviceId,const int wiper)442 void C1Wire::ReportWiper(const std::string& deviceId, const int wiper)
443 {
444 	if (wiper < 0)
445 		return;
446 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
447 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
448 
449 	int NodeID = (deviceIdByteArray[0] << 24) | (deviceIdByteArray[1] << 16) | (deviceIdByteArray[2] << 8) | (deviceIdByteArray[3]);
450 	unsigned int value = static_cast<int>(wiper * (100.0 / 255.0));
451 	SendSwitch(NodeID, 0, 255, wiper > 0, value, "Wiper");
452 }
453 
ReportTemperature(const std::string & deviceId,const float temperature)454 void C1Wire::ReportTemperature(const std::string& deviceId, const float temperature)
455 {
456 	if (temperature == -1000.0)
457 		return;
458 
459 
460 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
461 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
462 	uint16_t lID = (deviceIdByteArray[0] << 8) | deviceIdByteArray[1];
463 
464 	SendTempSensor(lID, 255, temperature, "Temperature");
465 }
466 
ReportHumidity(const std::string & deviceId,const float humidity)467 void C1Wire::ReportHumidity(const std::string& deviceId, const float humidity)
468 {
469 	if (humidity == -1000.0)
470 		return;
471 
472 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
473 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
474 	uint16_t lID = (deviceIdByteArray[0] << 8) | deviceIdByteArray[1];
475 
476 	SendHumiditySensor(lID, 255, round(humidity), "Humidity");
477 
478 }
479 
ReportPressure(const std::string & deviceId,const float pressure)480 void C1Wire::ReportPressure(const std::string& deviceId, const float pressure)
481 {
482 	if (pressure == -1000.0)
483 		return;
484 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
485 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
486 
487 	int lID = (deviceIdByteArray[0] << 24) + (deviceIdByteArray[1] << 16) + (deviceIdByteArray[2] << 8) + deviceIdByteArray[3];
488 	SendPressureSensor(0, lID, 255, pressure, "Pressure");
489 }
490 
ReportTemperatureHumidity(const std::string & deviceId,const float temperature,const float humidity)491 void C1Wire::ReportTemperatureHumidity(const std::string& deviceId, const float temperature, const float humidity)
492 {
493 	if ((temperature == -1000.0) || (humidity == -1000.0))
494 		return;
495 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
496 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
497 
498 	uint16_t lID = (deviceIdByteArray[0] << 8) | deviceIdByteArray[1];
499 	SendTempHumSensor(lID, 255, temperature, round(humidity), "TempHum");
500 }
501 
ReportLightState(const std::string & deviceId,const uint8_t unit,const bool state)502 void C1Wire::ReportLightState(const std::string& deviceId, const uint8_t unit, const bool state)
503 {
504 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
505 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
506 	int lID = (deviceIdByteArray[0] << 24) + (deviceIdByteArray[1] << 16) + (deviceIdByteArray[2] << 8) + deviceIdByteArray[3];
507 
508 	SendSwitch(lID, unit, 255, state, 0, "Switch");
509 }
510 
ReportCounter(const std::string & deviceId,const int unit,const unsigned long counter)511 void C1Wire::ReportCounter(const std::string& deviceId, const int unit, const unsigned long counter)
512 {
513 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
514 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
515 
516 	SendMeterSensor(deviceIdByteArray[0], deviceIdByteArray[1] + unit, 255, (const float)counter / 1000.0f, "Counter");
517 }
518 
ReportVoltage(const std::string &,const int unit,const int voltage)519 void C1Wire::ReportVoltage(const std::string& /*deviceId*/, const int unit, const int voltage)
520 {
521 	if (voltage == -1000.0)
522 		return;
523 
524 	// There is no matching SendXXX() function for this?
525 	RBUF tsen;
526 	memset(&tsen, 0, sizeof(RBUF));
527 	tsen.RFXSENSOR.packetlength = sizeof(tsen.RFXSENSOR) - 1;
528 	tsen.RFXSENSOR.packettype = pTypeRFXSensor;
529 	tsen.RFXSENSOR.subtype = sTypeRFXSensorVolt;
530 	tsen.RFXSENSOR.rssi = 12;
531 	tsen.RFXSENSOR.id = (uint8_t)(unit + 1);
532 
533 	tsen.RFXSENSOR.msg1 = (BYTE)(voltage / 256);
534 	tsen.RFXSENSOR.msg2 = (BYTE)(voltage - (tsen.RFXSENSOR.msg1 * 256));
535 	sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXSENSOR, NULL, 255);
536 }
537 
ReportIlluminance(const std::string & deviceId,const float illuminescence)538 void C1Wire::ReportIlluminance(const std::string& deviceId, const float illuminescence)
539 {
540 	if (illuminescence == -1000.0)
541 		return;
542 
543 	unsigned char deviceIdByteArray[DEVICE_ID_SIZE] = { 0 };
544 	DeviceIdToByteArray(deviceId, deviceIdByteArray);
545 
546 	uint8_t NodeID = deviceIdByteArray[0] ^ deviceIdByteArray[1];
547 	SendSolarRadiationSensor(NodeID, 255, illuminescence, "Solar Radiation");
548 }
549