174 lines
5.1 KiB
C
174 lines
5.1 KiB
C
/*
|
|
Last Updated: 30 Mar. 2018
|
|
By Anton Grimpelhuber (anton.grimpelhuber@gmail.com)
|
|
*/
|
|
|
|
// The TV-B-Gone for Arduino can use either the EU (European Union) or the NA (North America) database of POWER CODES
|
|
// EU is for Europe, Middle East, Australia, New Zealand, and some countries in Africa and South America
|
|
// NA is for North America, Asia, and the rest of the world not covered by EU
|
|
|
|
// Two regions!
|
|
#define NA 0 //set by a HIGH on REGIONSWITCH pin
|
|
#define EU 1 //set by a LOW on REGIONSWITCH pin
|
|
|
|
// What pins do what
|
|
#define LED 10 //LED indicator pin (built-in LED)
|
|
#define IRLED 9 //the IR sender LED / D5 on wemos D1 mini
|
|
#define TRIGGER 37 //the button pin / D6 on wemos D1 mini
|
|
#define REGIONSWITCH 39 //HIGH (1) = NA, LOW (0) = EU; Pin 5 / D1 (REGIONSWITCH) is HIGH (via in input pullup resistor) for North America, or you (the user) must wire it to ground to set the codes for Europe.
|
|
|
|
// Lets us calculate the size of the NA/EU databases
|
|
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)));
|
|
|
|
// set define to 0 to turn off debug output
|
|
#define DEBUG 0
|
|
#define DEBUGP(x) if (DEBUG == 1) { x ; }
|
|
|
|
// Shortcut to insert single, non-optimized-out nop
|
|
#define NOP __asm__ __volatile__ ("nop")
|
|
|
|
// Not used any more on esp8266, so don't bother
|
|
// Tweak this if neccessary to change timing
|
|
// -for 8MHz Arduinos, a good starting value is 11
|
|
// -for 16MHz Arduinos, a good starting value is 25
|
|
#define DELAY_CNT 25
|
|
|
|
// Makes the codes more readable. the OCRA is actually
|
|
// programmed in terms of 'periods' not 'freqs' - that
|
|
// is, the inverse!
|
|
// #define freq_to_timerval(x) (F_CPU / 8 / x - 1)
|
|
#define freq_to_timerval(x) (x / 1000)
|
|
|
|
// The structure of compressed code entries
|
|
struct IrCode {
|
|
uint8_t timer_val;
|
|
uint8_t numpairs;
|
|
uint8_t bitcompression;
|
|
uint16_t const *times;
|
|
uint8_t const *codes;
|
|
};
|
|
|
|
void xmitCodeElement(uint16_t ontime, uint16_t offtime, uint8_t PWM_code );
|
|
void quickflashLEDx( uint8_t x );
|
|
void delay_ten_us(uint16_t us);
|
|
void quickflashLED( void );
|
|
uint8_t read_bits(uint8_t count);
|
|
uint16_t rawData[300];
|
|
#define MAX_WAIT_TIME 65535 //tens of us (ie: 655.350ms)
|
|
IRsend irsend(IRLED); // Set the GPIO to be used to sending the message.
|
|
extern const IrCode* const NApowerCodes[];
|
|
extern const IrCode* const EUpowerCodes[];
|
|
extern uint8_t num_NAcodes, num_EUcodes;
|
|
uint8_t bitsleft_r = 0;
|
|
uint8_t bits_r = 0;
|
|
uint8_t code_ptr;
|
|
volatile const IrCode * powerCode;
|
|
uint8_t read_bits(uint8_t count)
|
|
{
|
|
uint8_t i;
|
|
uint8_t tmp = 0;
|
|
for (i = 0; i < count; i++) {
|
|
if (bitsleft_r == 0) {
|
|
bits_r = powerCode->codes[code_ptr++];
|
|
bitsleft_r = 8;
|
|
}
|
|
bitsleft_r--;
|
|
tmp |= (((bits_r >> (bitsleft_r)) & 1) << (count - 1 - i));
|
|
}
|
|
return tmp;
|
|
}
|
|
#define BUTTON_PRESSED LOW
|
|
#define BUTTON_RELEASED HIGH
|
|
uint16_t ontime, offtime;
|
|
uint8_t i, num_codes;
|
|
uint8_t region;
|
|
|
|
void sendAllCodes()
|
|
{
|
|
bool endingEarly = false; //will be set to true if the user presses the button during code-sending
|
|
if (region == NA) {
|
|
num_codes = num_NAcodes;
|
|
} else {
|
|
num_codes = num_EUcodes;
|
|
}
|
|
for (i = 0 ; i < num_codes; i++)
|
|
{
|
|
if (region == NA) {
|
|
powerCode = NApowerCodes[i];
|
|
}
|
|
else {
|
|
powerCode = EUpowerCodes[i];
|
|
}
|
|
const uint8_t freq = powerCode->timer_val;
|
|
const uint8_t numpairs = powerCode->numpairs;
|
|
M5.Lcd.fillScreen(BLACK);
|
|
M5.Lcd.setTextSize(4);
|
|
M5.Lcd.setCursor(5, 1);
|
|
M5.Lcd.println("TV-B-Gone");
|
|
M5.Lcd.setTextSize(2);
|
|
const uint8_t bitcompression = powerCode->bitcompression;
|
|
code_ptr = 0;
|
|
for (uint8_t k = 0; k < numpairs; k++) {
|
|
uint16_t ti;
|
|
ti = (read_bits(bitcompression)) * 2;
|
|
offtime = powerCode->times[ti]; // read word 1 - ontime
|
|
ontime = powerCode->times[ti + 1]; // read word 2 - offtime
|
|
M5.Lcd.setTextSize(1);
|
|
M5.Lcd.printf("rti = %d Pair = %d, %d\n", ti >> 1, ontime, offtime);
|
|
rawData[k * 2] = offtime * 10;
|
|
rawData[(k * 2) + 1] = ontime * 10;
|
|
yield();
|
|
}
|
|
irsend.sendRaw(rawData, (numpairs * 2) , freq);
|
|
// Hack: Set IRLED high to turn it off after each burst. Otherwise it stays on (active low)
|
|
digitalWrite(IRLED, HIGH);
|
|
yield();
|
|
bitsleft_r = 0;
|
|
delay_ten_us(20500);
|
|
if (digitalRead(TRIGGER) == BUTTON_PRESSED)
|
|
{
|
|
while (digitalRead(TRIGGER) == BUTTON_PRESSED) {
|
|
yield();
|
|
}
|
|
endingEarly = true;
|
|
delay_ten_us(50000); //500ms delay
|
|
quickflashLEDx(4);
|
|
delay_ten_us(MAX_WAIT_TIME); // wait 655.350ms
|
|
delay_ten_us(MAX_WAIT_TIME); // wait 655.350ms
|
|
break; //exit the POWER code "for" loop
|
|
}
|
|
}
|
|
if (endingEarly == false)
|
|
{
|
|
delay_ten_us(MAX_WAIT_TIME); // wait 655.350ms
|
|
delay_ten_us(MAX_WAIT_TIME); // wait 655.350ms
|
|
quickflashLEDx(8);
|
|
}
|
|
}
|
|
|
|
void delay_ten_us(uint16_t us) {
|
|
uint8_t timer;
|
|
while (us != 0) {
|
|
for (timer = 0; timer <= DELAY_CNT; timer++) {
|
|
NOP;
|
|
NOP;
|
|
}
|
|
NOP;
|
|
us--;
|
|
}
|
|
}
|
|
|
|
void quickflashLED( void ) {
|
|
digitalWrite(LED, LOW);
|
|
delay_ten_us(3000); // 30 ms ON-time delay
|
|
digitalWrite(LED, HIGH);
|
|
}
|
|
|
|
void quickflashLEDx( uint8_t x ) {
|
|
quickflashLED();
|
|
while (--x) {
|
|
delay_ten_us(25000); // 250 ms OFF-time delay between flashes
|
|
quickflashLED();
|
|
}
|
|
}
|