Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MyTransportRS485.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. *
  19. * -------------------------------------------------------------------------------
  20. *
  21. * Copyright (c) 2013, Majenko Technologies and S.J.Hoeksma
  22. * Copyright (c) 2015, LeoDesigner
  23. * https://github.com/leodesigner/mysensors-serial-transport
  24. * All rights reserved.
  25. *
  26. * Redistribution and use in source and binary forms, with or without
  27. * modification, are permitted provided that the following conditions are met:
  28. *
  29. * 1. Redistributions of source code must retain the above copyright notice, this
  30. * list of conditions and the following disclaimer.
  31. * 2. Redistributions in binary form must reproduce the above copyright notice,
  32. * this list of conditions and the following disclaimer in the documentation
  33. * and/or other materials provided with the distribution.
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  36. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  37. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  39. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  40. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  41. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  42. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  43. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45. *
  46. * The views and conclusions contained in the software and documentation are those
  47. * of the authors and should not be interpreted as representing official policies,
  48. * either expressed or implied, of Majenko Technologies.
  49. ********************************************************************************/
  50. // transport(Serial,0,-1); // serial port, node, dePin (-1 disabled)
  51. // Serial Transport
  52. #ifdef __linux__
  53. #include "SerialPort.h"
  54. #endif
  55. #if defined(MY_RS485_DE_PIN)
  56. #define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5)
  57. #define deassertDE() hwDigitalWrite(MY_RS485_DE_PIN, LOW)
  58. #else
  59. #define assertDE()
  60. #define deassertDE()
  61. #endif
  62. // We only use SYS_PACK in this application
  63. #define ICSC_SYS_PACK 0x58
  64. // Receiving header information
  65. char _header[6];
  66. // Reception state machine control and storage variables
  67. unsigned char _recPhase;
  68. unsigned char _recPos;
  69. unsigned char _recCommand;
  70. unsigned char _recLen;
  71. unsigned char _recStation;
  72. unsigned char _recSender;
  73. unsigned char _recCS;
  74. unsigned char _recCalcCS;
  75. #if defined(__linux__)
  76. SerialPort _dev = SerialPort(MY_RS485_HWSERIAL);
  77. #elif defined(MY_RS485_HWSERIAL)
  78. HardwareSerial& _dev = MY_RS485_HWSERIAL;
  79. #else
  80. AltSoftSerial _dev;
  81. #endif
  82. unsigned char _nodeId;
  83. char _data[MY_RS485_MAX_MESSAGE_LENGTH];
  84. uint8_t _packet_len;
  85. unsigned char _packet_from;
  86. bool _packet_received;
  87. // Packet wrapping characters, defined in standard ASCII table
  88. #define SOH 1
  89. #define STX 2
  90. #define ETX 3
  91. #define EOT 4
  92. //Reset the state machine and release the data pointer
  93. void _serialReset()
  94. {
  95. _recPhase = 0;
  96. _recPos = 0;
  97. _recLen = 0;
  98. _recCommand = 0;
  99. _recCS = 0;
  100. _recCalcCS = 0;
  101. }
  102. // This is the main reception state machine. Progress through the states
  103. // is keyed on either special control characters, or counted number of bytes
  104. // received. If all the data is in the right format, and the calculated
  105. // checksum matches the received checksum, AND the destination station is
  106. // our station ID, then look for a registered command that matches the
  107. // command code. If all the above is true, execute the command's
  108. // function.
  109. bool _serialProcess()
  110. {
  111. unsigned char i;
  112. if (!_dev.available()) {
  113. return false;
  114. }
  115. while(_dev.available()) {
  116. char inch;
  117. inch = _dev.read();
  118. switch(_recPhase) {
  119. // Case 0 looks for the header. Bytes arrive in the serial interface and get
  120. // shifted through a header buffer. When the start and end characters in
  121. // the buffer match the SOH/STX pair, and the destination station ID matches
  122. // our ID, save the header information and progress to the next state.
  123. case 0:
  124. memcpy(&_header[0],&_header[1],5);
  125. _header[5] = inch;
  126. if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) {
  127. _recCalcCS = 0;
  128. _recStation = _header[1];
  129. _recSender = _header[2];
  130. _recCommand = _header[3];
  131. _recLen = _header[4];
  132. for (i=1; i<=4; i++) {
  133. _recCalcCS += _header[i];
  134. }
  135. _recPhase = 1;
  136. _recPos = 0;
  137. //Avoid _data[] overflow
  138. if (_recLen >= MY_RS485_MAX_MESSAGE_LENGTH) {
  139. _serialReset();
  140. break;
  141. }
  142. //Check if we should process this message
  143. //We reject the message if we are the sender
  144. //We reject if we are not the receiver and message is not a broadcast
  145. if ((_recSender == _nodeId) ||
  146. (_recStation != _nodeId &&
  147. _recStation != BROADCAST_ADDRESS)) {
  148. _serialReset();
  149. break;
  150. }
  151. if (_recLen == 0) {
  152. _recPhase = 2;
  153. }
  154. }
  155. break;
  156. // Case 1 receives the data portion of the packet. Read in "_recLen" number
  157. // of bytes and store them in the _data array.
  158. case 1:
  159. _data[_recPos++] = inch;
  160. _recCalcCS += inch;
  161. if (_recPos == _recLen) {
  162. _recPhase = 2;
  163. }
  164. break;
  165. // After the data comes a single ETX character. Do we have it? If not,
  166. // reset the state machine to default and start looking for a new header.
  167. case 2:
  168. // Packet properly terminated?
  169. if (inch == ETX) {
  170. _recPhase = 3;
  171. } else {
  172. _serialReset();
  173. }
  174. break;
  175. // Next comes the checksum. We have already calculated it from the incoming
  176. // data, so just store the incoming checksum byte for later.
  177. case 3:
  178. _recCS = inch;
  179. _recPhase = 4;
  180. break;
  181. // The final state - check the last character is EOT and that the checksum matches.
  182. // If that test passes, then look for a valid command callback to execute.
  183. // Execute it if found.
  184. case 4:
  185. if (inch == EOT) {
  186. if (_recCS == _recCalcCS) {
  187. // First, check for system level commands. It is possible
  188. // to register your own callback as well for system level
  189. // commands which will be called after the system default
  190. // hook.
  191. switch (_recCommand) {
  192. case ICSC_SYS_PACK:
  193. _packet_from = _recSender;
  194. _packet_len = _recLen;
  195. _packet_received = true;
  196. break;
  197. }
  198. }
  199. }
  200. //Clear the data
  201. _serialReset();
  202. //Return true, we have processed one command
  203. return true;
  204. break;
  205. }
  206. }
  207. return true;
  208. }
  209. bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK)
  210. {
  211. (void)noACK; // not implemented
  212. const char *datap = static_cast<char const *>(data);
  213. unsigned char i;
  214. unsigned char cs = 0;
  215. // This is how many times to try and transmit before failing.
  216. unsigned char timeout = 10;
  217. // Let's start out by looking for a collision. If there has been anything seen in
  218. // the last millisecond, then wait for a random time and check again.
  219. while (_serialProcess()) {
  220. unsigned char del;
  221. del = rand() % 20;
  222. for (i = 0; i < del; i++) {
  223. delay(1);
  224. _serialProcess();
  225. }
  226. timeout--;
  227. if (timeout == 0) {
  228. // Failed to transmit!!!
  229. return false;
  230. }
  231. }
  232. #if defined(MY_RS485_DE_PIN)
  233. hwDigitalWrite(MY_RS485_DE_PIN, HIGH);
  234. delayMicroseconds(5);
  235. #endif
  236. // Start of header by writing multiple SOH
  237. for(byte w=0; w<MY_RS485_SOH_COUNT; w++) {
  238. _dev.write(SOH);
  239. }
  240. _dev.write(to); // Destination address
  241. cs += to;
  242. _dev.write(_nodeId); // Source address
  243. cs += _nodeId;
  244. _dev.write(ICSC_SYS_PACK); // Command code
  245. cs += ICSC_SYS_PACK;
  246. _dev.write(len); // Length of text
  247. cs += len;
  248. _dev.write(STX); // Start of text
  249. for(i=0; i<len; i++) {
  250. _dev.write(datap[i]); // Text bytes
  251. cs += datap[i];
  252. }
  253. _dev.write(ETX); // End of text
  254. _dev.write(cs);
  255. _dev.write(EOT);
  256. #if defined(MY_RS485_DE_PIN)
  257. #ifdef __PIC32MX__
  258. // MPIDE has nothing yet for this. It uses the hardware buffer, which
  259. // could be up to 8 levels deep. For now, let's just delay for 8
  260. // characters worth.
  261. delayMicroseconds((F_CPU/9600)+1);
  262. #else
  263. #if defined(ARDUINO) && ARDUINO >= 100
  264. #if ARDUINO >= 104
  265. // Arduino 1.0.4 and upwards does it right
  266. _dev.flush();
  267. #else
  268. // Between 1.0.0 and 1.0.3 it almost does it - need to compensate
  269. // for the hardware buffer. Delay for 2 bytes worth of transmission.
  270. _dev.flush();
  271. delayMicroseconds((20000000UL/9600)+1);
  272. #endif
  273. #elif defined(__linux__)
  274. _dev.flush();
  275. #endif
  276. #endif
  277. hwDigitalWrite(MY_RS485_DE_PIN, LOW);
  278. #endif
  279. return true;
  280. }
  281. bool transportInit(void)
  282. {
  283. // Reset the state machine
  284. _dev.begin(MY_RS485_BAUD_RATE);
  285. _serialReset();
  286. #if defined(MY_RS485_DE_PIN)
  287. hwPinMode(MY_RS485_DE_PIN, OUTPUT);
  288. hwDigitalWrite(MY_RS485_DE_PIN, LOW);
  289. #endif
  290. return true;
  291. }
  292. void transportSetAddress(const uint8_t address)
  293. {
  294. _nodeId = address;
  295. }
  296. uint8_t transportGetAddress(void)
  297. {
  298. return _nodeId;
  299. }
  300. bool transportAvailable(void)
  301. {
  302. _serialProcess();
  303. return _packet_received;
  304. }
  305. bool transportSanityCheck(void)
  306. {
  307. // not implemented yet
  308. return true;
  309. }
  310. uint8_t transportReceive(void* data)
  311. {
  312. if (_packet_received) {
  313. memcpy(data,_data,_packet_len);
  314. _packet_received = false;
  315. return _packet_len;
  316. } else {
  317. return (0);
  318. }
  319. }
  320. void transportPowerDown(void)
  321. {
  322. // Nothing to shut down here
  323. }
  324. void transportPowerUp(void)
  325. {
  326. // not implemented
  327. }
  328. void transportSleep(void)
  329. {
  330. // not implemented
  331. }
  332. void transportStandBy(void)
  333. {
  334. // not implemented
  335. }
  336. int16_t transportGetSendingRSSI(void)
  337. {
  338. // not implemented
  339. return INVALID_RSSI;
  340. }
  341. int16_t transportGetReceivingRSSI(void)
  342. {
  343. // not implemented
  344. return INVALID_RSSI;
  345. }
  346. int16_t transportGetSendingSNR(void)
  347. {
  348. // not implemented
  349. return INVALID_SNR;
  350. }
  351. int16_t transportGetReceivingSNR(void)
  352. {
  353. // not implemented
  354. return INVALID_SNR;
  355. }
  356. int16_t transportGetTxPowerPercent(void)
  357. {
  358. // not implemented
  359. return static_cast<int16_t>(100);
  360. }
  361. int16_t transportGetTxPowerLevel(void)
  362. {
  363. // not implemented
  364. return static_cast<int16_t>(100);
  365. }
  366. bool transportSetTxPowerPercent(const uint8_t powerPercent)
  367. {
  368. // not possible
  369. (void)powerPercent;
  370. return false;
  371. }