esic.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #include "esic.h"
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include "esp_log.h"
  5. #include "../rxTimer.h"
  6. #include "config.h"
  7. #ifdef TRANCEIVER_ENABLED
  8. /**
  9. **********************************************************************************
  10. * TEMP 3
  11. * ESIC WT450H
  12. +---+ +---+ +-------+ + high
  13. | | | | | | |
  14. | | | | | | |
  15. + +---+ +---+ +-------+ low
  16. ^ ^ ^ ^ ^ clock cycle
  17. | 1 | 1 | 0 | 0 | translates as
  18. Each transmission is 36 bits long (i.e. 72 ms)
  19. .short_width = 976, // half-bit width 976 us
  20. .long_width = 1952, // bit width 1952 us
  21. Data is transmitted in pure binary values, NOT BCD-coded.
  22. Example transmission (House 1, Channel 1, RH 59 %, Temperature 23.5 �C)
  23. 1100 00010011001110110100100110011000
  24. b00 - b03 (4 bits): Constant, 1100, probably preamble
  25. b04 - b07 (4 bits): House code (here: 0001 = HC 1)
  26. b08 - b09 (2 bits): Channel code - 1 (here 00 = CC 1)
  27. b10 - b12 (3 bits): Constant, 110
  28. b13 - b19 (7 bits): Relative humidity (here 0111011 = 59 %)
  29. b20 - b34 (15 bits): Temperature (see below)
  30. b35 - b35 (1 bit) : Parity (xor of all bits should give 0)
  31. The temperature is transmitted as (temp + 50.0) * 128,
  32. which equals (temp * 128) + 6400. Adding 50.0 �C makes
  33. all values positive, an unsigned 15 bit integer where the
  34. first 8 bits correspond to the whole part of the temperature
  35. (here 01001001, decimal 73, substract 50 = 23).
  36. Remaining 7 bits correspond to the fractional part.
  37. To avoid floating point calculations I store the raw temperature value
  38. as a signed integer in the variable esicTemp, then transform it to
  39. actual temperature * 10 using "esicTemp = (esicTemp - 6400) * 10 / 128",
  40. where 6400 is the added 50 times 128.
  41. When reporting the temperature I simply print "esicTemp / 10" (integer division,
  42. no fraction), followed by a decimal point and "esicTemp % 10" (remainder, which
  43. equals first fractional decimal digit).
  44. Summary of bit fields:
  45. 1100 0001 00 110 0111011 010010011001100 0
  46. c1 hc cc c2 rh t p
  47. c1, c2 = constant field 1 and 2
  48. hc, cc = house code and channel code
  49. rh, t = relative humidity, temperature
  50. p = parity bit 1111111111111110
  51. This interpretation is from: https://github.com/merbanan/rtl_433/blob/master/src/devices/wt450.c
  52. 1100 0001 | 0011 0011 | 1000 0011 | 1011 0011 | 0001
  53. xxxx ssss | ccxx bhhh | hhhh tttt | tttt tttt | sseo
  54. - x: constant
  55. - s: House code
  56. - c: Channel
  57. - b: battery low indicator (0=>OK, 1=>LOW)
  58. - h: Humidity
  59. - t: Temperature, 12 bit, offset 50, scale 16
  60. - s: sequence number of message repeat
  61. - e: parity of all even bits
  62. - o: parity of all odd bits
  63. **********************************************************************************
  64. */
  65. volatile unsigned long long temp3_x_data;
  66. void ESIC_ResetDecoder() {
  67. temp3_x_data = 0;
  68. }
  69. #define NO_OF_PULSES 60
  70. #define max(a,b) (((a)>(b))?(a):(b))
  71. #define isShortPulse(width) (((long_pulse/2)-maxDiff) <= width && width <= ((long_pulse/2)+maxDiff))
  72. #define isLongPulse(width) ((long_pulse-maxDiff) <= width && width <= (long_pulse+maxDiff))
  73. unsigned int temp3_pulses[NO_OF_PULSES];
  74. static int long_pulse = 1955;
  75. static int maxDiff = 300;
  76. static void storePulses(unsigned int inWidth) {
  77. int i;
  78. // Shift pulses down
  79. for(i=1;i<NO_OF_PULSES;i++) {
  80. temp3_pulses[i-1] = temp3_pulses[i];
  81. }
  82. temp3_pulses[NO_OF_PULSES-1] = inWidth;
  83. }
  84. static void sweepForNoise() {
  85. // If we have a short pulse in position 2
  86. // Then add together pos 1,2 and 3 if they are a valid pulse
  87. // This way we can handle one single noise pulse in a real pulse
  88. if( temp3_pulses[NO_OF_PULSES-2] < ((long_pulse/2)-maxDiff) ) {
  89. int totPulse = temp3_pulses[NO_OF_PULSES-1]+temp3_pulses[NO_OF_PULSES-2]+temp3_pulses[NO_OF_PULSES-3];
  90. if( isShortPulse(totPulse) || isLongPulse(totPulse) ) {
  91. // Store new pulse in last position
  92. temp3_pulses[NO_OF_PULSES-1] = totPulse;
  93. // Move everything up again
  94. for(int i=NO_OF_PULSES-2;i>1;i--) {
  95. temp3_pulses[i] = temp3_pulses[i-2];
  96. }
  97. temp3_pulses[0] = 0;
  98. temp3_pulses[1] = 0;
  99. }
  100. }
  101. }
  102. /*static void adjustTiming() {
  103. int p1 = temp3_pulses[NO_OF_PULSES-8];
  104. int p2 = temp3_pulses[NO_OF_PULSES-7];
  105. int p3 = temp3_pulses[NO_OF_PULSES-6];
  106. int p4 = temp3_pulses[NO_OF_PULSES-5];
  107. int p5 = temp3_pulses[NO_OF_PULSES-4];
  108. int p6 = temp3_pulses[NO_OF_PULSES-3];
  109. int p7 = temp3_pulses[NO_OF_PULSES-2];
  110. int p8 = temp3_pulses[NO_OF_PULSES-1];
  111. // Check max differance between the short pulses
  112. int sh_mean = (p1+p2+p3+p4) / 4;
  113. int sh_max_diff = max(max(abs(p1-sh_mean),abs(p2-sh_mean)),max(abs(p3-sh_mean),abs(p4-sh_mean)));
  114. // Check max differance between the long pulses
  115. int long_mean = (p5+p6+p7+p8) / 4;
  116. int long_max_diff = max(max(abs(p5-long_mean),abs(p6-long_mean)),max(abs(p7-long_mean),abs(p8-long_mean)));
  117. if( sh_max_diff < maxDiff && long_max_diff < maxDiff ) {
  118. int mean = (long_mean + sh_mean)/2;
  119. if( long_mean > (mean+maxDiff) && sh_mean < (mean-maxDiff) ) {
  120. if( abs(long_mean - (sh_mean*2)) < maxDiff ) {
  121. long_pulse = (long_mean + sh_mean*2)/2;
  122. maxDiff = long_mean / 15;
  123. }
  124. }
  125. }
  126. }*/
  127. // The latest/newest pulse is at the end of the array [59]
  128. // This ([59]) is the latest bit in the bit-stream from the transmitter
  129. // This is way we input the bits at a high position and shift them towards lower values
  130. // So..start reading backwards and working towards the first/highest bits
  131. static int checkPulsePattern() {
  132. int i = NO_OF_PULSES-1; // Start reading from the last received (end of array)
  133. int b = 0;
  134. unsigned long long code = 0;
  135. while( i >= 0 ) {
  136. int combWidth = temp3_pulses[i] + temp3_pulses[i-1];
  137. if( isLongPulse(temp3_pulses[i]) ) {
  138. b++;
  139. i-=1;
  140. code = code >> 1;
  141. }
  142. else if( isShortPulse(temp3_pulses[i]) && isShortPulse(temp3_pulses[i-1]) ) {
  143. b++;
  144. i-=2;
  145. code = ((code >> 1) | 0x200000000);
  146. }
  147. else if( isLongPulse( combWidth ) ) {
  148. b++;
  149. i-=2;
  150. code = ((code >> 1) | 0x200000000);
  151. }
  152. else {
  153. return -1;
  154. }
  155. if( b == 34 ) {
  156. /*
  157. 0000 0001 00 110 0101000 010010110101000 1
  158. AND: 0011 1111 00 111 0000000 000000000000000 0 = 001111110011100000000000000000000000 = 0x3F3800000
  159. RES: 0000 0001 00 110 0000000 000000000000000 0 = 000000010011000000000000000000000000 = 0x013000000
  160. Summary of bit fields:
  161. 1100 0001 00 110 0111011 010010011001100 0
  162. c1 hc cc c2 rh t p
  163. */
  164. if( (code & 0x3F3800000) == 0x013000000 ) {
  165. temp3_x_data = (code&0xFFFFFFFF);
  166. // Check parity
  167. int even=0;
  168. unsigned long long data = temp3_x_data;
  169. for(int i=0;i<32;i++) {
  170. if( data & 1 ) even++;
  171. data >>= 1;
  172. }
  173. if( even % 2 != 0 ) {
  174. temp3_x_data = 0;
  175. printf("Wrong parity\n");
  176. return -1;
  177. }
  178. // A correct code has been received
  179. //printf("Code received: %llu on row:%d\n",(code&0xFFFFFFFF),row_no);
  180. temp3_x_data &= 0xFFFFFFF0; // Remove sequence and parity bits in lowest nibble
  181. return 1;
  182. }
  183. else {
  184. return -1;
  185. }
  186. }
  187. }
  188. return 0;
  189. }
  190. static int temp3decode (unsigned int inWidth) {
  191. int width = inWidth; //preProcessPulses(inWidth);
  192. if( width == -1 ) return -1;
  193. if( width == 0 ) return 0;
  194. storePulses(inWidth);
  195. sweepForNoise();
  196. //adjustTiming();
  197. return checkPulsePattern();
  198. }
  199. int64_t nextPulseESICSensor(uint32_t width) {
  200. static int64_t previous_data = 0;
  201. static uint32_t old_time=0;
  202. static uint32_t now;
  203. int64_t retVal = -1;
  204. if( width > 0 ) {
  205. if( temp3_x_data == 0 ) {
  206. temp3decode(width);
  207. }
  208. }
  209. if( temp3_x_data > 0 ) {
  210. now = millis();
  211. if( temp3_x_data != previous_data || (now > (old_time+1000)) ) {
  212. previous_data = temp3_x_data;
  213. retVal = temp3_x_data;
  214. }
  215. old_time = now;
  216. ESIC_ResetDecoder();
  217. }
  218. return retVal;
  219. }
  220. #endif