RCSwitch.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /*
  2. RCSwitch - Arduino libary for remote control outlet switches
  3. Copyright (c) 2011 Suat Özgür. All right reserved.
  4. Contributors:
  5. - Andre Koehler / info(at)tomate-online(dot)de
  6. - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
  7. - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
  8. - Dominik Fischer / dom_fischer(at)web(dot)de
  9. - Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
  10. - Andreas Steinel / A.<lastname>(at)gmail(dot)com
  11. - Max Horn / max(at)quendi(dot)de
  12. - Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
  13. - Johann Richard / <first name>.<last name>(at)gmail(dot)com
  14. - Vlad Gheorghe / <first name>.<last name>(at)gmail(dot)com https://github.com/vgheo
  15. Project home: https://github.com/sui77/rc-switch/
  16. This library is free software; you can redistribute it and/or
  17. modify it under the terms of the GNU Lesser General Public
  18. License as published by the Free Software Foundation; either
  19. version 2.1 of the License, or (at your option) any later version.
  20. This library is distributed in the hope that it will be useful,
  21. but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  23. Lesser General Public License for more details.
  24. You should have received a copy of the GNU Lesser General Public
  25. License along with this library; if not, write to the Free Software
  26. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  27. */
  28. #include "RCSwitch.h"
  29. #ifdef RaspberryPi
  30. // PROGMEM and _P functions are for AVR based microprocessors,
  31. // so we must normalize these for the ARM processor:
  32. #define PROGMEM
  33. #define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
  34. #endif
  35. #if defined(ESP8266) || defined(ESP32)
  36. // interrupt handler and related code must be in RAM on ESP8266,
  37. // according to issue #46.
  38. #define RECEIVE_ATTR ICACHE_RAM_ATTR
  39. #else
  40. #define RECEIVE_ATTR
  41. #endif
  42. /* Format for protocol definitions:
  43. * {pulselength, Sync bit, "0" bit, "1" bit}
  44. *
  45. * pulselength: pulse length in microseconds, e.g. 350
  46. * Sync bit: {1, 31} means 1 high pulse and 31 low pulses
  47. * (perceived as a 31*pulselength long pulse, total length of sync bit is
  48. * 32*pulselength microseconds), i.e:
  49. * _
  50. * | |_______________________________ (don't count the vertical bars)
  51. * "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
  52. * and 3 low pulses, total length (1+3)*pulselength, i.e:
  53. * _
  54. * | |___
  55. * "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
  56. * ___
  57. * | |_
  58. *
  59. * These are combined to form Tri-State bits when sending or receiving codes.
  60. */
  61. #if defined(ESP8266) || defined(ESP32)
  62. static const RCSwitch::Protocol proto[] = {
  63. #else
  64. static const RCSwitch::Protocol PROGMEM proto[] = {
  65. #endif
  66. { 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1
  67. { 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2
  68. { 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3
  69. { 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4
  70. { 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5
  71. { 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B)
  72. { 150, { 2, 62 }, { 1, 6 }, { 6, 1 }, false } // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote)
  73. };
  74. enum {
  75. numProto = sizeof(proto) / sizeof(proto[0])
  76. };
  77. #if not defined( RCSwitchDisableReceiving )
  78. volatile unsigned long RCSwitch::nReceivedValue = 0;
  79. volatile unsigned int RCSwitch::nReceivedBitlength = 0;
  80. volatile unsigned int RCSwitch::nReceivedDelay = 0;
  81. volatile unsigned int RCSwitch::nReceivedProtocol = 0;
  82. int RCSwitch::nReceiveTolerance = 60;
  83. const unsigned int RCSwitch::nSeparationLimit = 4300;
  84. // separationLimit: minimum microseconds between received codes, closer codes are ignored.
  85. // according to discussion on issue #14 it might be more suitable to set the separation
  86. // limit to the same time as the 'low' part of the sync signal for the current protocol.
  87. unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
  88. #endif
  89. RCSwitch::RCSwitch() {
  90. this->nTransmitterPin = -1;
  91. this->setRepeatTransmit(10);
  92. this->setProtocol(1);
  93. #if not defined( RCSwitchDisableReceiving )
  94. this->nReceiverInterrupt = -1;
  95. this->setReceiveTolerance(60);
  96. RCSwitch::nReceivedValue = 0;
  97. #endif
  98. }
  99. /**
  100. * Sets the protocol to send.
  101. */
  102. void RCSwitch::setProtocol(Protocol protocol) {
  103. this->protocol = protocol;
  104. }
  105. /**
  106. * Sets the protocol to send, from a list of predefined protocols
  107. */
  108. void RCSwitch::setProtocol(int nProtocol) {
  109. if (nProtocol < 1 || nProtocol > numProto) {
  110. nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
  111. }
  112. #if defined(ESP8266) || defined(ESP32)
  113. this->protocol = proto[nProtocol-1];
  114. #else
  115. memcpy_P(&this->protocol, &proto[nProtocol-1], sizeof(Protocol));
  116. #endif
  117. }
  118. /**
  119. * Sets the protocol to send with pulse length in microseconds.
  120. */
  121. void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
  122. setProtocol(nProtocol);
  123. this->setPulseLength(nPulseLength);
  124. }
  125. /**
  126. * Sets pulse length in microseconds
  127. */
  128. void RCSwitch::setPulseLength(int nPulseLength) {
  129. this->protocol.pulseLength = nPulseLength;
  130. }
  131. /**
  132. * Sets Repeat Transmits
  133. */
  134. void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
  135. this->nRepeatTransmit = nRepeatTransmit;
  136. }
  137. /**
  138. * Set Receiving Tolerance
  139. */
  140. #if not defined( RCSwitchDisableReceiving )
  141. void RCSwitch::setReceiveTolerance(int nPercent) {
  142. RCSwitch::nReceiveTolerance = nPercent;
  143. }
  144. #endif
  145. /**
  146. * Enable transmissions
  147. *
  148. * @param nTransmitterPin Arduino Pin to which the sender is connected to
  149. */
  150. void RCSwitch::enableTransmit(int nTransmitterPin) {
  151. this->nTransmitterPin = nTransmitterPin;
  152. pinMode(this->nTransmitterPin, OUTPUT);
  153. }
  154. /**
  155. * Disable transmissions
  156. */
  157. void RCSwitch::disableTransmit() {
  158. this->nTransmitterPin = -1;
  159. }
  160. /**
  161. * Switch a remote switch on (Type D REV)
  162. *
  163. * @param sGroup Code of the switch group (A,B,C,D)
  164. * @param nDevice Number of the switch itself (1..3)
  165. */
  166. void RCSwitch::switchOn(char sGroup, int nDevice) {
  167. this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) );
  168. }
  169. /**
  170. * Switch a remote switch off (Type D REV)
  171. *
  172. * @param sGroup Code of the switch group (A,B,C,D)
  173. * @param nDevice Number of the switch itself (1..3)
  174. */
  175. void RCSwitch::switchOff(char sGroup, int nDevice) {
  176. this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) );
  177. }
  178. /**
  179. * Switch a remote switch on (Type C Intertechno)
  180. *
  181. * @param sFamily Familycode (a..f)
  182. * @param nGroup Number of group (1..4)
  183. * @param nDevice Number of device (1..4)
  184. */
  185. void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
  186. this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
  187. }
  188. /**
  189. * Switch a remote switch off (Type C Intertechno)
  190. *
  191. * @param sFamily Familycode (a..f)
  192. * @param nGroup Number of group (1..4)
  193. * @param nDevice Number of device (1..4)
  194. */
  195. void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
  196. this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
  197. }
  198. /**
  199. * Switch a remote switch on (Type B with two rotary/sliding switches)
  200. *
  201. * @param nAddressCode Number of the switch group (1..4)
  202. * @param nChannelCode Number of the switch itself (1..4)
  203. */
  204. void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
  205. this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
  206. }
  207. /**
  208. * Switch a remote switch off (Type B with two rotary/sliding switches)
  209. *
  210. * @param nAddressCode Number of the switch group (1..4)
  211. * @param nChannelCode Number of the switch itself (1..4)
  212. */
  213. void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
  214. this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
  215. }
  216. /**
  217. * Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
  218. * Switch a remote switch on (Type A with 10 pole DIP switches)
  219. *
  220. * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
  221. * @param nChannelCode Number of the switch itself (1..5)
  222. */
  223. void RCSwitch::switchOn(const char* sGroup, int nChannel) {
  224. const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
  225. this->switchOn(sGroup, code[nChannel]);
  226. }
  227. /**
  228. * Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
  229. * Switch a remote switch off (Type A with 10 pole DIP switches)
  230. *
  231. * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
  232. * @param nChannelCode Number of the switch itself (1..5)
  233. */
  234. void RCSwitch::switchOff(const char* sGroup, int nChannel) {
  235. const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
  236. this->switchOff(sGroup, code[nChannel]);
  237. }
  238. /**
  239. * Switch a remote switch on (Type A with 10 pole DIP switches)
  240. *
  241. * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
  242. * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
  243. */
  244. void RCSwitch::switchOn(const char* sGroup, const char* sDevice) {
  245. this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
  246. }
  247. /**
  248. * Switch a remote switch off (Type A with 10 pole DIP switches)
  249. *
  250. * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
  251. * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
  252. */
  253. void RCSwitch::switchOff(const char* sGroup, const char* sDevice) {
  254. this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
  255. }
  256. /**
  257. * Returns a char[13], representing the code word to be send.
  258. *
  259. */
  260. char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) {
  261. static char sReturn[13];
  262. int nReturnPos = 0;
  263. for (int i = 0; i < 5; i++) {
  264. sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
  265. }
  266. for (int i = 0; i < 5; i++) {
  267. sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
  268. }
  269. sReturn[nReturnPos++] = bStatus ? '0' : 'F';
  270. sReturn[nReturnPos++] = bStatus ? 'F' : '0';
  271. sReturn[nReturnPos] = '\0';
  272. return sReturn;
  273. }
  274. /**
  275. * Encoding for type B switches with two rotary/sliding switches.
  276. *
  277. * The code word is a tristate word and with following bit pattern:
  278. *
  279. * +-----------------------------+-----------------------------+----------+------------+
  280. * | 4 bits address | 4 bits address | 3 bits | 1 bit |
  281. * | switch group | switch number | not used | on / off |
  282. * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
  283. * +-----------------------------+-----------------------------+----------+------------+
  284. *
  285. * @param nAddressCode Number of the switch group (1..4)
  286. * @param nChannelCode Number of the switch itself (1..4)
  287. * @param bStatus Whether to switch on (true) or off (false)
  288. *
  289. * @return char[13], representing a tristate code word of length 12
  290. */
  291. char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) {
  292. static char sReturn[13];
  293. int nReturnPos = 0;
  294. if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
  295. return 0;
  296. }
  297. for (int i = 1; i <= 4; i++) {
  298. sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
  299. }
  300. for (int i = 1; i <= 4; i++) {
  301. sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
  302. }
  303. sReturn[nReturnPos++] = 'F';
  304. sReturn[nReturnPos++] = 'F';
  305. sReturn[nReturnPos++] = 'F';
  306. sReturn[nReturnPos++] = bStatus ? 'F' : '0';
  307. sReturn[nReturnPos] = '\0';
  308. return sReturn;
  309. }
  310. /**
  311. * Like getCodeWord (Type C = Intertechno)
  312. */
  313. char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) {
  314. static char sReturn[13];
  315. int nReturnPos = 0;
  316. int nFamily = (int)sFamily - 'a';
  317. if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
  318. return 0;
  319. }
  320. // encode the family into four bits
  321. sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
  322. sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
  323. sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
  324. sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
  325. // encode the device and group
  326. sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0';
  327. sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0';
  328. sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0';
  329. sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0';
  330. // encode the status code
  331. sReturn[nReturnPos++] = '0';
  332. sReturn[nReturnPos++] = 'F';
  333. sReturn[nReturnPos++] = 'F';
  334. sReturn[nReturnPos++] = bStatus ? 'F' : '0';
  335. sReturn[nReturnPos] = '\0';
  336. return sReturn;
  337. }
  338. /**
  339. * Encoding for the REV Switch Type
  340. *
  341. * The code word is a tristate word and with following bit pattern:
  342. *
  343. * +-----------------------------+-------------------+----------+--------------+
  344. * | 4 bits address | 3 bits address | 3 bits | 2 bits |
  345. * | switch group | device number | not used | on / off |
  346. * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
  347. * +-----------------------------+-------------------+----------+--------------+
  348. *
  349. * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
  350. *
  351. * @param sGroup Name of the switch group (A..D, resp. a..d)
  352. * @param nDevice Number of the switch itself (1..3)
  353. * @param bStatus Whether to switch on (true) or off (false)
  354. *
  355. * @return char[13], representing a tristate code word of length 12
  356. */
  357. char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) {
  358. static char sReturn[13];
  359. int nReturnPos = 0;
  360. // sGroup must be one of the letters in "abcdABCD"
  361. int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
  362. if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
  363. return 0;
  364. }
  365. for (int i = 0; i < 4; i++) {
  366. sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
  367. }
  368. for (int i = 1; i <= 3; i++) {
  369. sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
  370. }
  371. sReturn[nReturnPos++] = '0';
  372. sReturn[nReturnPos++] = '0';
  373. sReturn[nReturnPos++] = '0';
  374. sReturn[nReturnPos++] = bStatus ? '1' : '0';
  375. sReturn[nReturnPos++] = bStatus ? '0' : '1';
  376. sReturn[nReturnPos] = '\0';
  377. return sReturn;
  378. }
  379. /**
  380. * @param sCodeWord a tristate code word consisting of the letter 0, 1, F
  381. */
  382. void RCSwitch::sendTriState(const char* sCodeWord) {
  383. // turn the tristate code word into the corresponding bit pattern, then send it
  384. unsigned long code = 0;
  385. unsigned int length = 0;
  386. for (const char* p = sCodeWord; *p; p++) {
  387. code <<= 2L;
  388. switch (*p) {
  389. case '0':
  390. // bit pattern 00
  391. break;
  392. case 'F':
  393. // bit pattern 01
  394. code |= 1L;
  395. break;
  396. case '1':
  397. // bit pattern 11
  398. code |= 3L;
  399. break;
  400. }
  401. length += 2;
  402. }
  403. this->send(code, length);
  404. }
  405. /**
  406. * @param sCodeWord a binary code word consisting of the letter 0, 1
  407. */
  408. void RCSwitch::send(const char* sCodeWord) {
  409. // turn the tristate code word into the corresponding bit pattern, then send it
  410. unsigned long code = 0;
  411. unsigned int length = 0;
  412. for (const char* p = sCodeWord; *p; p++) {
  413. code <<= 1L;
  414. if (*p != '0')
  415. code |= 1L;
  416. length++;
  417. }
  418. this->send(code, length);
  419. }
  420. /**
  421. * Transmit the first 'length' bits of the integer 'code'. The
  422. * bits are sent from MSB to LSB, i.e., first the bit at position length-1,
  423. * then the bit at position length-2, and so on, till finally the bit at position 0.
  424. */
  425. void RCSwitch::send(unsigned long code, unsigned int length) {
  426. if (this->nTransmitterPin == -1)
  427. return;
  428. #if not defined( RCSwitchDisableReceiving )
  429. // make sure the receiver is disabled while we transmit
  430. int nReceiverInterrupt_backup = nReceiverInterrupt;
  431. if (nReceiverInterrupt_backup != -1) {
  432. this->disableReceive();
  433. }
  434. #endif
  435. for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
  436. for (int i = length-1; i >= 0; i--) {
  437. if (code & (1L << i))
  438. this->transmit(protocol.one);
  439. else
  440. this->transmit(protocol.zero);
  441. }
  442. this->transmit(protocol.syncFactor);
  443. }
  444. // Disable transmit after sending (i.e., for inverted protocols)
  445. digitalWrite(this->nTransmitterPin, LOW);
  446. #if not defined( RCSwitchDisableReceiving )
  447. // enable receiver again if we just disabled it
  448. if (nReceiverInterrupt_backup != -1) {
  449. this->enableReceive(nReceiverInterrupt_backup);
  450. }
  451. #endif
  452. }
  453. /**
  454. * Transmit a single high-low pulse.
  455. */
  456. void RCSwitch::transmit(HighLow pulses) {
  457. uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH;
  458. uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW;
  459. digitalWrite(this->nTransmitterPin, firstLogicLevel);
  460. delayMicroseconds( this->protocol.pulseLength * pulses.high);
  461. digitalWrite(this->nTransmitterPin, secondLogicLevel);
  462. delayMicroseconds( this->protocol.pulseLength * pulses.low);
  463. }
  464. #if not defined( RCSwitchDisableReceiving )
  465. /**
  466. * Enable receiving data
  467. */
  468. void RCSwitch::enableReceive(int interrupt) {
  469. this->nReceiverInterrupt = interrupt;
  470. this->enableReceive();
  471. }
  472. void RCSwitch::enableReceive() {
  473. if (this->nReceiverInterrupt != -1) {
  474. RCSwitch::nReceivedValue = 0;
  475. RCSwitch::nReceivedBitlength = 0;
  476. #if defined(RaspberryPi) // Raspberry Pi
  477. wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt);
  478. #else // Arduino
  479. attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
  480. #endif
  481. }
  482. }
  483. /**
  484. * Disable receiving data
  485. */
  486. void RCSwitch::disableReceive() {
  487. #if not defined(RaspberryPi) // Arduino
  488. detachInterrupt(this->nReceiverInterrupt);
  489. #endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
  490. this->nReceiverInterrupt = -1;
  491. }
  492. bool RCSwitch::available() {
  493. return RCSwitch::nReceivedValue != 0;
  494. }
  495. void RCSwitch::resetAvailable() {
  496. RCSwitch::nReceivedValue = 0;
  497. }
  498. unsigned long RCSwitch::getReceivedValue() {
  499. return RCSwitch::nReceivedValue;
  500. }
  501. unsigned int RCSwitch::getReceivedBitlength() {
  502. return RCSwitch::nReceivedBitlength;
  503. }
  504. unsigned int RCSwitch::getReceivedDelay() {
  505. return RCSwitch::nReceivedDelay;
  506. }
  507. unsigned int RCSwitch::getReceivedProtocol() {
  508. return RCSwitch::nReceivedProtocol;
  509. }
  510. unsigned int* RCSwitch::getReceivedRawdata() {
  511. return RCSwitch::timings;
  512. }
  513. /* helper function for the receiveProtocol method */
  514. static inline unsigned int diff(int A, int B) {
  515. return abs(A - B);
  516. }
  517. /**
  518. *
  519. */
  520. bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) {
  521. #if defined(ESP8266) || defined(ESP32)
  522. const Protocol &pro = proto[p-1];
  523. #else
  524. Protocol pro;
  525. memcpy_P(&pro, &proto[p-1], sizeof(Protocol));
  526. #endif
  527. unsigned long code = 0;
  528. //Assuming the longer pulse length is the pulse captured in timings[0]
  529. const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high);
  530. const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses;
  531. const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100;
  532. /* For protocols that start low, the sync period looks like
  533. * _________
  534. * _____________| |XXXXXXXXXXXX|
  535. *
  536. * |--1st dur--|-2nd dur-|-Start data-|
  537. *
  538. * The 3rd saved duration starts the data.
  539. *
  540. * For protocols that start high, the sync period looks like
  541. *
  542. * ______________
  543. * | |____________|XXXXXXXXXXXXX|
  544. *
  545. * |-filtered out-|--1st dur--|--Start data--|
  546. *
  547. * The 2nd saved duration starts the data
  548. */
  549. const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1);
  550. for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) {
  551. code <<= 1;
  552. if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance &&
  553. diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) {
  554. // zero
  555. } else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance &&
  556. diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
  557. // one
  558. code |= 1;
  559. } else {
  560. // Failed
  561. return false;
  562. }
  563. }
  564. if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise
  565. RCSwitch::nReceivedValue = code;
  566. RCSwitch::nReceivedBitlength = (changeCount - 1) / 2;
  567. RCSwitch::nReceivedDelay = delay;
  568. RCSwitch::nReceivedProtocol = p;
  569. return true;
  570. }
  571. return false;
  572. }
  573. void RECEIVE_ATTR RCSwitch::handleInterrupt() {
  574. static unsigned int changeCount = 0;
  575. static unsigned long lastTime = 0;
  576. static unsigned int repeatCount = 0;
  577. const long time = micros();
  578. const unsigned int duration = time - lastTime;
  579. if (duration > RCSwitch::nSeparationLimit) {
  580. // A long stretch without signal level change occurred. This could
  581. // be the gap between two transmission.
  582. if (diff(duration, RCSwitch::timings[0]) < 200) {
  583. // This long signal is close in length to the long signal which
  584. // started the previously recorded timings; this suggests that
  585. // it may indeed by a a gap between two transmissions (we assume
  586. // here that a sender will send the signal multiple times,
  587. // with roughly the same gap between them).
  588. repeatCount++;
  589. if (repeatCount == 2) {
  590. for(unsigned int i = 1; i <= numProto; i++) {
  591. if (receiveProtocol(i, changeCount)) {
  592. // receive succeeded for protocol i
  593. break;
  594. }
  595. }
  596. repeatCount = 0;
  597. }
  598. }
  599. changeCount = 0;
  600. }
  601. // detect overflow
  602. if (changeCount >= RCSWITCH_MAX_CHANGES) {
  603. changeCount = 0;
  604. repeatCount = 0;
  605. }
  606. RCSwitch::timings[changeCount++] = duration;
  607. lastTime = time;
  608. }
  609. #endif