Fork of the espurna firmware for `mhsw` switches
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.

158 lines
4.4 KiB

  1. /*
  2. * RemoteSwitch library v2.0.0 made by Randy Simons http://randysimons.nl
  3. * See RemoteSwitchSender.h for details.
  4. *
  5. * License: "Free BSD license". See license.txt
  6. */
  7. #include "RemoteReceiver.h"
  8. /************
  9. * RemoteReceiver
  10. ************/
  11. unsigned short RemoteReceiver::_interrupt;
  12. volatile int RemoteReceiver::_state;
  13. unsigned short RemoteReceiver::_minRepeats;
  14. RemoteReceiverCallBack RemoteReceiver::_callback;
  15. boolean RemoteReceiver::_inCallback = false;
  16. void RemoteReceiver::init(unsigned short interrupt, unsigned short minRepeats, RemoteReceiverCallBack callback) {
  17. _interrupt = interrupt;
  18. _minRepeats = minRepeats;
  19. _callback = callback;
  20. //enable();
  21. }
  22. void RemoteReceiver::enable() {
  23. _state = -1;
  24. attachInterrupt(_interrupt, interruptHandler, CHANGE);
  25. }
  26. void RemoteReceiver::disable() {
  27. detachInterrupt(_interrupt);
  28. }
  29. void RemoteReceiver::interruptHandler() {
  30. static unsigned int period; //Calculated duration of 1 period
  31. static unsigned short receivedBit; //Contains "bit" currently receiving
  32. static unsigned long receivedCode; //Contains received code
  33. static unsigned long previousCode; //Contains previous received code
  34. static unsigned short repeats = 0; //The number of times the an identical code is received in a row.
  35. static unsigned long lastChange=0; //Timestamp of previous edge
  36. static unsigned int min1Period, max1Period, min3Period, max3Period;
  37. unsigned long currentTime=micros();
  38. unsigned int duration=currentTime-lastChange; //Duration = Time between edges
  39. lastChange=currentTime;
  40. if (_state==-1) { //Waiting for sync-signal
  41. if (duration>3720) { //==31*120 minimal time between two edges before decoding starts.
  42. //Sync signal received.. Preparing for decoding
  43. period=duration/31;
  44. receivedCode=previousCode=repeats=0;
  45. //Allow for large error-margin. ElCheapo-hardware :(
  46. min1Period=period*4/10; //Avoid floating point math; saves memory.
  47. max1Period=period*16/10;
  48. min3Period=period*23/10;
  49. max3Period=period*37/10;
  50. }
  51. else {
  52. return;
  53. }
  54. } else if (_state<48) { //Decoding message
  55. //bit part durations can ONLY be 1 or 3 periods.
  56. if (duration>=min1Period && duration<=max1Period) {
  57. bitClear(receivedBit,_state%4); //Note: this sets the bits in reversed order! Correct order would be: 3-(_state%4), but that's overhead we don't want.
  58. }
  59. else if (duration>=min3Period && duration<=max3Period) {
  60. bitSet(receivedBit,_state%4); //Note: this sets the bits in reversed order!
  61. }
  62. else { //Otherwise the entire sequence is invalid
  63. _state=-1;
  64. return;
  65. }
  66. if ((_state%4)==3) { //Last bit part?
  67. //Shift
  68. receivedCode*=3;
  69. //Decode bit.
  70. if (receivedBit==B1010) { //short long short long == B0101, but bits are set in reversed order, so compare to B1010
  71. //bit "0" received
  72. receivedCode+=0; //I hope the optimizer handles this ;)
  73. }
  74. else if (receivedBit==B0101) { //long short long short == B101, but bits are set in reversed order, so compare to B0101
  75. //bit "1" received
  76. receivedCode+=1;
  77. }
  78. else if (receivedBit==B0110) { //short long long short. Reversed too, but makes no difference.
  79. //bit "f" received
  80. receivedCode+=2;
  81. }
  82. else {
  83. //Bit was rubbish. Abort.
  84. _state=-1;
  85. return;
  86. }
  87. }
  88. } else if (_state==48) { //Waiting for sync bit part 1
  89. //Must be 1 period.
  90. if (duration<min1Period || duration>max1Period) {
  91. _state=-1;
  92. return;
  93. }
  94. } else { //Waiting for sync bit part 2
  95. //Must be 31 periods.
  96. if (duration<period*25 || duration>period*36) {
  97. _state=-1;
  98. return;
  99. }
  100. //receivedCode is a valid code!
  101. if (receivedCode!=previousCode) {
  102. repeats=0;
  103. previousCode=receivedCode;
  104. }
  105. repeats++;
  106. if (repeats>=_minRepeats) {
  107. if (!_inCallback) {
  108. _inCallback = true;
  109. (_callback)(receivedCode, period);
  110. _inCallback = false;
  111. }
  112. //Reset after callback.
  113. _state=-1;
  114. return;
  115. }
  116. //Reset for next round
  117. receivedCode = 0;
  118. _state=0; //no need to wait for another sync-bit!
  119. return;
  120. }
  121. _state++;
  122. return;
  123. }
  124. boolean RemoteReceiver::isReceiving(int waitMillis) {
  125. unsigned long startTime=millis();
  126. int waited; //signed int!
  127. do {
  128. if (_state!=-1) {
  129. return true;
  130. }
  131. waited = (millis()-startTime);
  132. } while(waited>=0 && waited <= waitMillis); //Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time.
  133. return false;
  134. }