NewRemoteReceiver.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * NewRemoteSwitch library v1.2.0 (20140128) made by Randy Simons http://randysimons.nl/
  3. * See NewRemoteReceiver.h for details.
  4. *
  5. * License: GPLv3. See license.txt
  6. */
  7. #include "NewRemoteReceiver.h"
  8. #define RESET_STATE _state = -1 // Resets state to initial position.
  9. /************
  10. * NewRemoteReceiver
  11. Protocol. (Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410,
  12. but with slightly different timings, as measured on my device.)
  13. _ _
  14. '0': | |_| |_____ (T,T,T,5T)
  15. _ _
  16. '1': | |_____| |_ (T,5T,T,T)
  17. _ _
  18. dim: | |_| |_ (T,T,T,T)
  19. T = short period of ~260µs. However, this code tries
  20. to figure out the correct period
  21. A full frame looks like this:
  22. - start pulse: 1T high, 10.44T low
  23. - 26 bit: Address
  24. - 1 bit: group bit
  25. - 1 bit: on/off/[dim]
  26. - 4 bit: unit
  27. - [4 bit: dim level. Present of [dim] is chosen, but might be present anyway...]
  28. - stop pulse: 1T high, 40T low
  29. ************/
  30. #ifdef ESP8266
  31. // interrupt handler and related code must be in RAM on ESP8266,
  32. #define RECEIVE_ATTR ICACHE_RAM_ATTR
  33. #define CALLBACK_SIGNATURE (_callback)(receivedCode.period, receivedCode.address, receivedCode.groupBit, receivedCode.unit, receivedCode.switchType)
  34. #else
  35. #define RECEIVE_ATTR
  36. #define CALLBACK_SIGNATURE (_callback)(receivedCode.period, receivedCode.address, receivedCode.groupBit, receivedCode.unit, receivedCode.switchType)
  37. #endif
  38. int8_t NewRemoteReceiver::_interrupt;
  39. volatile short NewRemoteReceiver::_state;
  40. byte NewRemoteReceiver::_minRepeats;
  41. NewRemoteReceiverCallBack NewRemoteReceiver::_callback;
  42. boolean NewRemoteReceiver::_inCallback = false;
  43. boolean NewRemoteReceiver::_enabled = false;
  44. void NewRemoteReceiver::init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback) {
  45. _interrupt = interrupt;
  46. _minRepeats = minRepeats;
  47. _callback = callback;
  48. enable();
  49. if (_interrupt >= 0) {
  50. attachInterrupt(_interrupt, interruptHandler, CHANGE);
  51. }
  52. }
  53. void NewRemoteReceiver::enable() {
  54. RESET_STATE;
  55. _enabled = true;
  56. }
  57. void NewRemoteReceiver::disable() {
  58. _enabled = false;
  59. }
  60. void NewRemoteReceiver::deinit() {
  61. _enabled = false;
  62. if (_interrupt >= 0) {
  63. detachInterrupt(_interrupt);
  64. }
  65. }
  66. void RECEIVE_ATTR NewRemoteReceiver::interruptHandler() {
  67. // This method is written as compact code to keep it fast. While breaking up this method into more
  68. // methods would certainly increase the readability, it would also be much slower to execute.
  69. // Making calls to other methods is quite expensive on AVR. As These interrupt handlers are called
  70. // many times a second, calling other methods should be kept to a minimum.
  71. if (!_enabled) {
  72. return;
  73. }
  74. static byte receivedBit; // Contains "bit" currently receiving
  75. static NewRemoteCode receivedCode; // Contains received code
  76. static NewRemoteCode previousCode; // Contains previous received code
  77. static byte repeats = 0; // The number of times the an identical code is received in a row.
  78. static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges
  79. static unsigned int min1Period, max1Period, min5Period, max5Period;
  80. static bool skip;
  81. // Filter out too short pulses. This method works as a low pass filter.
  82. edgeTimeStamp[1] = edgeTimeStamp[2];
  83. edgeTimeStamp[2] = micros();
  84. if (skip) {
  85. skip = false;
  86. return;
  87. }
  88. if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) {
  89. // Last edge was too short.
  90. // Skip this edge, and the next too.
  91. skip = true;
  92. return;
  93. }
  94. unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0];
  95. edgeTimeStamp[0] = edgeTimeStamp[1];
  96. // Note that if state>=0, duration is always >= 1 period.
  97. if (_state == -1) {
  98. // wait for the long low part of a stop bit.
  99. // Stopbit: 1T high, 40T low
  100. // By default 1T is 260µs, but for maximum compatibility go as low as 120µs
  101. if (duration > 4800 && duration < 15000) { // =40*120µs, minimal time between two edges before decoding starts.
  102. // Sync signal received.. Preparing for decoding
  103. repeats = 0;
  104. receivedCode.period = duration / 40; // Measured signal is 40T, so 1T (period) is measured signal / 40.
  105. // Allow for large error-margin. ElCheapo-hardware :(
  106. min1Period = receivedCode.period * 3 / 10; // Lower limit for 1 period is 0.3 times measured period; high signals can "linger" a bit sometimes, making low signals quite short.
  107. max1Period = receivedCode.period * 3; // Upper limit for 1 period is 3 times measured period
  108. min5Period = receivedCode.period * 3; // Lower limit for 5 periods is 3 times measured period
  109. max5Period = receivedCode.period * 8; // Upper limit for 5 periods is 8 times measured period
  110. }
  111. else {
  112. return;
  113. }
  114. } else if (_state == 0) { // Verify start bit part 1 of 2
  115. // Duration must be ~1T
  116. if (duration > max1Period) {
  117. RESET_STATE;
  118. return;
  119. }
  120. // Start-bit passed. Do some clean-up.
  121. receivedCode.address = receivedCode.unit = receivedCode.dimLevel = 0;
  122. } else if (_state == 1) { // Verify start bit part 2 of 2
  123. // Duration must be ~10.44T
  124. // Position wird nicht erreicht
  125. // SFL
  126. //
  127. // digitalWrite(LED_BUILTIN, HIGH);// turning LED on
  128. //
  129. //
  130. if (duration < 7 * receivedCode.period || duration > 15 * receivedCode.period) {
  131. RESET_STATE;
  132. return;
  133. }
  134. } else if (_state < 148) { // state 146 is first edge of stop-sequence. All bits before that adhere to default protocol, with exception of dim-bit
  135. receivedBit <<= 1;
  136. // Position wird nicht erreicht
  137. // SFL
  138. //
  139. // digitalWrite(LED_BUILTIN, HIGH);// turning LED on
  140. //
  141. //
  142. // One bit consists out of 4 bit parts.
  143. // bit part durations can ONLY be 1 or 5 periods.
  144. if (duration <= max1Period) {
  145. receivedBit &= B1110; // Clear LSB of receivedBit
  146. } else if (duration >= min5Period && duration <= max5Period) {
  147. receivedBit |= B1; // Set LSB of receivedBit
  148. } else if (
  149. // Check if duration matches the second part of stopbit (duration must be ~40T), and ...
  150. (duration >= 20 * receivedCode.period && duration <= 80 * receivedCode.period) &&
  151. // if first part op stopbit was a short signal (short signal yielded a 0 as second bit in receivedBit), and ...
  152. ((receivedBit & B10) == B00) &&
  153. // we are in a state in which a stopbit is actually valid, only then ...
  154. (_state == 147 || _state == 131) ) {
  155. // If a dim-level was present...
  156. if (_state == 147) {
  157. // mark received switch signal as signal-with-dim
  158. receivedCode.dimLevelPresent = true;
  159. }
  160. // a valid signal was found!
  161. if (
  162. receivedCode.address != previousCode.address ||
  163. receivedCode.unit != previousCode.unit ||
  164. receivedCode.dimLevelPresent != previousCode.dimLevelPresent ||
  165. receivedCode.dimLevel != previousCode.dimLevel ||
  166. receivedCode.groupBit != previousCode.groupBit ||
  167. receivedCode.switchType != previousCode.switchType
  168. ) { // memcmp isn't deemed safe
  169. repeats=0;
  170. previousCode = receivedCode;
  171. }
  172. repeats++;
  173. if (repeats>=_minRepeats) {
  174. if (!_inCallback) {
  175. _inCallback = true;
  176. CALLBACK_SIGNATURE;
  177. _inCallback = false;
  178. }
  179. // Reset after callback.
  180. RESET_STATE;
  181. return;
  182. }
  183. // Reset for next round
  184. _state=0; // no need to wait for another sync-bit!
  185. return;
  186. }
  187. else { // Otherwise the entire sequence is invalid
  188. RESET_STATE;
  189. return;
  190. }
  191. if (_state % 4 == 1) { // Last bit part? Note: this is the short version of "if ( (_state-2) % 4 == 3 )"
  192. // There are 3 valid options for receivedBit:
  193. // 0, indicated by short short short long == B0001.
  194. // 1, short long shot short == B0100.
  195. // dim, short shot short shot == B0000.
  196. // Everything else: inconsistent data, trash the whole sequence.
  197. if (_state < 106) {
  198. // States 2 - 105 are address bit states
  199. receivedCode.address <<= 1;
  200. // Decode bit. Only 4 LSB's of receivedBit are used; trim the rest.
  201. switch (receivedBit & B1111) {
  202. case B0001: // Bit "0" received.
  203. // receivedCode.address |= 0; But let's not do that, as it is wasteful.
  204. break;
  205. case B0100: // Bit "1" received.
  206. receivedCode.address |= 1;
  207. break;
  208. default: // Bit was invalid. Abort.
  209. RESET_STATE;
  210. return;
  211. }
  212. } else if (_state < 110) {
  213. // States 106 - 109 are group bit states.
  214. switch (receivedBit & B1111) {
  215. case B0001: // Bit "0" received.
  216. receivedCode.groupBit = false;
  217. break;
  218. case B0100: // Bit "1" received.
  219. receivedCode.groupBit = true;
  220. break;
  221. default: // Bit was invalid. Abort.
  222. RESET_STATE;
  223. return;
  224. }
  225. } else if (_state < 114) {
  226. // States 110 - 113 are switch bit states.
  227. switch (receivedBit & B1111) {
  228. case B0001: // Bit "0" received.
  229. receivedCode.switchType = NewRemoteCode::off;
  230. break;
  231. case B0100: // Bit "1" received. Note: this might turn out to be a on_with_dim signal.
  232. receivedCode.switchType = NewRemoteCode::on;
  233. break;
  234. case B0000: // Bit "dim" received.
  235. receivedCode.switchType = NewRemoteCode::dim;
  236. break;
  237. default: // Bit was invalid. Abort.
  238. RESET_STATE;
  239. return;
  240. }
  241. } else if (_state < 130){
  242. // States 114 - 129 are unit bit states.
  243. receivedCode.unit <<= 1;
  244. // Decode bit.
  245. switch (receivedBit & B1111) {
  246. case B0001: // Bit "0" received.
  247. // receivedCode.unit |= 0; But let's not do that, as it is wasteful.
  248. break;
  249. case B0100: // Bit "1" received.
  250. receivedCode.unit |= 1;
  251. break;
  252. default: // Bit was invalid. Abort.
  253. RESET_STATE;
  254. return;
  255. }
  256. } else if (_state < 146) {
  257. // States 130 - 145 are dim bit states.
  258. // Depending on hardware, these bits can be present, even if switchType is NewRemoteCode::on or NewRemoteCode::off
  259. receivedCode.dimLevel <<= 1;
  260. // Decode bit.
  261. switch (receivedBit & B1111) {
  262. case B0001: // Bit "0" received.
  263. // receivedCode.dimLevel |= 0; But let's not do that, as it is wasteful.
  264. break;
  265. case B0100: // Bit "1" received.
  266. receivedCode.dimLevel |= 1;
  267. break;
  268. default: // Bit was invalid. Abort.
  269. RESET_STATE;
  270. return;
  271. }
  272. }
  273. }
  274. }
  275. _state++;
  276. digitalWrite(LED_BUILTIN, LOW);// turning LED off
  277. return;
  278. }
  279. boolean NewRemoteReceiver::isReceiving(int waitMillis) {
  280. unsigned long startTime=millis();
  281. int waited; // Signed int!
  282. do {
  283. if (_state >= 34) { // Abort if a significant part of a code (start pulse + 8 bits) has been received
  284. return true;
  285. }
  286. waited = (millis()-startTime);
  287. } while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time.
  288. return false;
  289. }