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.

263 lines
6.3 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 "RemoteSwitch.h"
  8. /************
  9. * RemoteSwitch
  10. ************/
  11. RemoteSwitch::RemoteSwitch(unsigned short pin, unsigned int periodusec, unsigned short repeats) {
  12. _pin=pin;
  13. _periodusec=periodusec;
  14. _repeats=repeats;
  15. pinMode(_pin, OUTPUT);
  16. }
  17. unsigned long RemoteSwitch::encodeTelegram(unsigned short trits[]) {
  18. unsigned long data = 0;
  19. //Encode data
  20. for (unsigned short i=0;i<12;i++) {
  21. data*=3;
  22. data+=trits[i];
  23. }
  24. //Encode period duration
  25. data |= (unsigned long)_periodusec << 23;
  26. //Encode repeats
  27. data |= (unsigned long)_repeats << 20;
  28. return data;
  29. }
  30. void RemoteSwitch::sendTelegram(unsigned short trits[]) {
  31. sendTelegram(encodeTelegram(trits),_pin);
  32. }
  33. /**
  34. * Format data:
  35. * pppppppp|prrrdddd|dddddddd|dddddddd (32 bit)
  36. * p = perioud (9 bit unsigned int
  37. * r = repeats as 2log. Thus, if r = 3, then signal is sent 2^3=8 times
  38. * d = data
  39. */
  40. void RemoteSwitch::sendTelegram(unsigned long data, unsigned short pin) {
  41. unsigned int periodusec = (unsigned long)data >> 23;
  42. unsigned short repeats = 1 << (((unsigned long)data >> 20) & B111);
  43. data = data & 0xfffff; //truncate to 20 bit
  44. //Convert the base3-code to base4, to avoid lengthy calculations when transmitting.. Messes op timings.
  45. unsigned long dataBase4 = 0;
  46. for (unsigned short i=0; i<12; i++) {
  47. dataBase4<<=2;
  48. dataBase4|=(data%3);
  49. data/=3;
  50. }
  51. for (unsigned short int j=0;j<repeats;j++) {
  52. //Sent one telegram
  53. //Use data-var as working var
  54. data=dataBase4;
  55. for (unsigned short i=0; i<12; i++) {
  56. switch (data & B11) {
  57. case 0:
  58. digitalWrite(pin, HIGH);
  59. delayMicroseconds(periodusec);
  60. digitalWrite(pin, LOW);
  61. delayMicroseconds(periodusec*3);
  62. digitalWrite(pin, HIGH);
  63. delayMicroseconds(periodusec);
  64. digitalWrite(pin, LOW);
  65. delayMicroseconds(periodusec*3);
  66. break;
  67. case 1:
  68. digitalWrite(pin, HIGH);
  69. delayMicroseconds(periodusec*3);
  70. digitalWrite(pin, LOW);
  71. delayMicroseconds(periodusec);
  72. digitalWrite(pin, HIGH);
  73. delayMicroseconds(periodusec*3);
  74. digitalWrite(pin, LOW);
  75. delayMicroseconds(periodusec);
  76. break;
  77. case 2: //AKA: X or float
  78. digitalWrite(pin, HIGH);
  79. delayMicroseconds(periodusec);
  80. digitalWrite(pin, LOW);
  81. delayMicroseconds(periodusec*3);
  82. digitalWrite(pin, HIGH);
  83. delayMicroseconds(periodusec*3);
  84. digitalWrite(pin, LOW);
  85. delayMicroseconds(periodusec);
  86. break;
  87. }
  88. //Next trit
  89. data>>=2;
  90. }
  91. //Send termination/synchronisation-signal. Total length: 32 periods
  92. digitalWrite(pin, HIGH);
  93. delayMicroseconds(periodusec);
  94. digitalWrite(pin, LOW);
  95. delayMicroseconds(periodusec*31);
  96. }
  97. }
  98. boolean RemoteSwitch::isSameCode(unsigned long encodedTelegram, unsigned long receivedData) {
  99. return (receivedData==(encodedTelegram & 0xFFFFF)); //Compare the 20 LSB's
  100. }
  101. /************
  102. * ActionSwitch
  103. ************/
  104. ActionSwitch::ActionSwitch(unsigned short pin, unsigned int periodusec) : RemoteSwitch(pin,periodusec,3) {
  105. //Call contructor
  106. }
  107. void ActionSwitch::sendSignal(unsigned short systemCode, char device, boolean on) {
  108. sendTelegram(getTelegram(systemCode,device,on), _pin);
  109. }
  110. unsigned long ActionSwitch::getTelegram(unsigned short systemCode, char device, boolean on) {
  111. unsigned short trits[12];
  112. device-=65;
  113. for (unsigned short i=0; i<5; i++) {
  114. //bits 0-4 contain address (2^5=32 addresses)
  115. trits[i]=(systemCode & 1)?1:2;
  116. systemCode>>=1;
  117. //bits 5-9 contain device. Only one trit has value 0, others have 2 (float)!
  118. trits[i+5]=(i==device?0:2);
  119. }
  120. //switch on or off
  121. trits[10]=(!on?0:2);
  122. trits[11]=(on?0:2);
  123. return encodeTelegram(trits);
  124. }
  125. /************
  126. * BlokkerSwitch
  127. ************/
  128. BlokkerSwitch::BlokkerSwitch(unsigned short pin, unsigned int periodusec) : RemoteSwitch(pin,periodusec,3) {
  129. //Call contructor
  130. }
  131. void BlokkerSwitch::sendSignal(unsigned short device, boolean on) {
  132. sendTelegram(getTelegram(device,on), _pin);
  133. }
  134. unsigned long BlokkerSwitch::getTelegram(unsigned short device, boolean on) {
  135. unsigned short trits[12]={0};
  136. device--;
  137. for (unsigned short i=1; i<4; i++) {
  138. //Bits 1-3 contain device
  139. trits[i]=(device & 1)?0:1;
  140. device>>=1;
  141. }
  142. //switch on or off
  143. trits[8]=(on?1:0);
  144. return encodeTelegram(trits);
  145. }
  146. /************
  147. * KaKuSwitch
  148. ************/
  149. KaKuSwitch::KaKuSwitch(unsigned short pin, unsigned int periodusec) : RemoteSwitch(pin,periodusec,3) {
  150. //Call contructor
  151. }
  152. void KaKuSwitch::sendSignal(char address, unsigned short device, boolean on) {
  153. sendTelegram(getTelegram(address, device, on), _pin);
  154. }
  155. unsigned long KaKuSwitch::getTelegram(char address, unsigned short device, boolean on) {
  156. unsigned short trits[12];
  157. address-=65;
  158. device-=1;
  159. for (unsigned short i=0; i<4; i++) {
  160. //bits 0-3 contain address (2^4 = 16 addresses)
  161. trits[i]=(address & 1)?2:0;
  162. address>>=1;
  163. //bits 4-8 contain device (2^4 = 16 addresses)
  164. trits[i+4]=(device & 1)?2:0;
  165. device>>=1;
  166. }
  167. //bits 8-10 seem to be fixed
  168. trits[8]=0;
  169. trits[9]=2;
  170. trits[10]=2;
  171. //switch on or off
  172. trits[11]=(on?2:0);
  173. return encodeTelegram(trits);
  174. }
  175. void KaKuSwitch::sendSignal(char address, unsigned short group, unsigned short device, boolean on) {
  176. sendTelegram(getTelegram(address, group, on), _pin);
  177. }
  178. unsigned long KaKuSwitch::getTelegram(char address, unsigned short group, unsigned short device, boolean on) {
  179. unsigned short trits[12], i;
  180. address-=65;
  181. group-=1;
  182. device-=1;
  183. //address. M3E Pin A0-A3
  184. for (i=0; i<4; i++) {
  185. //bits 0-3 contain address (2^4 = 16 addresses)
  186. trits[i]=(address & 1)?2:0;
  187. address>>=1;
  188. }
  189. //device. M3E Pin A4-A5
  190. for (; i<6; i++) {
  191. trits[i]=(device & 1)?2:0;
  192. device>>=1;
  193. }
  194. //group. M3E Pin A6-A7
  195. for (; i<8; i++) {
  196. trits[i]=(group & 1)?2:0;
  197. group>>=1;
  198. }
  199. //bits 8-10 are be fixed. M3E Pin A8/D0-A10/D2
  200. trits[8]=0;
  201. trits[9]=2;
  202. trits[10]=2;
  203. //switch on or off, M3E Pin A11/D3
  204. trits[11]=(on?2:0);
  205. return encodeTelegram(trits);
  206. }