├── main.h ├── README.md ├── FloraTVB.pde └── WORLDcodes.cpp /main.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | // The TV-B-Gone for Arduino can use 5 | // either the EU or the NA database of POWER CODES 6 | // EU is for Europe, Middle East, Australia, New Zealand, and some countries in Africa and South America 7 | // NA is for North America, Asia, and the rest of the world not covered by EU 8 | 9 | // Two regions! 10 | #define NA 1 11 | #define EU 0 12 | 13 | // What pins do what 14 | #define DBG 12 15 | #define LED 7 // Flora's onboard LED is connected to D7 16 | #define IRLED 3 // D3 is marked "SCL" on Flora 17 | #define TRIGGER 9 // pushbutton will be connected to D9 18 | #define REGIONSWITCH 5 19 | 20 | // Lets us calculate the size of the NA/EU databases 21 | #define NUM_ELEM(x) (sizeof (x) / sizeof (*(x))); 22 | 23 | // set define to 0 to turn off debug output 24 | #define DEBUG 0 25 | #define DEBUGP(x) if (DEBUG == 1) { x ; } 26 | 27 | // Shortcut to insert single, non-optimized-out nop 28 | #define NOP __asm__ __volatile__ ("nop") 29 | 30 | // Tweak this if neccessary to change timing 31 | #define DELAY_CNT 25 32 | 33 | // Makes the codes more readable. the OCRA is actually 34 | // programmed in terms of 'periods' not 'freqs' - that 35 | // is, the inverse! 36 | #define freq_to_timerval(x) (F_CPU / 8 / x - 1) 37 | 38 | // The structure of compressed code entries 39 | struct IrCode { 40 | uint8_t timer_val; 41 | uint8_t numpairs; 42 | uint8_t bitcompression; 43 | uint16_t const *times; 44 | uint8_t const*codes; 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated Code - Doesn't work anymore 2 | 3 | ## Working code now available at https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/master/Flora_TV_B_Gone 4 | 5 | This code is the TV-B-Gone library ported to run on the Adafruit Flora. 6 | 7 | Code updated for Flora's 32u4 microcontroller by Phillip Burgess for Adafruit Industries 8 | 9 | Complete instructions: http://learn.adafruit.com/flora-tv-b-gone/ 10 | 11 | Adafruit invests time and resources providing this open source design, 12 | please support Adafruit and open-source hardware by purchasing 13 | products from Adafruit! 14 | 15 | ------------- 16 | based on Ken Shirriff's port of TV-B-Gone to Arduino, version 1.2, Oct 23 2010 17 | For details on the Arduino port, how to build it, and how to use it, see: 18 | http://www.arcfn.com/2010/11/improved-arduino-tv-b-gone.html 19 | 20 | For information on the original TV-B-Gone see: 21 | http://www.tvbgone.com/cfe_tvbg_main.php 22 | 23 | The original code is: 24 | TV-B-Gone Firmware version 1.2 25 | for use with ATtiny85v and v1.2 hardware 26 | (c) Mitch Altman + Limor Fried 2009 27 | Last edits, August 16 2009 28 | 29 | I added universality for EU or NA, 30 | and Sleep mode to Ken's Arduino port 31 | -- Mitch Altman 18-Oct-2010 32 | Thanks to ka1kjz for the code for adding Sleep 33 | 34 | 35 | With some code from: 36 | Kevin Timmerman & Damien Good 7-Dec-07 37 | 38 | Distributed under Creative Commons 2.5 -- Attribution & Share-Alike 39 | All text above must be included in any redistribution 40 | 41 | 42 | -------------------------------------------------------------------------------- /FloraTVB.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Flora TV-B-Gone 3 | 4 | Code updated for Flora's 32u4 microcontroller by Phillip Burgess for Adafruit Industries 5 | 6 | Complete instructions: http://learn.adafruit.com/flora-tv-b-gone/ 7 | 8 | The hardware for this project uses an Adafruit Flora (Arduino-compatible 32u4): 9 | Connect the base of an NPN bipolar transistor to pin 3, marked "SCL" on Flora (RLED). 10 | Connect the collector pin of the transistor to ground (Marked "GND" on Flora). 11 | Connect the transistor's emitter to the positive lead of an IR LED, and connect the LED's negative leg to ground through a 100-ohm resistor. 12 | Connect a pushbutton between pin D9 (TRIGGER) and ground. 13 | Pin 5 (REGIONSWITCH) is floating for North America, or wired to ground for Europe. 14 | 15 | ------------- 16 | based on Ken Shirriff's port of TV-B-Gone to Arduino, version 1.2, Oct 23 2010 17 | http://www.arcfn.com/2009/12/tv-b-gone-for-arduino.html 18 | 19 | The original code is: 20 | TV-B-Gone Firmware version 1.2 21 | for use with ATtiny85v and v1.2 hardware 22 | (c) Mitch Altman + Limor Fried 2009 23 | Last edits, August 16 2009 24 | 25 | 26 | I added universality for EU or NA, 27 | and Sleep mode to Ken's Arduino port 28 | -- Mitch Altman 18-Oct-2010 29 | Thanks to ka1kjz for the code for adding Sleep 30 | 31 | 32 | With some code from: 33 | Kevin Timmerman & Damien Good 7-Dec-07 34 | 35 | Distributed under Creative Commons 2.5 -- Attib & Share Alike 36 | 37 | */ 38 | 39 | #include "main.h" 40 | #include 41 | 42 | void xmitCodeElement(uint16_t ontime, uint16_t offtime, uint8_t PWM_code ); 43 | void quickflashLEDx( uint8_t x ); 44 | void delay_ten_us(uint16_t us); 45 | void quickflashLED( void ); 46 | uint8_t read_bits(uint8_t count); 47 | 48 | #define putstring_nl(s) Serial.println(s) 49 | #define putstring(s) Serial.print(s) 50 | #define putnum_ud(n) Serial.print(n, DEC) 51 | #define putnum_uh(n) Serial.print(n, HEX) 52 | 53 | /* 54 | This project transmits a bunch of TV POWER codes, one right after the other, 55 | with a pause in between each. (To have a visible indication that it is 56 | transmitting, it also pulses a visible LED once each time a POWER code is 57 | transmitted.) That is all TV-B-Gone does. The tricky part of TV-B-Gone 58 | was collecting all of the POWER codes, and getting rid of the duplicates and 59 | near-duplicates (because if there is a duplicate, then one POWER code will 60 | turn a TV off, and the duplicate will turn it on again (which we certainly 61 | do not want). I have compiled the most popular codes with the 62 | duplicates eliminated, both for North America (which is the same as Asia, as 63 | far as POWER codes are concerned -- even though much of Asia USES PAL video) 64 | and for Europe (which works for Australia, New Zealand, the Middle East, and 65 | other parts of the world that use PAL video). 66 | 67 | Before creating a TV-B-Gone Kit, I originally started this project by hacking 68 | the MiniPOV kit. This presents a limitation, based on the size of 69 | the Atmel ATtiny2313 internal flash memory, which is 2KB. With 2KB we can only 70 | fit about 7 POWER codes into the firmware's database of POWER codes. However, 71 | the more codes the better! Which is why we chose the ATtiny85 for the 72 | TV-B-Gone Kit. 73 | 74 | This version of the firmware has the most popular 100+ POWER codes for 75 | North America and 100+ POWER codes for Europe. You can select which region 76 | to use by soldering a 10K pulldown resistor. 77 | */ 78 | 79 | 80 | /* 81 | This project is a good example of how to use the AVR chip timers. 82 | */ 83 | 84 | extern PGM_P *NApowerCodes[] PROGMEM; 85 | extern PGM_P *EUpowerCodes[] PROGMEM; 86 | extern uint8_t num_NAcodes, num_EUcodes; 87 | 88 | /* This function is the 'workhorse' of transmitting IR codes. 89 | Given the on and off times, it turns on the PWM output on and off 90 | to generate one 'pair' from a long code. Each code has ~50 pairs! */ 91 | void xmitCodeElement(uint16_t ontime, uint16_t offtime, uint8_t PWM_code ) 92 | { 93 | #ifdef __AVR_ATmega32U4__ 94 | TCNT0 = 0; 95 | #else 96 | TCNT2 = 0; 97 | #endif 98 | if(PWM_code) { 99 | pinMode(IRLED, OUTPUT); 100 | // Fast PWM, setting top limit, divide by 8 101 | // Output to pin 3 102 | #ifdef __AVR_ATmega32U4__ 103 | #if (IRLED == 11) 104 | TCCR0A = _BV(COM0A1) | _BV(COM0A0) | _BV(WGM01) | _BV(WGM00); 105 | #elif (IRLED == 3) 106 | TCCR0A = _BV(COM0B1) | _BV(COM0B0) | _BV(WGM01) | _BV(WGM00); 107 | #else 108 | #error "IR LED must be on Leonardo digital pin 3 or 11." 109 | #endif 110 | TCCR0B = _BV(WGM02) | _BV(CS01); 111 | #else 112 | TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); 113 | TCCR2B = _BV(WGM22) | _BV(CS21); 114 | #endif 115 | } 116 | else { 117 | // However some codes dont use PWM in which case we just turn the IR 118 | // LED on for the period of time. 119 | digitalWrite(IRLED, HIGH); 120 | } 121 | 122 | // Now we wait, allowing the PWM hardware to pulse out the carrier 123 | // frequency for the specified 'on' time 124 | delay_ten_us(ontime); 125 | 126 | // Now we have to turn it off so disable the PWM output 127 | #ifdef __AVR_ATmega32U4__ 128 | TCCR0A = 0; 129 | TCCR0B = 0; 130 | #else 131 | TCCR2A = 0; 132 | TCCR2B = 0; 133 | #endif 134 | // And make sure that the IR LED is off too (since the PWM may have 135 | // been stopped while the LED is on!) 136 | digitalWrite(IRLED, LOW); 137 | 138 | // Now we wait for the specified 'off' time 139 | delay_ten_us(offtime); 140 | } 141 | 142 | /* This is kind of a strange but very useful helper function 143 | Because we are using compression, we index to the timer table 144 | not with a full 8-bit byte (which is wasteful) but 2 or 3 bits. 145 | Once code_ptr is set up to point to the right part of memory, 146 | this function will let us read 'count' bits at a time which 147 | it does by reading a byte into 'bits_r' and then buffering it. */ 148 | 149 | uint8_t bitsleft_r = 0; 150 | uint8_t bits_r=0; 151 | PGM_P code_ptr; 152 | 153 | // we cant read more than 8 bits at a time so dont try! 154 | uint8_t read_bits(uint8_t count) 155 | { 156 | uint8_t i; 157 | uint8_t tmp=0; 158 | 159 | // we need to read back count bytes 160 | for (i=0; i> (bitsleft_r)) & 1) << (count-1-i)); 172 | } 173 | // return the selected bits in the LSB part of tmp 174 | return tmp; 175 | } 176 | 177 | 178 | /* 179 | The C compiler creates code that will transfer all constants into RAM when 180 | the microcontroller resets. Since this firmware has a table (powerCodes) 181 | that is too large to transfer into RAM, the C compiler needs to be told to 182 | keep it in program memory space. This is accomplished by the macro PROGMEM 183 | (this is used in the definition for powerCodes). Since the C compiler assumes 184 | that constants are in RAM, rather than in program memory, when accessing 185 | powerCodes, we need to use the pgm_read_word() and pgm_read_byte macros, and 186 | we need to use powerCodes as an address. This is done with PGM_P, defined 187 | below. 188 | For example, when we start a new powerCode, we first point to it with the 189 | following statement: 190 | PGM_P thecode_p = pgm_read_word(powerCodes+i); 191 | The next read from the powerCode is a byte that indicates the carrier 192 | frequency, read as follows: 193 | const uint8_t freq = pgm_read_byte(code_ptr++); 194 | After that is a byte that tells us how many 'onTime/offTime' pairs we have: 195 | const uint8_t numpairs = pgm_read_byte(code_ptr++); 196 | The next byte tells us the compression method. Since we are going to use a 197 | timing table to keep track of how to pulse the LED, and the tables are 198 | pretty short (usually only 4-8 entries), we can index into the table with only 199 | 2 to 4 bits. Once we know the bit-packing-size we can decode the pairs 200 | const uint8_t bitcompression = pgm_read_byte(code_ptr++); 201 | Subsequent reads from the powerCode are n bits (same as the packing size) 202 | that index into another table in ROM that actually stores the on/off times 203 | const PGM_P time_ptr = (PGM_P)pgm_read_word(code_ptr); 204 | */ 205 | 206 | uint16_t ontime, offtime; 207 | uint8_t i,num_codes, Loop; 208 | uint8_t region; 209 | uint8_t startOver; 210 | 211 | #define FALSE 0 212 | #define TRUE 1 213 | 214 | void setup() { 215 | Serial.begin(9600); 216 | 217 | #ifdef __AVR_ATmega32U4__ 218 | // Timer0 is used on Arduino Leonardo (there is no Timer2). 219 | // This means delay(), millis() etc. are not available, 220 | // but they're currently not being used by this code. 221 | TIMSK0 = 0; // Disable Timer0 interrupt 222 | TCCR0A = 0; 223 | TCCR0B = 0; 224 | #else 225 | TCCR2A = 0; 226 | TCCR2B = 0; 227 | #endif 228 | 229 | digitalWrite(LED, LOW); 230 | digitalWrite(IRLED, LOW); 231 | digitalWrite(DBG, LOW); // debug 232 | pinMode(LED, OUTPUT); 233 | pinMode(IRLED, OUTPUT); 234 | pinMode(DBG, OUTPUT); // debug 235 | pinMode(REGIONSWITCH, INPUT); 236 | pinMode(TRIGGER, INPUT); 237 | digitalWrite(REGIONSWITCH, HIGH); //Pull-up 238 | digitalWrite(TRIGGER, HIGH); 239 | 240 | delay_ten_us(5000); // Let everything settle for a bit 241 | 242 | // determine region 243 | if (digitalRead(REGIONSWITCH)) { 244 | region = NA; 245 | DEBUGP(putstring_nl("NA")); 246 | } 247 | else { 248 | region = EU; 249 | DEBUGP(putstring_nl("EU")); 250 | } 251 | 252 | // Indicate how big our database is 253 | DEBUGP(putstring("\n\rNA Codesize: "); 254 | putnum_ud(num_NAcodes); 255 | ); 256 | DEBUGP(putstring("\n\rEU Codesize: "); 257 | putnum_ud(num_EUcodes); 258 | ); 259 | 260 | // Tell the user what region we're in - 3 flashes is NA, 6 is EU 261 | delay_ten_us(65500); // wait maxtime 262 | delay_ten_us(65500); // wait maxtime 263 | delay_ten_us(65500); // wait maxtime 264 | delay_ten_us(65500); // wait maxtime 265 | quickflashLEDx(3); 266 | if (region == EU) { 267 | quickflashLEDx(3); 268 | } 269 | } 270 | 271 | void sendAllCodes() { 272 | Start_transmission: 273 | // startOver will become TRUE if the user pushes the Trigger button while transmitting the sequence of all codes 274 | startOver = FALSE; 275 | 276 | // determine region from REGIONSWITCH: 1 = NA, 0 = EU 277 | if (digitalRead(REGIONSWITCH)) { 278 | region = NA; 279 | num_codes = num_NAcodes; 280 | } 281 | else { 282 | region = EU; 283 | num_codes = num_EUcodes; 284 | } 285 | 286 | // for every POWER code in our collection 287 | for (i=0 ; i < num_codes; i++) { 288 | PGM_P data_ptr; 289 | 290 | // print out the code # we are about to transmit 291 | DEBUGP(putstring("\n\r\n\rCode #: "); 292 | putnum_ud(i)); 293 | 294 | // point to next POWER code, from the right database 295 | if (region == NA) { 296 | data_ptr = (PGM_P)pgm_read_word(NApowerCodes+i); 297 | } 298 | else { 299 | data_ptr = (PGM_P)pgm_read_word(EUpowerCodes+i); 300 | } 301 | 302 | // print out the address in ROM memory we're reading 303 | DEBUGP(putstring("\n\rAddr: "); 304 | putnum_uh((uint16_t)data_ptr)); 305 | 306 | // Read the carrier frequency from the first byte of code structure 307 | const uint8_t freq = pgm_read_byte(data_ptr++); 308 | // set OCR for Timer1 to output this POWER code's carrier frequency 309 | #ifdef __AVR_ATmega32U4__ 310 | OCR0A = freq; 311 | OCR0B = freq / 3; // 33% duty cycle 312 | #else 313 | OCR2A = freq; 314 | OCR2B = freq / 3; // 33% duty cycle 315 | #endif 316 | 317 | // Print out the frequency of the carrier and the PWM settings 318 | DEBUGP(putstring("\n\rOCR1: "); 319 | putnum_ud(freq); 320 | ); 321 | DEBUGP(uint16_t x = (freq+1) * 2; 322 | putstring("\n\rFreq: "); 323 | putnum_ud(F_CPU/x); 324 | ); 325 | 326 | // Get the number of pairs, the second byte from the code struct 327 | const uint8_t numpairs = pgm_read_byte(data_ptr++); 328 | DEBUGP(putstring("\n\rOn/off pairs: "); 329 | putnum_ud(numpairs)); 330 | 331 | // Get the number of bits we use to index into the timer table 332 | // This is the third byte of the structure 333 | const uint8_t bitcompression = pgm_read_byte(data_ptr++); 334 | DEBUGP(putstring("\n\rCompression: "); 335 | putnum_ud(bitcompression); 336 | putstring("\n\r")); 337 | 338 | // Get pointer (address in memory) to pulse-times table 339 | // The address is 16-bits (2 byte, 1 word) 340 | PGM_P time_ptr = (PGM_P)pgm_read_word(data_ptr); 341 | data_ptr+=2; 342 | code_ptr = (PGM_P)pgm_read_word(data_ptr); 343 | 344 | // Transmit all codeElements for this POWER code 345 | // (a codeElement is an onTime and an offTime) 346 | // transmitting onTime means pulsing the IR emitters at the carrier 347 | // frequency for the length of time specified in onTime 348 | // transmitting offTime means no output from the IR emitters for the 349 | // length of time specified in offTime 350 | 351 | #if 0 352 | 353 | // print out all of the pulse pairs 354 | for (uint8_t k=0; k