/* * Dish/Arduino IR blaster. * * Copyright (c) 2009 Alex Williamson * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation, 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For the complete license, please see http://www.fsf.org/licenses/gpl.txt * or request a copy from the author of this program. */ #include #define IR_PIN 13 /* From dish remote lirc files, times in us */ #define PHEAD 525 #define SHEAD 6045 #define PONE 440 #define SONE 1645 #define PZERO 440 #define SZERO 2780 #define PTRAIL 450 #define GAP 6115 #define DATA_BITS 6 #define POST_BITS 10 #define PERIOD_US 18 // ~= (1/56kHz) * 1000000 #define DEFAULT_REMOTE 0x000 #define DEFAULT_REPEAT 4 #define DEFAULT_DELAY 250 /* * Algorithm found at: * http://blog.lucaseckels.com/2009/08/23/arduino-ir-transmitter/ */ static void modulate(int time) { int count; byte portb = PORTB; byte portbHigh = portb | 0x20; /* Pin 13 is bit 0x20 on PORTB. */ byte portbLow = portb & ~0x20; for (count = time / PERIOD_US; count; count--) { /* Values determined by timing loop with micros() */ PORTB = portbHigh; _delay_loop_2(34); PORTB = portbLow; _delay_loop_2(34); } PORTB = portb; } static void inline send_bit(int bit) { if (bit) { modulate(PONE); _delay_loop_2((SONE * 4) - 50); } else { modulate(PZERO); _delay_loop_2((SZERO * 4) - 74); } } static byte inline wait_for_byte() { while (!Serial.available()); return Serial.read(); } static void usage(void) { Serial.print("Arduino dish IR blaster\n"); Serial.print("Default remote code: "); Serial.print(DEFAULT_REMOTE, DEC); Serial.print("\nDefault repeat count: "); Serial.print(DEFAULT_REPEAT, DEC); Serial.print("\nDefault post command delay: "); Serial.print(DEFAULT_DELAY, DEC); Serial.print("(ms)\nCommand format: " "[#][@][d].\n"); Serial.print("Values in decimal\n"); } static int get_command(int *code, int *repeat, int *remote, int *delay_ms) { byte data; int *cur; *code = 0; *repeat = DEFAULT_REPEAT; *remote = DEFAULT_REMOTE; *delay_ms = DEFAULT_DELAY; cur = code; while (data = wait_for_byte()) { switch (data) { case '#': cur = repeat; *cur = 0; break; case '@': cur = remote; *cur = 0; break; case 'd': cur = delay_ms; *cur = 0; break; case '.': return 0; case '0' ... '9': *cur *= 10; *cur += (data - '0'); break; default: usage(); return -1; } } } void setup() { pinMode(IR_PIN, OUTPUT); digitalWrite(IR_PIN, LOW); Serial.begin(115200); delay(500); } void loop() { int i, code, repeat, remote, delay_ms; unsigned int mask; while (get_command(&code, &repeat, &remote, &delay_ms) != 0); /* * Wait for serial to settle. If we get a long stream of * commands, we may start executing while bytes are still * coming in, this can affect the timing. */ do { i = Serial.available(); delay(1); } while (i != Serial.available()); modulate(PHEAD); _delay_loop_2((SHEAD * 4) - 154); do { for (mask = 0x1 << (DATA_BITS - 1); mask; mask >>= 1) send_bit(code & mask); for (mask = 0x1 << (POST_BITS - 1); mask; mask >>= 1) send_bit(remote & mask); modulate(PTRAIL); _delay_loop_2((GAP * 4) - 200); } while (--repeat > 0); delay(delay_ms); }