1 #include "stdafx.h"
2 #include "RFXComSerial.h"
3 #include "../main/Logger.h"
4 #include "../main/Helper.h"
5 #include "../main/mainworker.h"
6 #include "../main/localtime_r.h"
7 #include "../main/SQLHelper.h"
8 #include "../main/WebServer.h"
9 #include "../webserver/cWebem.h"
10 #include <json/json.h>
11
12 #include <string>
13 #include <algorithm>
14 #include <iostream>
15 #include <boost/bind.hpp>
16
17 #include <ctime>
18
19 #ifndef WIN32
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <pwd.h>
24 #endif
25
26 #define RETRY_DELAY 30
27
28 #define RFX_WRITE_DELAY 300
29
30 extern std::string szStartupFolder;
31
32 #define round(a) ( int ) ( a + .5 )
33
34 const unsigned char PKT_STX = 0x55;
35 const unsigned char PKT_ETX = 0x04;
36 const unsigned char PKT_DLE = 0x05;
37
38 #define PKT_writeblock 256
39 #define PKT_readblock 4
40 #define PKT_eraseblock 2048
41 #define PKT_maxpacket 261
42 #define PKT_bytesperaddr 2
43
44 #define PKT_pmrangelow 0x001800
45 #define PKT_pmrangehigh 0x00A7FF
46
47 #define PKT_pmrangelow868 0x001000
48 #define PKT_pmrangehigh868 0x0147FF
49
50 #define PKT_userresetvector 0x100
51 #define PKT_bootdelay 0x102
52
53 #define COMMAND_WRITEPM 2
54 #define COMMAND_ERASEPM 3
55
56 const unsigned char PKT_STARTBOOT[5] = { 0x01, 0x01, 0x00, 0x00, 0xFF };
57 const unsigned char PKT_RESET[2] = { 0x00, 0x00 };
58 const unsigned char PKT_VERSION[2] = { 0x00, 0x02 };
59 const unsigned char PKT_VERIFY_OK[5] = { 0x08, 0x01, 0x00, 0x00, 0x00 };
60
61 //
62 //Class RFXComSerial
63 //
RFXComSerial(const int ID,const std::string & devname,unsigned int baud_rate,const _eRFXAsyncType AsyncType)64 RFXComSerial::RFXComSerial(const int ID, const std::string& devname, unsigned int baud_rate, const _eRFXAsyncType AsyncType) :
65 m_szSerialPort(devname)
66 {
67 m_HwdID = ID;
68 m_iBaudRate = baud_rate;
69
70 m_AsyncType = AsyncType;
71
72 m_bReceiverStarted = false;
73 m_bInBootloaderMode = false;
74 m_bStartFirmwareUpload = false;
75 m_FirmwareUploadPercentage = 0;
76 m_bHaveRX = false;
77 m_rx_tot_bytes = 0;
78 m_retrycntr = RETRY_DELAY;
79
80 m_serial.setPort(m_szSerialPort);
81 m_serial.setBaudrate(m_iBaudRate);
82 m_serial.setBytesize(serial::eightbits);
83 m_serial.setParity(serial::parity_none);
84 m_serial.setStopbits(serial::stopbits_one);
85 m_serial.setFlowcontrol(serial::flowcontrol_none);
86
87 serial::Timeout stimeout = serial::Timeout::simpleTimeout(200);
88 m_serial.setTimeout(stimeout);
89 }
90
~RFXComSerial()91 RFXComSerial::~RFXComSerial()
92 {
93
94 }
95
StartHardware()96 bool RFXComSerial::StartHardware()
97 {
98 RequestStart();
99
100 //return OpenSerialDevice();
101 //somehow retry does not seem to work?!
102 m_bReceiverStarted = false;
103
104 m_retrycntr = RETRY_DELAY; //will force reconnect first thing
105
106 //Start worker thread
107 m_thread = std::make_shared<std::thread>(&RFXComSerial::Do_Work, this);
108 SetThreadNameInt(m_thread->native_handle());
109
110 return (m_thread != nullptr);
111
112 }
113
StopHardware()114 bool RFXComSerial::StopHardware()
115 {
116 if (m_thread)
117 {
118 RequestStop();
119 m_thread->join();
120 m_thread.reset();
121 }
122 m_bIsStarted = false;
123 return true;
124 }
125
Do_Work()126 void RFXComSerial::Do_Work()
127 {
128 int sec_counter = 0;
129
130 Log(LOG_STATUS, "Worker started...");
131
132 while (IsStopRequested(1000) == false)
133 {
134 sec_counter++;
135
136 if (sec_counter % 12 == 0) {
137 m_LastHeartbeat = mytime(NULL);
138 }
139
140 if (m_bStartFirmwareUpload)
141 {
142 m_bStartFirmwareUpload = false;
143 terminate();
144 try {
145 sleep_seconds(1);
146 UpgradeFirmware();
147 }
148 catch (...)
149 {
150 }
151 }
152
153 if (!isOpen())
154 {
155 if (m_retrycntr == 0)
156 {
157 Log(LOG_STATUS, "retrying in %d seconds...", RETRY_DELAY);
158 }
159 m_retrycntr++;
160 if (m_retrycntr >= RETRY_DELAY)
161 {
162 m_retrycntr = 0;
163 OpenSerialDevice();
164 }
165 }
166 }
167 terminate(); //Close serial port (if open)
168
169 Log(LOG_STATUS, "Worker stopped...");
170 }
171
172
OpenSerialDevice(const bool bIsFirmwareUpgrade)173 bool RFXComSerial::OpenSerialDevice(const bool bIsFirmwareUpgrade)
174 {
175 //Try to open the Serial Port
176 try
177 {
178 open(m_szSerialPort, m_iBaudRate);
179 Log(LOG_STATUS, "Using serial port: %s", m_szSerialPort.c_str());
180 }
181 catch (boost::exception & e)
182 {
183 Log(LOG_ERROR, "Error opening serial port!");
184 #ifdef _DEBUG
185 Log(LOG_ERROR, "-----------------\n%s\n----------------", boost::diagnostic_information(e).c_str());
186 #else
187 (void)e;
188 #endif
189 return false;
190 }
191 catch (...)
192 {
193 Log(LOG_ERROR, "Error opening serial port!!!");
194 return false;
195 }
196 m_bIsStarted = true;
197 m_rxbufferpos = 0;
198 setReadCallback(boost::bind(&RFXComSerial::readCallback, this, _1, _2));
199 if (!bIsFirmwareUpgrade)
200 sOnConnected(this);
201 return true;
202 }
203
UploadFirmware(const std::string & szFilename)204 bool RFXComSerial::UploadFirmware(const std::string &szFilename)
205 {
206 m_szFirmwareFile = szFilename;
207 m_FirmwareUploadPercentage = 0;
208 m_bStartFirmwareUpload = true;
209 try {
210 clearReadCallback();
211 }
212 catch (...)
213 {
214 //Don't throw from a Stop command
215 }
216 return true;
217 }
218
UpgradeFirmware()219 bool RFXComSerial::UpgradeFirmware()
220 {
221 int AddressLow = PKT_pmrangelow;
222 int AddressHigh = PKT_pmrangehigh;
223 if (HwdType == HTYPE_RFXtrx868)
224 {
225 AddressLow = PKT_pmrangelow868;
226 AddressHigh = PKT_pmrangehigh868;
227 }
228 m_FirmwareUploadPercentage = 0;
229 m_bStartFirmwareUpload = false;
230 std::map<unsigned long, std::string> firmwareBuffer;
231 int icntr = 0;
232 if (!Read_Firmware_File(m_szFirmwareFile.c_str(), firmwareBuffer))
233 {
234 m_FirmwareUploadPercentage = -1;
235 goto exitfirmwareupload;
236 }
237
238 try
239 {
240 m_serial.open();
241 }
242 catch (...)
243 {
244 m_szUploadMessage = "Error opening serial port!!!";
245 Log(LOG_ERROR, m_szUploadMessage);
246 m_FirmwareUploadPercentage = -1;
247 goto exitfirmwareupload;
248 }
249 //Start bootloader mode
250 m_szUploadMessage = "Start bootloader process...";
251 Log(LOG_STATUS, m_szUploadMessage);
252 Write_TX_PKT(PKT_STARTBOOT, sizeof(PKT_STARTBOOT), 1);
253 Write_TX_PKT(PKT_STARTBOOT, sizeof(PKT_STARTBOOT), 1);
254 m_szUploadMessage = "Get bootloader version...";
255 Log(LOG_STATUS, m_szUploadMessage);
256 //read bootloader version
257 if (!Write_TX_PKT(PKT_VERSION, sizeof(PKT_VERSION)))
258 {
259 m_szUploadMessage = "Error getting bootloader version!!!";
260 Log(LOG_ERROR, m_szUploadMessage);
261 m_FirmwareUploadPercentage = -1;
262 goto exitfirmwareupload;
263 }
264 Log(LOG_STATUS, "bootloader version v%d.%d", m_rx_input_buffer[3], m_rx_input_buffer[2]);
265
266 if (!EraseMemory(AddressLow, AddressHigh))
267 {
268 m_FirmwareUploadPercentage = -1;
269 goto exitfirmwareupload;
270 }
271
272 #ifndef WIN32
273 try
274 {
275 m_serial.flush();
276 }
277 catch (...)
278 {
279 m_szUploadMessage = "Bootloader, unable to flush serial device!!!";
280 Log(LOG_ERROR, m_szUploadMessage);
281 m_FirmwareUploadPercentage = -1;
282 goto exitfirmwareupload;
283 }
284 #endif
285 try
286 {
287 m_serial.close();
288 }
289 catch (...)
290 {
291 }
292 sleep_seconds(1);
293
294 try
295 {
296 m_serial.open();
297 }
298 catch (...)
299 {
300 m_szUploadMessage = "Error opening serial port!!!";
301 Log(LOG_ERROR, m_szUploadMessage);
302 m_FirmwareUploadPercentage = -1;
303 goto exitfirmwareupload;
304 }
305
306 m_szUploadMessage = "Start bootloader version...";
307 Log(LOG_STATUS, m_szUploadMessage);
308 Write_TX_PKT(PKT_STARTBOOT, sizeof(PKT_STARTBOOT), 1);
309 Write_TX_PKT(PKT_STARTBOOT, sizeof(PKT_STARTBOOT), 1);
310
311 m_szUploadMessage = "Bootloader, Start programming...";
312 Log(LOG_STATUS, m_szUploadMessage);
313 for (auto itt : firmwareBuffer)
314 {
315 icntr++;
316 if (icntr % 5 == 0)
317 {
318 m_LastHeartbeat = mytime(NULL);
319 }
320 unsigned long Address = itt.first;
321 m_FirmwareUploadPercentage = (100.0f / float(firmwareBuffer.size()))*icntr;
322 if (m_FirmwareUploadPercentage > 100)
323 m_FirmwareUploadPercentage = 100;
324
325 //if ((Address >= AddressLow) && (Address <= AddressHigh))
326 {
327 std::stringstream saddress;
328 saddress << "Programming Address: 0x" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << Address;
329
330 std::stringstream spercentage;
331 spercentage.precision(2);
332 spercentage << std::setprecision(2) << std::fixed << m_FirmwareUploadPercentage;
333 m_szUploadMessage = saddress.str() + ", " + spercentage.str() + " %";
334 _log.Log(LOG_STATUS, m_szUploadMessage);
335
336 unsigned char bcmd[PKT_writeblock + 10];
337 bcmd[0] = COMMAND_WRITEPM;
338 bcmd[1] = 1;
339 bcmd[2] = Address & 0xFF;
340 bcmd[3] = (Address & 0xFF00) >> 8;
341 bcmd[4] = (unsigned char)((Address & 0xFF0000) >> 16);
342 memcpy(bcmd + 5, itt.second.c_str(), itt.second.size());
343 bool ret = Write_TX_PKT(bcmd, 5 + itt.second.size(), 20);
344 if (!ret)
345 {
346 m_szUploadMessage = "Bootloader, unable to program firmware memory, please try again!!!";
347 Log(LOG_ERROR, m_szUploadMessage);
348 m_FirmwareUploadPercentage = -1;
349 goto exitfirmwareupload;
350 }
351 }
352 }
353 firmwareBuffer.clear();
354 #ifndef WIN32
355 try
356 {
357 m_serial.flush();
358 }
359 catch (...)
360 {
361 m_szUploadMessage = "Bootloader, unable to flush serial device!!!";
362 Log(LOG_ERROR, m_szUploadMessage);
363 m_FirmwareUploadPercentage = -1;
364 goto exitfirmwareupload;
365 }
366 #endif
367 //Verify
368 m_szUploadMessage = "Start bootloader verify...";
369 Log(LOG_STATUS, m_szUploadMessage);
370 if (!Write_TX_PKT(PKT_VERIFY_OK, sizeof(PKT_VERIFY_OK)))
371 {
372 m_szUploadMessage = "Bootloader, program firmware memory not succeeded, please try again!!!";
373 Log(LOG_ERROR, m_szUploadMessage);
374 m_FirmwareUploadPercentage = -1;
375 goto exitfirmwareupload;
376 }
377 if (m_rx_input_buffer[0] != PKT_VERIFY_OK[0])
378 {
379 m_FirmwareUploadPercentage = -1;
380 m_szUploadMessage = "Bootloader, program firmware memory not succeeded, please try again!!!";
381 Log(LOG_ERROR, m_szUploadMessage);
382 }
383 else
384 {
385 m_szUploadMessage = "Bootloader, Programming completed successfully...";
386 Log(LOG_STATUS, m_szUploadMessage);
387 }
388 exitfirmwareupload:
389 m_szUploadMessage = "bootloader reset...";
390 Log(LOG_STATUS, m_szUploadMessage);
391 Write_TX_PKT(PKT_RESET, sizeof(PKT_RESET), 1);
392 #ifndef WIN32
393 try
394 {
395 m_serial.flush();
396 }
397 catch (...)
398 {
399 m_szUploadMessage = "Bootloader, unable to flush serial device!!!";
400 Log(LOG_ERROR, m_szUploadMessage);
401 m_FirmwareUploadPercentage = -1;
402 goto exitfirmwareupload;
403 }
404 #endif
405 sleep_seconds(1);
406 try
407 {
408 if (m_serial.isOpen())
409 {
410 m_serial.close();
411 }
412 }
413 catch (...)
414 {
415 }
416
417 m_rxbufferpos = 0;
418 m_bInBootloaderMode = false;
419 m_FirmwareUploadPercentage = 100;
420 RequestStart();
421 OpenSerialDevice();
422 return true;
423 }
424
425 //returns -1 when failed
GetUploadPercentage()426 float RFXComSerial::GetUploadPercentage()
427 {
428 return m_FirmwareUploadPercentage;
429 }
430
GetUploadMessage()431 std::string RFXComSerial::GetUploadMessage()
432 {
433 return m_szUploadMessage;
434 }
435
Read_Firmware_File(const char * szFilename,std::map<unsigned long,std::string> & fileBuffer)436 bool RFXComSerial::Read_Firmware_File(const char *szFilename, std::map<unsigned long, std::string>& fileBuffer)
437 {
438 #ifndef WIN32
439 struct stat info;
440 if (stat(szFilename, &info) == 0)
441 {
442 struct passwd *pw = getpwuid(info.st_uid);
443 int ret = chown(szFilename, pw->pw_uid, pw->pw_gid);
444 if (ret != 0)
445 {
446 m_szUploadMessage = "Error setting firmware ownership (chown returned an error!)";
447 Log(LOG_ERROR, m_szUploadMessage);
448 return false;
449 }
450 }
451 #endif
452
453 std::ifstream infile;
454 std::string sLine;
455 infile.open(szFilename);
456 if (!infile.is_open())
457 {
458 m_szUploadMessage = "bootloader, unable to open file: " + std::string(szFilename);
459 Log(LOG_ERROR, m_szUploadMessage);
460 return false;
461 }
462
463 m_szUploadMessage = "start reading Firmware...";
464 Log(LOG_STATUS, m_szUploadMessage);
465
466 unsigned char rawLineBuf[PKT_writeblock];
467 int raw_length = 0;
468 unsigned long dest_address = 0;
469 int line = 0;
470 int addrh = 0;
471
472 fileBuffer.clear();
473 std::string dstring = "";
474 bool bHaveEOF = false;
475
476 while (!infile.eof())
477 {
478 getline(infile, sLine);
479 if (sLine.empty())
480 continue;
481 //Every line should start with ':'
482 if (sLine[0] != ':')
483 {
484 infile.close();
485 m_szUploadMessage = "bootloader, firmware does not start with ':'";
486 Log(LOG_ERROR, m_szUploadMessage);
487 return false;
488 }
489 sLine = sLine.substr(1);
490 if (sLine.size() > 1)
491 {
492 if (sLine[sLine.size() - 1] == '\n')
493 {
494 sLine = sLine.substr(0, sLine.size() - 1);
495 }
496 if (sLine[sLine.size() - 1] == '\r')
497 {
498 sLine = sLine.substr(0, sLine.size() - 1);
499 }
500 }
501 if (sLine.size() % 2 != 0)
502 {
503 infile.close();
504 m_szUploadMessage = "bootloader, firmware line not equals 2 digests";
505 Log(LOG_ERROR, m_szUploadMessage);
506 return false;
507 }
508 raw_length = 0;
509 unsigned char chksum = 0;
510 while (!sLine.empty())
511 {
512 std::string szHex = sLine.substr(0, 2); sLine = sLine.substr(2);
513 std::stringstream sstr;
514 int iByte = 0;
515 sstr << std::hex << szHex;
516 sstr >> iByte;
517 rawLineBuf[raw_length++] = (unsigned char)iByte;
518 if (!sLine.empty())
519 chksum += iByte;
520 if (raw_length > sizeof(rawLineBuf) - 1)
521 {
522 infile.close();
523 m_szUploadMessage = "bootloader, incorrect length";
524 Log(LOG_ERROR, m_szUploadMessage);
525 return false;
526 }
527
528 }
529 //
530 chksum = ~chksum + 1;
531 if ((chksum != rawLineBuf[raw_length - 1]) || (raw_length < 4))
532 {
533 infile.close();
534 m_szUploadMessage = "bootloader, checksum mismatch!";
535 Log(LOG_ERROR, m_szUploadMessage);
536 return false;
537 }
538 int byte_count = rawLineBuf[0];
539 int faddress = (rawLineBuf[1] << 8) | rawLineBuf[2];
540 int rtype = rawLineBuf[3];
541
542 switch (rtype)
543 {
544 case 0:
545 //Data record
546 dstring += std::string((const char*)&rawLineBuf + 4, (const char*)rawLineBuf + 4 + byte_count);
547 if (dstring.size() == PKT_writeblock)
548 {
549 dest_address = (((((addrh << 16) | (faddress + byte_count)) - PKT_writeblock)) / PKT_bytesperaddr);
550 fileBuffer[dest_address] = dstring;
551 dstring.clear();
552 }
553 break;
554 case 1:
555 //EOF Record
556 bHaveEOF = dstring.empty();
557 if (!bHaveEOF)
558 {
559 m_szUploadMessage = "Bootloader invalid size!";
560 Log(LOG_ERROR, m_szUploadMessage);
561 }
562 break;
563 case 2:
564 //Extended Segment Address Record
565 m_szUploadMessage = "Bootloader type 2 not supported!";
566 Log(LOG_ERROR, m_szUploadMessage);
567 infile.close();
568 return false;
569 case 3:
570 //Start Segment Address Record
571 m_szUploadMessage = "Bootloader type 3 not supported!";
572 Log(LOG_ERROR, m_szUploadMessage);
573 infile.close();
574 return false;
575 case 4:
576 //Extended Linear Address Record
577 if (raw_length < 7)
578 {
579 m_szUploadMessage = "Invalid line length!!";
580 Log(LOG_ERROR, m_szUploadMessage);
581 infile.close();
582 return false;
583 }
584 addrh = (rawLineBuf[4] << 8) | rawLineBuf[5];
585 break;
586 case 5:
587 //Start Linear Address Record
588 m_szUploadMessage = "Bootloader type 5 not supported!";
589 Log(LOG_ERROR, m_szUploadMessage);
590 infile.close();
591 return false;
592 }
593 line++;
594 }
595 infile.close();
596 if (!bHaveEOF)
597 {
598 m_szUploadMessage = "No end-of-line found!!";
599 Log(LOG_ERROR, m_szUploadMessage);
600 return false;
601 }
602 m_szUploadMessage = "Firmware read correctly...";
603 Log(LOG_STATUS, m_szUploadMessage);
604 return true;
605 }
606
EraseMemory(const int StartAddress,const int StopAddress)607 bool RFXComSerial::EraseMemory(const int StartAddress, const int StopAddress)
608 {
609 m_szUploadMessage = "Erasing memory....";
610 Log(LOG_STATUS, m_szUploadMessage);
611 int BootAddr = StartAddress;
612
613 while (BootAddr < StopAddress)
614 {
615 int nBlocks = ((StopAddress - StartAddress + 1) * PKT_bytesperaddr) / PKT_eraseblock;
616 nBlocks = (StopAddress - StartAddress + 1) / (PKT_eraseblock / PKT_bytesperaddr);
617 if (nBlocks > 255)
618 nBlocks = 255;
619
620 unsigned char bcmd[5];
621 bcmd[0] = COMMAND_ERASEPM;
622 bcmd[1] = nBlocks;
623 bcmd[2] = BootAddr & 0xFF;
624 bcmd[3] = (BootAddr & 0xFF00) >> 8;
625 bcmd[4] = (BootAddr & 0xFF0000) >> 16;
626
627 if (!Write_TX_PKT(bcmd, sizeof(bcmd), 5))
628 {
629 m_szUploadMessage = "Error erasing memory!";
630 Log(LOG_ERROR, m_szUploadMessage);
631 return false;
632 }
633 BootAddr += (PKT_eraseblock * nBlocks);
634 }
635 m_szUploadMessage = "Erasing memory completed....";
636 Log(LOG_STATUS, m_szUploadMessage);
637 return true;
638 }
639
Write_TX_PKT(const unsigned char * pdata,size_t length,int max_retry)640 bool RFXComSerial::Write_TX_PKT(const unsigned char *pdata, size_t length, int max_retry)
641 {
642 if (!m_serial.isOpen())
643 return false;
644
645 unsigned char output_buffer[512];
646 int tot_bytes = 0;
647
648 output_buffer[tot_bytes++] = PKT_STX;
649 output_buffer[tot_bytes++] = PKT_STX;
650
651 // Generate the checksum
652 unsigned char chksum = 0;
653 for (size_t ii = 0; ii < length; ii++)
654 {
655 unsigned char dbyte = pdata[ii];
656 chksum += dbyte;
657
658 //if control character, stuff DLE
659 if (dbyte == PKT_STX || dbyte == PKT_ETX || dbyte == PKT_DLE)
660 {
661 output_buffer[tot_bytes++] = PKT_DLE;
662 }
663 output_buffer[tot_bytes++] = dbyte;
664 }
665 chksum = ~chksum + 1;
666 if (chksum == PKT_STX || chksum == PKT_ETX || chksum == PKT_DLE)
667 {
668 output_buffer[tot_bytes++] = PKT_DLE;
669 }
670 output_buffer[tot_bytes++] = chksum;
671 output_buffer[tot_bytes++] = PKT_ETX;
672
673 m_bInBootloaderMode = true;
674 /*
675 if (!WaitForResponse)
676 {
677 write((const char*)&output_buffer, tot_bytes);
678 sleep_milliseconds(500);
679 return true;
680 }
681 */
682 while (max_retry > 0)
683 {
684 try
685 {
686 size_t twrite = m_serial.write((const uint8_t *)&output_buffer, tot_bytes);
687 sleep_milliseconds(RFX_WRITE_DELAY);
688 if (twrite == tot_bytes)
689 {
690 int rcount = 0;
691 while (rcount < 2)
692 {
693 if (Read_TX_PKT())
694 return true;
695 sleep_milliseconds(500);
696 rcount++;
697 }
698 }
699 max_retry--;
700 }
701 catch (...)
702 {
703 return false;
704 }
705 }
706 return m_bHaveRX;
707 }
708
709 //Reads data from serial port between STX/ETX
Read_TX_PKT()710 bool RFXComSerial::Read_TX_PKT()
711 {
712 uint8_t sbuffer[512];
713 size_t buffer_offset = 0;
714 bool bSTXFound1 = false;
715 bool bSTXFound2 = false;
716 bool bETXFound = false;
717 bool bHadDLE = false;
718 unsigned char chksum = 0;
719 m_rx_tot_bytes = 0;
720 while (m_rx_tot_bytes < sizeof(m_rx_input_buffer))
721 {
722 size_t tot_read = m_serial.read((uint8_t*)&sbuffer, sizeof(sbuffer));
723 if (tot_read <= 0)
724 return false;
725 int ii = 0;
726 while (tot_read > 0)
727 {
728 uint8_t tByte = sbuffer[ii++];
729 if (!bSTXFound1)
730 {
731 if (tByte != PKT_STX)
732 return false;
733 bSTXFound1 = true;
734 }
735 else if (!bSTXFound2)
736 {
737 if (tByte != PKT_STX)
738 return false;
739 bSTXFound2 = true;
740 chksum = 0;
741 bHadDLE = false;
742 m_rx_tot_bytes = 0;
743 }
744 else
745 {
746 //Read data until ETX is found
747 if ((tByte == PKT_ETX) && (!bHadDLE))
748 {
749 chksum = ~chksum + 1; //test checksum
750 if (chksum != 0)
751 {
752 Log(LOG_ERROR, "bootloader, received response with invalid checksum!");
753 return false;
754 }
755 m_bHaveRX = true;
756 return true;
757 }
758 else if (tByte == PKT_DLE)
759 {
760 bHadDLE = true;
761 }
762 else
763 {
764 bHadDLE = false;
765 chksum += tByte;
766 m_rx_input_buffer[m_rx_tot_bytes++] = tByte;
767 }
768 }
769 tot_read--;
770 }
771 }
772 return ((buffer_offset > 0) && (bETXFound));
773 }
774
Handle_RX_PKT(const unsigned char * pdata,size_t length)775 bool RFXComSerial::Handle_RX_PKT(const unsigned char *pdata, size_t length)
776 {
777 if (length < 2)
778 return false;
779 if ((pdata[0] != PKT_STX) || (pdata[1] != PKT_STX))
780 return false;
781
782 unsigned char chksum = 0;
783 m_rx_tot_bytes = 0;
784 size_t ii = 1;
785 // std::string szRespone = "Received: ";
786 // int jj;
787 while ((ii < length) && (m_rx_tot_bytes < sizeof(m_rx_input_buffer) - 1))
788 {
789 unsigned char dbyte = pdata[ii];
790 switch (dbyte)
791 {
792 case PKT_STX:
793 m_rx_tot_bytes = 0;
794 chksum = 0;
795 break;
796 case PKT_ETX:
797 chksum = ~chksum + 1; //test checksum
798 if (chksum != 0)
799 {
800 Log(LOG_ERROR, "bootloader, received response with invalid checksum!");
801 return false;
802 }
803 //Message OK
804 /*
805 for (jj = 0; jj < m_rx_tot_bytes; jj++)
806 {
807 std::stringstream sstr;
808 sstr << "0x" << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << int(m_rx_input_buffer[jj]);
809 if (jj != m_rx_tot_bytes - 1)
810 sstr << ", ";
811 szRespone+=sstr.str();
812 }
813 _log.Log(LOG_STATUS, "%s", szRespone.c_str());
814 */
815 m_bHaveRX = true;
816 return true;
817 break;
818 case PKT_DLE:
819 dbyte = pdata[ii + 1];
820 ii++;
821 if (ii >= length)
822 return false;
823 default:
824 chksum += dbyte;
825 m_rx_input_buffer[m_rx_tot_bytes++] = dbyte;
826 break;
827 }
828 ii++;
829 }
830 return false;
831 }
832
readCallback(const char * data,size_t len)833 void RFXComSerial::readCallback(const char *data, size_t len)
834 {
835 std::lock_guard<std::mutex> l(readQueueMutex);
836 try
837 {
838 if (!m_bInBootloaderMode)
839 {
840 bool bRet = onInternalMessage((const unsigned char *)data, len);
841 if (bRet == false)
842 {
843 //close serial connection, and restart
844 terminate();
845
846 }
847 }
848 }
849 catch (...)
850 {
851
852 }
853 }
854
WriteToHardware(const char * pdata,const unsigned char length)855 bool RFXComSerial::WriteToHardware(const char *pdata, const unsigned char length)
856 {
857 if (!isOpen())
858 return false;
859 if (m_bInBootloaderMode)
860 return false;
861 write(pdata, length);
862 return true;
863 }
864
865 //Webserver helpers
866 namespace http {
867 namespace server {
RFXComUpgradeFirmware(WebEmSession & session,const request & req,std::string & redirect_uri)868 void CWebServer::RFXComUpgradeFirmware(WebEmSession & session, const request& req, std::string & redirect_uri)
869 {
870 redirect_uri = "/index.html";
871 if (session.rights != 2)
872 {
873 session.reply_status = reply::forbidden;
874 return; //Only admin user allowed
875 }
876
877 std::string hardwareid = request::findValue(&req, "hardwareid");
878 std::string firmwarefile = request::findValue(&req, "firmwarefile");
879
880 if (firmwarefile.empty())
881 {
882 return;
883 }
884
885 CDomoticzHardwareBase *pHardware = NULL;
886 if ((!hardwareid.empty()) && (hardwareid != "undefined"))
887 {
888 pHardware = m_mainworker.GetHardware(atoi(hardwareid.c_str()));
889 }
890 if (pHardware == NULL)
891 {
892 //Direct Entry, try to find the RFXCom hardware
893 pHardware = m_mainworker.GetHardwareByType(HTYPE_RFXtrx433);
894 if (pHardware == NULL)
895 {
896 pHardware = m_mainworker.GetHardwareByType(HTYPE_RFXtrx868);
897 if (pHardware == NULL)
898 {
899 return;
900 }
901 }
902 }
903 #ifdef WIN32
904 std::string outputfile = szStartupFolder + "rfx_firmware.hex";
905 #else
906 std::string outputfile = "/tmp/rfx_firmware.hex";
907 #endif
908 std::ofstream outfile;
909 outfile.open(outputfile.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
910 if (!outfile.is_open())
911 return;
912 outfile << firmwarefile;
913 outfile.flush();
914 outfile.close();
915
916 if (
917 (pHardware->HwdType == HTYPE_RFXtrx315) ||
918 (pHardware->HwdType == HTYPE_RFXtrx433) ||
919 (pHardware->HwdType == HTYPE_RFXtrx868)
920 )
921 {
922 RFXComSerial *pRFXComSerial = reinterpret_cast<RFXComSerial *>(pHardware);
923 pRFXComSerial->UploadFirmware(outputfile);
924 }
925 }
926
SetRFXCOMMode(WebEmSession & session,const request & req,std::string & redirect_uri)927 void CWebServer::SetRFXCOMMode(WebEmSession & session, const request& req, std::string & redirect_uri)
928 {
929 redirect_uri = "/index.html";
930
931 if (session.rights != 2)
932 {
933 session.reply_status = reply::forbidden;
934 return; //Only admin user allowed
935 }
936
937 std::string idx = request::findValue(&req, "idx");
938 if (idx == "") {
939 return;
940 }
941 std::vector<std::vector<std::string> > result;
942
943 result = m_sql.safe_query("SELECT Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, [Type] FROM Hardware WHERE (ID='%q')", idx.c_str());
944 if (result.empty())
945 return;
946
947 unsigned char Mode1 = atoi(result[0][0].c_str());
948 unsigned char Mode2 = atoi(result[0][1].c_str());
949 unsigned char Mode3 = atoi(result[0][2].c_str());
950 unsigned char Mode4 = atoi(result[0][3].c_str());
951 unsigned char Mode5 = atoi(result[0][4].c_str());
952 unsigned char Mode6 = atoi(result[0][5].c_str());
953
954 _eHardwareTypes HWType = (_eHardwareTypes)atoi(result[0][6].c_str());
955
956 tRBUF Response;
957 Response.ICMND.freqsel = Mode1;
958 Response.ICMND.xmitpwr = Mode2;
959 Response.ICMND.msg3 = Mode3;
960 Response.ICMND.msg4 = Mode4;
961 Response.ICMND.msg5 = Mode5;
962 Response.ICMND.msg6 = Mode6;
963
964 if (HWType != HTYPE_RFXtrx868)
965 {
966 Response.IRESPONSE.UNDECODEDenabled = (request::findValue(&req, "undecon") == "on") ? 1 : 0;
967 Response.IRESPONSE.X10enabled = (request::findValue(&req, "X10") == "on") ? 1 : 0;
968 Response.IRESPONSE.ARCenabled = (request::findValue(&req, "ARC") == "on") ? 1 : 0;
969 Response.IRESPONSE.ACenabled = (request::findValue(&req, "AC") == "on") ? 1 : 0;
970 Response.IRESPONSE.HEEUenabled = (request::findValue(&req, "HomeEasyEU") == "on") ? 1 : 0;
971 Response.IRESPONSE.MEIANTECHenabled = (request::findValue(&req, "Meiantech") == "on") ? 1 : 0;
972 Response.IRESPONSE.OREGONenabled = (request::findValue(&req, "OregonScientific") == "on") ? 1 : 0;
973 Response.IRESPONSE.ATIenabled = (request::findValue(&req, "ATIremote") == "on") ? 1 : 0;
974 Response.IRESPONSE.VISONICenabled = (request::findValue(&req, "Visonic") == "on") ? 1 : 0;
975 Response.IRESPONSE.MERTIKenabled = (request::findValue(&req, "Mertik") == "on") ? 1 : 0;
976 Response.IRESPONSE.LWRFenabled = (request::findValue(&req, "ADLightwaveRF") == "on") ? 1 : 0;
977 Response.IRESPONSE.HIDEKIenabled = (request::findValue(&req, "HidekiUPM") == "on") ? 1 : 0;
978 Response.IRESPONSE.LACROSSEenabled = (request::findValue(&req, "LaCrosse") == "on") ? 1 : 0;
979 Response.IRESPONSE.LEGRANDenabled = (request::findValue(&req, "Legrand") == "on") ? 1 : 0;
980 Response.IRESPONSE.MSG4Reserved5 = (request::findValue(&req, "ProGuard") == "on") ? 1 : 0;
981 Response.IRESPONSE.BLINDST0enabled = (request::findValue(&req, "BlindT0") == "on") ? 1 : 0;
982 Response.IRESPONSE.BLINDST1enabled = (request::findValue(&req, "BlindT1T2T3T4") == "on") ? 1 : 0;
983 Response.IRESPONSE.AEenabled = (request::findValue(&req, "AEBlyss") == "on") ? 1 : 0;
984 Response.IRESPONSE.RUBICSONenabled = (request::findValue(&req, "Rubicson") == "on") ? 1 : 0;
985 Response.IRESPONSE.FINEOFFSETenabled = (request::findValue(&req, "FineOffsetViking") == "on") ? 1 : 0;
986 Response.IRESPONSE.LIGHTING4enabled = (request::findValue(&req, "Lighting4") == "on") ? 1 : 0;
987 Response.IRESPONSE.RSLenabled = (request::findValue(&req, "RSL") == "on") ? 1 : 0;
988 Response.IRESPONSE.SXenabled = (request::findValue(&req, "ByronSX") == "on") ? 1 : 0;
989 Response.IRESPONSE.IMAGINTRONIXenabled = (request::findValue(&req, "ImaginTronix") == "on") ? 1 : 0;
990 Response.IRESPONSE.KEELOQenabled = (request::findValue(&req, "Keeloq") == "on") ? 1 : 0;
991 Response.IRESPONSE.HCEnabled = (request::findValue(&req, "HC") == "on") ? 1 : 0;
992
993 CDomoticzHardwareBase *pHardware = m_mainworker.GetHardware(atoi(idx.c_str()));
994 if (pHardware)
995 {
996 CRFXBase *pBase = reinterpret_cast<CRFXBase *>(pHardware);
997 pBase->SetRFXCOMHardwaremodes(Response.ICMND.freqsel, Response.ICMND.xmitpwr, Response.ICMND.msg3, Response.ICMND.msg4, Response.ICMND.msg5, Response.ICMND.msg6);
998
999 if (pBase->m_Version.find("Pro XL") != std::string::npos)
1000 {
1001 std::string AsyncMode = request::findValue(&req, "combo_rfx_xl_async_type");
1002 if (AsyncMode == "")
1003 AsyncMode = "0";
1004 result = m_sql.safe_query("UPDATE Hardware SET Extra='%q' WHERE (ID='%q')", AsyncMode.c_str(), idx.c_str());
1005 pBase->SetAsyncType((CRFXBase::_eRFXAsyncType)atoi(AsyncMode.c_str()));
1006 }
1007 }
1008 }
1009 else
1010 {
1011 //For now disable setting the protocols on a 868Mhz device
1012 }
1013 }
1014
Cmd_RFXComGetFirmwarePercentage(WebEmSession & session,const request & req,Json::Value & root)1015 void CWebServer::Cmd_RFXComGetFirmwarePercentage(WebEmSession & session, const request& req, Json::Value &root)
1016 {
1017 root["status"] = "ERR";
1018 root["title"] = "GetFirmwareUpgradePercentage";
1019 std::string hardwareid = request::findValue(&req, "hardwareid");
1020
1021 CDomoticzHardwareBase *pHardware = NULL;
1022 if ((!hardwareid.empty()) && (hardwareid != "undefined"))
1023 {
1024 pHardware = m_mainworker.GetHardware(atoi(hardwareid.c_str()));
1025 }
1026 if (pHardware == NULL)
1027 {
1028 //Direct Entry, try to find the RFXCom hardware
1029 pHardware = m_mainworker.GetHardwareByType(HTYPE_RFXtrx433);
1030 if (pHardware == NULL)
1031 {
1032 pHardware = m_mainworker.GetHardwareByType(HTYPE_RFXtrx868);
1033 }
1034 }
1035 if (pHardware != NULL)
1036 {
1037 if (
1038 (pHardware->HwdType == HTYPE_RFXtrx315) ||
1039 (pHardware->HwdType == HTYPE_RFXtrx433) ||
1040 (pHardware->HwdType == HTYPE_RFXtrx868)
1041 )
1042 {
1043 RFXComSerial *pRFXComSerial = reinterpret_cast<RFXComSerial *>(pHardware);
1044 root["status"] = "OK";
1045 root["percentage"] = pRFXComSerial->GetUploadPercentage();
1046 root["message"] = pRFXComSerial->GetUploadMessage();
1047 }
1048 }
1049 else
1050 root["message"] = "Hardware not found, or not enabled!";
1051 }
1052 }
1053 }
1054