BrickUp API Service for Docker version.

IRSendRev.cpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. * IRremote
  3. * Version 0.11 August, 2009
  4. * Copyright 2009 Ken Shirriff
  5. * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
  6. *
  7. * Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
  8. * Modified by Mitra Ardron <mitra@mitra.biz>
  9. * Added Sanyo and Mitsubishi controllers
  10. * Modified Sony to spot the repeat codes that some Sony's send
  11. *
  12. * Modifier by
  13. * Interrupt code based on NECIRrcv by Joe Knapp
  14. * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
  15. * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
  16. *
  17. * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
  18. */
  19. #include "IRSendRev.h"
  20. #include "IRSendRevInt.h"
  21. // Provides ISR
  22. #include <avr/interrupt.h>
  23. volatile irparams_t irparams;
  24. void IRSendRev::sendRaw(unsigned int buf[], int len, int hz)
  25. {
  26. enableIROut(hz);
  27. for (int i = 0; i < len; i++) {
  28. if (i & 1) {
  29. space(buf[i]);
  30. }
  31. else {
  32. mark(buf[i]);
  33. }
  34. }
  35. space(0); // Just to be sure
  36. }
  37. void IRSendRev::mark(int time) {
  38. // Sends an IR mark for the specified number of microseconds.
  39. // The mark output is modulated at the PWM frequency.
  40. TIMER_ENABLE_PWM; // Enable pin 3 PWM output
  41. delayMicroseconds(time);
  42. }
  43. /* Leave pin off for time (given in microseconds) */
  44. void IRSendRev::space(int time) {
  45. // Sends an IR space for the specified number of microseconds.
  46. // A space is no output, so the PWM output is disabled.
  47. TIMER_DISABLE_PWM; // Disable pin 3 PWM output
  48. delayMicroseconds(time);
  49. }
  50. void IRSendRev::enableIROut(int khz) {
  51. // Enables IR output. The khz value controls the modulation frequency in kilohertz.
  52. // The IR output will be on pin 3 (OC2B).
  53. // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
  54. // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
  55. // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
  56. // controlling the duty cycle.
  57. // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
  58. // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
  59. // A few hours staring at the ATmega documentation and this will all make sense.
  60. // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
  61. // Disable the Timer2 Interrupt (which is used for receiving IR)
  62. TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
  63. pinMode(TIMER_PWM_PIN, OUTPUT);
  64. digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
  65. TIMER_CONFIG_KHZ(khz);
  66. TIMER_ENABLE_PWM;
  67. }
  68. void IRSendRev::Init(int revPin)
  69. {
  70. irparams.recvpin = revPin;
  71. enableIRIn(); // Start the receiver
  72. delay(20);
  73. Clear();
  74. }
  75. void IRSendRev::Init()
  76. {
  77. delay(20);
  78. Clear();
  79. }
  80. // initialization
  81. void IRSendRev::enableIRIn() {
  82. cli();
  83. // setup pulse clock timer interrupt
  84. //Prescale /8 (16M/8 = 0.5 microseconds per tick)
  85. // Therefore, the timer interval can range from 0.5 to 128 microseconds
  86. // depending on the reset value (255 to 0)
  87. TIMER_CONFIG_NORMAL();
  88. //Timer2 Overflow Interrupt Enable
  89. TIMER_ENABLE_INTR;
  90. TIMER_RESET;
  91. sei(); // enable interrupts
  92. // initialize state machine variables
  93. irparams.rcvstate = STATE_IDLE;
  94. irparams.rawlen = 0;
  95. // set pin modes
  96. pinMode(irparams.recvpin, INPUT);
  97. }
  98. // TIMER2 interrupt code to collect raw data.
  99. // Widths of alternating SPACE, MARK are recorded in rawbuf.
  100. // Recorded in ticks of 50 microseconds.
  101. // rawlen counts the number of entries recorded so far.
  102. // First entry is the SPACE between transmissions.
  103. // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
  104. // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
  105. ISR(TIMER_INTR_NAME)
  106. {
  107. TIMER_RESET;
  108. uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
  109. irparams.timer++; // One more 50us tick
  110. if (irparams.rawlen >= RAWBUF) {
  111. // Buffer overflow
  112. irparams.rcvstate = STATE_STOP;
  113. }
  114. switch(irparams.rcvstate) {
  115. case STATE_IDLE: // In the middle of a gap
  116. if (irdata == MARK) {
  117. if (irparams.timer < GAP_TICKS) {
  118. // Not big enough to be a gap.
  119. irparams.timer = 0;
  120. }
  121. else {
  122. // gap just ended, record duration and start recording transmission
  123. irparams.rawlen = 0;
  124. irparams.rawbuf[irparams.rawlen++] = irparams.timer;
  125. irparams.timer = 0;
  126. irparams.rcvstate = STATE_MARK;
  127. }
  128. }
  129. break;
  130. case STATE_MARK: // timing MARK
  131. if (irdata == SPACE) { // MARK ended, record time
  132. irparams.rawbuf[irparams.rawlen++] = irparams.timer;
  133. irparams.timer = 0;
  134. irparams.rcvstate = STATE_SPACE;
  135. }
  136. break;
  137. case STATE_SPACE: // timing SPACE
  138. if (irdata == MARK) { // SPACE just ended, record it
  139. irparams.rawbuf[irparams.rawlen++] = irparams.timer;
  140. irparams.timer = 0;
  141. irparams.rcvstate = STATE_MARK;
  142. }
  143. else { // SPACE
  144. if (irparams.timer > GAP_TICKS) {
  145. // big SPACE, indicates gap between codes
  146. // Mark current code as ready for processing
  147. // Switch to STOP
  148. // Don't reset timer; keep counting space width
  149. irparams.rcvstate = STATE_STOP;
  150. }
  151. }
  152. break;
  153. case STATE_STOP: // waiting, measuring gap
  154. if (irdata == MARK) { // reset gap timer
  155. irparams.timer = 0;
  156. }
  157. break;
  158. }
  159. }
  160. void IRSendRev::Clear() {
  161. irparams.rcvstate = STATE_IDLE;
  162. irparams.rawlen = 0;
  163. }
  164. // Decodes the received IR message
  165. // Returns 0 if no data ready, 1 if data ready.
  166. // Results of decoding are stored in results
  167. int IRSendRev::decode(decode_results *results) {
  168. results->rawbuf = irparams.rawbuf;
  169. results->rawlen = irparams.rawlen;
  170. if (irparams.rcvstate != STATE_STOP) {
  171. return ERR;
  172. }
  173. // Throw away and start over
  174. Clear();
  175. return 1;
  176. }
  177. unsigned char IRSendRev::Recv(unsigned char *revData)
  178. {
  179. int count = results.rawlen;
  180. int nshort = 0;
  181. int nlong = 0;
  182. int count_data = 0;
  183. count_data = (count-4)/16;
  184. for(int i = 0; i<10; i++) // count nshort
  185. {
  186. nshort += results.rawbuf[3+2*i];
  187. }
  188. nshort /= 10;
  189. int i = 0;
  190. int j = 0;
  191. while(1) // count nlong
  192. {
  193. if(results.rawbuf[4+2*i] > (2*nshort))
  194. {
  195. nlong += results.rawbuf[4+2*i];
  196. j++;
  197. }
  198. i++;
  199. if(j==10)break;
  200. if((4+2*i)>(count-10))break;
  201. }
  202. nlong /= j;
  203. int doubleshort = 2*nshort;
  204. for(i = 0; i<count_data; i++)
  205. {
  206. revData[i+D_DATA] = 0x00;
  207. for(j = 0; j<8; j++)
  208. {
  209. if(results.rawbuf[4 + 16*i + j*2] > doubleshort) // 1
  210. {
  211. revData[i+D_DATA] |= 0x01<< (7-j);
  212. }
  213. else
  214. {
  215. revData[i+D_DATA] &= ~(0x01<<(7-j));
  216. }
  217. }
  218. }
  219. revData[D_LEN] = count_data+5;
  220. revData[D_STARTH] = results.rawbuf[1];
  221. revData[D_STARTL] = results.rawbuf[2];
  222. revData[D_SHORT] = nshort;
  223. revData[D_LONG] = nlong;
  224. revData[D_DATALEN] = count_data;
  225. #if __DEBUG
  226. Serial.print("\r\n*************************************************************\r\n");
  227. Serial.print("len\t = ");Serial.println(revData[D_LEN]);
  228. Serial.print("start_h\t = ");Serial.println(revData[D_STARTH]);
  229. Serial.print("start_l\t = ");Serial.println(revData[D_STARTL]);
  230. Serial.print("short\t = ");Serial.println(revData[D_SHORT]);
  231. Serial.print("long\t = ");Serial.println(revData[D_LONG]);
  232. Serial.print("data_len = ");Serial.println(revData[D_DATALEN]);
  233. for(int i = 0; i<revData[D_DATALEN]; i++)
  234. {
  235. Serial.print(revData[D_DATA+i]);Serial.print("\t");
  236. }
  237. Serial.print("\r\n*************************************************************\r\n");
  238. #endif
  239. Clear(); // Receive the next value
  240. return revData[D_LEN]+1;
  241. }
  242. //if get some data from IR
  243. unsigned char IRSendRev::IsDta()
  244. {
  245. if(decode(&results))
  246. {
  247. int count = results.rawlen;
  248. if(count < 20 || (count -4)%8 != 0)
  249. {
  250. #if __DEBUG
  251. Serial.print("IR GET BAD DATA!\r\n");
  252. #endif
  253. Clear(); // Receive the next value
  254. return 0;
  255. }
  256. int count_data = (count-4) / 16;
  257. #if __DEBUG
  258. Serial.print("ir get data! count_data = ");
  259. Serial.println(count_data);
  260. #endif
  261. return (unsigned char)(count_data+6);
  262. }
  263. else
  264. {
  265. return 0;
  266. }
  267. }
  268. void IRSendRev::Send(unsigned char *idata, unsigned char ifreq)
  269. {
  270. int len = idata[0];
  271. unsigned char start_high = idata[1];
  272. unsigned char start_low = idata[2];
  273. unsigned char nshort = idata[3];
  274. unsigned char nlong = idata[4];
  275. unsigned char datalen = idata[5];
  276. unsigned int *pSt = (unsigned int *)malloc((4+datalen*16)*sizeof(unsigned int));
  277. if(NULL == pSt)
  278. {
  279. #if __DEBUG
  280. Serial.println("not enough place!!\r\n");
  281. #endif
  282. exit(1);
  283. }
  284. #if __DEBUG
  285. Serial.println("begin to send ir:\r\n");
  286. Serial.print("ifreq = ");Serial.println(ifreq);
  287. Serial.print("len = ");Serial.println(len);
  288. Serial.print("start_high = ");Serial.println(start_high);
  289. Serial.print("start_low = ");Serial.println(start_low);
  290. Serial.print("nshort = ");Serial.println(nshort);
  291. Serial.print("nlong = ");Serial.println(nlong);
  292. Serial.print("datalen = ");Serial.println(datalen);
  293. #endif
  294. pSt[0] = start_high*50;
  295. pSt[1] = start_low*50;
  296. for(int i = 0; i<datalen; i++)
  297. {
  298. for(int j = 0; j<8; j++)
  299. {
  300. if(idata[6+i] & 0x01<<(7-j))
  301. {
  302. pSt[16*i + 2*j + 2] = nshort*50;
  303. pSt[16*i + 2*j+3] = nlong*50;
  304. }
  305. else
  306. {
  307. pSt[16*i + 2*j+2] = nshort*50;
  308. pSt[16*i + 2*j+3] = nshort*50;
  309. }
  310. }
  311. }
  312. pSt[2+datalen*16] = nshort*50;
  313. pSt[2+datalen*16+1] = nshort*50;
  314. #if __DEBUG
  315. for(int i = 0; i<4+datalen*16; i++)
  316. {
  317. Serial.print(pSt[i]);Serial.print("\t");
  318. }
  319. Serial.println();
  320. #endif
  321. sendRaw(pSt, 4+datalen*16, ifreq);
  322. free(pSt);
  323. }
  324. IRSendRev IR;