123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- /*
- * IRremote
- * Version 0.11 August, 2009
- * Copyright 2009 Ken Shirriff
- * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
- *
- * Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
- * Modified by Mitra Ardron <mitra@mitra.biz>
- * Added Sanyo and Mitsubishi controllers
- * Modified Sony to spot the repeat codes that some Sony's send
- *
- * Modifier by
- * Interrupt code based on NECIRrcv by Joe Knapp
- * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
- * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
- *
- * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
- */
- #include "IRSendRev.h"
- #include "IRSendRevInt.h"
- // Provides ISR
- #include <avr/interrupt.h>
- volatile irparams_t irparams;
- void IRSendRev::sendRaw(unsigned int buf[], int len, int hz)
- {
- enableIROut(hz);
- for (int i = 0; i < len; i++) {
- if (i & 1) {
- space(buf[i]);
- }
- else {
- mark(buf[i]);
- }
- }
- space(0); // Just to be sure
- }
- void IRSendRev::mark(int time) {
- // Sends an IR mark for the specified number of microseconds.
- // The mark output is modulated at the PWM frequency.
- TIMER_ENABLE_PWM; // Enable pin 3 PWM output
- delayMicroseconds(time);
- }
- /* Leave pin off for time (given in microseconds) */
- void IRSendRev::space(int time) {
- // Sends an IR space for the specified number of microseconds.
- // A space is no output, so the PWM output is disabled.
- TIMER_DISABLE_PWM; // Disable pin 3 PWM output
- delayMicroseconds(time);
- }
- void IRSendRev::enableIROut(int khz) {
- // Enables IR output. The khz value controls the modulation frequency in kilohertz.
- // The IR output will be on pin 3 (OC2B).
- // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
- // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
- // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
- // controlling the duty cycle.
- // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
- // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
- // A few hours staring at the ATmega documentation and this will all make sense.
- // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
- // Disable the Timer2 Interrupt (which is used for receiving IR)
- TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
-
- pinMode(TIMER_PWM_PIN, OUTPUT);
- digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
- TIMER_CONFIG_KHZ(khz);
- TIMER_ENABLE_PWM;
- }
- void IRSendRev::Init(int revPin)
- {
- irparams.recvpin = revPin;
-
- enableIRIn(); // Start the receiver
- delay(20);
- Clear();
- }
- void IRSendRev::Init()
- {
- delay(20);
- Clear();
- }
- // initialization
- void IRSendRev::enableIRIn() {
- cli();
- // setup pulse clock timer interrupt
- //Prescale /8 (16M/8 = 0.5 microseconds per tick)
- // Therefore, the timer interval can range from 0.5 to 128 microseconds
- // depending on the reset value (255 to 0)
- TIMER_CONFIG_NORMAL();
- //Timer2 Overflow Interrupt Enable
- TIMER_ENABLE_INTR;
- TIMER_RESET;
- sei(); // enable interrupts
- // initialize state machine variables
- irparams.rcvstate = STATE_IDLE;
- irparams.rawlen = 0;
- // set pin modes
- pinMode(irparams.recvpin, INPUT);
- }
- // TIMER2 interrupt code to collect raw data.
- // Widths of alternating SPACE, MARK are recorded in rawbuf.
- // Recorded in ticks of 50 microseconds.
- // rawlen counts the number of entries recorded so far.
- // First entry is the SPACE between transmissions.
- // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
- // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
- ISR(TIMER_INTR_NAME)
- {
- TIMER_RESET;
- uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
- irparams.timer++; // One more 50us tick
- if (irparams.rawlen >= RAWBUF) {
- // Buffer overflow
- irparams.rcvstate = STATE_STOP;
- }
- switch(irparams.rcvstate) {
- case STATE_IDLE: // In the middle of a gap
- if (irdata == MARK) {
- if (irparams.timer < GAP_TICKS) {
- // Not big enough to be a gap.
- irparams.timer = 0;
- }
- else {
- // gap just ended, record duration and start recording transmission
- irparams.rawlen = 0;
- irparams.rawbuf[irparams.rawlen++] = irparams.timer;
- irparams.timer = 0;
- irparams.rcvstate = STATE_MARK;
- }
- }
- break;
- case STATE_MARK: // timing MARK
- if (irdata == SPACE) { // MARK ended, record time
- irparams.rawbuf[irparams.rawlen++] = irparams.timer;
- irparams.timer = 0;
- irparams.rcvstate = STATE_SPACE;
- }
- break;
- case STATE_SPACE: // timing SPACE
- if (irdata == MARK) { // SPACE just ended, record it
- irparams.rawbuf[irparams.rawlen++] = irparams.timer;
- irparams.timer = 0;
- irparams.rcvstate = STATE_MARK;
- }
- else { // SPACE
- if (irparams.timer > GAP_TICKS) {
- // big SPACE, indicates gap between codes
- // Mark current code as ready for processing
- // Switch to STOP
- // Don't reset timer; keep counting space width
- irparams.rcvstate = STATE_STOP;
- }
- }
- break;
- case STATE_STOP: // waiting, measuring gap
- if (irdata == MARK) { // reset gap timer
- irparams.timer = 0;
- }
- break;
- }
- }
- void IRSendRev::Clear() {
- irparams.rcvstate = STATE_IDLE;
- irparams.rawlen = 0;
- }
- // Decodes the received IR message
- // Returns 0 if no data ready, 1 if data ready.
- // Results of decoding are stored in results
- int IRSendRev::decode(decode_results *results) {
- results->rawbuf = irparams.rawbuf;
- results->rawlen = irparams.rawlen;
- if (irparams.rcvstate != STATE_STOP) {
- return ERR;
- }
- // Throw away and start over
- Clear();
- return 1;
- }
- unsigned char IRSendRev::Recv(unsigned char *revData)
- {
- int count = results.rawlen;
- int nshort = 0;
- int nlong = 0;
- int count_data = 0;
- count_data = (count-4)/16;
- for(int i = 0; i<10; i++) // count nshort
- {
- nshort += results.rawbuf[3+2*i];
- }
- nshort /= 10;
- int i = 0;
- int j = 0;
- while(1) // count nlong
- {
- if(results.rawbuf[4+2*i] > (2*nshort))
- {
- nlong += results.rawbuf[4+2*i];
- j++;
- }
- i++;
- if(j==10)break;
- if((4+2*i)>(count-10))break;
- }
- nlong /= j;
- int doubleshort = 2*nshort;
- for(i = 0; i<count_data; i++)
- {
- revData[i+D_DATA] = 0x00;
- for(j = 0; j<8; j++)
- {
- if(results.rawbuf[4 + 16*i + j*2] > doubleshort) // 1
- {
- revData[i+D_DATA] |= 0x01<< (7-j);
- }
- else
- {
- revData[i+D_DATA] &= ~(0x01<<(7-j));
- }
- }
- }
- revData[D_LEN] = count_data+5;
- revData[D_STARTH] = results.rawbuf[1];
- revData[D_STARTL] = results.rawbuf[2];
- revData[D_SHORT] = nshort;
- revData[D_LONG] = nlong;
- revData[D_DATALEN] = count_data;
-
- #if __DEBUG
- Serial.print("\r\n*************************************************************\r\n");
- Serial.print("len\t = ");Serial.println(revData[D_LEN]);
- Serial.print("start_h\t = ");Serial.println(revData[D_STARTH]);
- Serial.print("start_l\t = ");Serial.println(revData[D_STARTL]);
- Serial.print("short\t = ");Serial.println(revData[D_SHORT]);
- Serial.print("long\t = ");Serial.println(revData[D_LONG]);
- Serial.print("data_len = ");Serial.println(revData[D_DATALEN]);
- for(int i = 0; i<revData[D_DATALEN]; i++)
- {
- Serial.print(revData[D_DATA+i]);Serial.print("\t");
- }
- Serial.print("\r\n*************************************************************\r\n");
- #endif
- Clear(); // Receive the next value
- return revData[D_LEN]+1;
- }
- //if get some data from IR
- unsigned char IRSendRev::IsDta()
- {
- if(decode(&results))
- {
- int count = results.rawlen;
- if(count < 20 || (count -4)%8 != 0)
- {
- #if __DEBUG
- Serial.print("IR GET BAD DATA!\r\n");
- #endif
- Clear(); // Receive the next value
- return 0;
- }
- int count_data = (count-4) / 16;
- #if __DEBUG
- Serial.print("ir get data! count_data = ");
- Serial.println(count_data);
- #endif
- return (unsigned char)(count_data+6);
- }
- else
- {
- return 0;
- }
- }
- void IRSendRev::Send(unsigned char *idata, unsigned char ifreq)
- {
- int len = idata[0];
- unsigned char start_high = idata[1];
- unsigned char start_low = idata[2];
- unsigned char nshort = idata[3];
- unsigned char nlong = idata[4];
- unsigned char datalen = idata[5];
- unsigned int *pSt = (unsigned int *)malloc((4+datalen*16)*sizeof(unsigned int));
- if(NULL == pSt)
- {
- #if __DEBUG
- Serial.println("not enough place!!\r\n");
- #endif
- exit(1);
- }
- #if __DEBUG
- Serial.println("begin to send ir:\r\n");
- Serial.print("ifreq = ");Serial.println(ifreq);
- Serial.print("len = ");Serial.println(len);
- Serial.print("start_high = ");Serial.println(start_high);
- Serial.print("start_low = ");Serial.println(start_low);
- Serial.print("nshort = ");Serial.println(nshort);
- Serial.print("nlong = ");Serial.println(nlong);
- Serial.print("datalen = ");Serial.println(datalen);
- #endif
- pSt[0] = start_high*50;
- pSt[1] = start_low*50;
- for(int i = 0; i<datalen; i++)
- {
- for(int j = 0; j<8; j++)
- {
- if(idata[6+i] & 0x01<<(7-j))
- {
- pSt[16*i + 2*j + 2] = nshort*50;
- pSt[16*i + 2*j+3] = nlong*50;
- }
- else
- {
- pSt[16*i + 2*j+2] = nshort*50;
- pSt[16*i + 2*j+3] = nshort*50;
- }
- }
- }
- pSt[2+datalen*16] = nshort*50;
- pSt[2+datalen*16+1] = nshort*50;
- #if __DEBUG
- for(int i = 0; i<4+datalen*16; i++)
- {
- Serial.print(pSt[i]);Serial.print("\t");
- }
- Serial.println();
- #endif
- sendRaw(pSt, 4+datalen*16, ifreq);
- free(pSt);
-
- }
- IRSendRev IR;
|