diff --git a/README.md b/README.md index 2877c74..f214985 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,9 @@ decode.rb decode the MilesTag v2 recorded transmission +avr +=== + +firmware for the IR grenade. +based on the TV-B-Gone firmware + diff --git a/avr/Makefile b/avr/Makefile new file mode 100644 index 0000000..fc39539 --- /dev/null +++ b/avr/Makefile @@ -0,0 +1,80 @@ +# required packages +# sudo aptitude install avrdude gcc-avr avr-libc +# the program +PROG=ir-cock-grenade +# to compile +CC=avr-gcc +OBJDUMP=avr-objdump +OBJCOPY=avr-objcopy +CFLAGS=-g -Wall -O3 +# the target +#DEVICE=atmega328p +DEVICE=attiny85 +F_CPU=1000000 +# the port to flash +#PORT=/dev/ttyUSB0 +# the flasher +#PROGRAMMER=buspirate +PROGRAMMER=usbtiny +# to flash +#AVRDUDE=avrdude -p $(DEVICE) -P $(PORT) -c $(PROGRAMMER) +AVRDUDE=avrdude -p $(DEVICE) -c $(PROGRAMMER) -B 50 + +all: prog + +prog: verify $(PROG).c + $(CC) $(CFLAGS) -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -o $(PROG) $(PROG).c + $(OBJDUMP) -h -S $(PROG) > $(PROG).lst + $(OBJCOPY) -j .text -j .data -O ihex $(PROG) $(PROG).hex + +# Fuse extended byte: +# 0x07 = - - - - - 1 1 1 +# \-+-/ +# +------ BODLEVEL 2..0 (Brown-out Detector trigger level -> disabled) +# +# Fuse high byte: +# 0xdf = 1 1 0 1 1 1 1 1 +# ^ ^ ^ ^ ^ \+/ ^ +# | | | | | | +---- BOOTRST (Select Reset Vector -> jump to application at start) +# | | | | | +------- BOOTSZ 1..0 (Select Boot Size -> 256 words starting at 0x3F00) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable -> enabled) +# +-------------------- RSTDISBL (disable external reset -> reset disabled) +# +# Fuse low byte: +# 0x62 = 0 1 1 0 0 0 1 0 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> Internal RC oscillator) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> divide) +burn-fuse: + $(AVRDUDE) -U efuse:w:0x07:m -U hfuse:w:0xdf:m -U lfuse:w:0x62:m + +read-fuse: + $(AVRDUDE) -U efuse:r:efuse.raw:r -U hfuse:r:hfuse.raw:r -U lfuse:r:lfuse.raw:r + +flash: + $(AVRDUDE) -U flash:w:$(PROG).hex:i + +read-flash: + $(AVRDUDE) -U flash:r:flash_dump.hex:i + +flash: prog load +install : prog load +load: + $(AVRDUDE) -U flash:w:$(PROG).hex:i + +clean: + rm -f $(PROG) *.hex *.lst + +verify: + $(AVRDUDE) + if [ $$? -eq 0 ]; then \ + echo "avrdude configured correctly"; \ + else \ + echo "avrdude not configured correctly in Makefile"; \ + exit 1; \ + fi diff --git a/avr/README.md b/avr/README.md new file mode 100644 index 0000000..95fe1f7 --- /dev/null +++ b/avr/README.md @@ -0,0 +1,9 @@ +packages needed: +sudo apt-get install gcc-avr avr-libc avrdude + +I used the sparkfune AVR Pocket programmer, a USBtinyISP clone (http://ladyada.net/make/usbtinyisp/) +it uses libusb, not a serial port +to be able to use it a non-root part of the dialout group (on ubuntu distributions) +echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="1781", ATTR{idProduct}=="0c9f", MODE="0660", GROUP="dialout"' | sudo tee /etc/udev/rules.d/99-avr.rules +sudo service udev reload + diff --git a/avr/ir grenade/Makefile b/avr/ir grenade/Makefile new file mode 100644 index 0000000..59bd189 --- /dev/null +++ b/avr/ir grenade/Makefile @@ -0,0 +1,371 @@ +# MCU name +MCU = attiny85 +F_CPU = 8000000 + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + +# Target file name (without extension). +TARGET = tvbgone +#NA_CODE = 1 + +# Optimization level, can be [0, 1, 2, 3, s]. 0 turns off optimization. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + +# List C source files here. (C dependencies are automatically generated.) +SRC = main.c util.c + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +# Optional compiler flags. +# -g: generate debugging information (for GDB, or for COFF conversion) +# -O*: optimization level +# -f...: tuning, see gcc manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -ahlms: create assembler listing +CFLAGS = -g -O$(OPT) \ +-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \ +-Wall -Wstrict-prototypes \ +-DF_CPU=$(F_CPU) \ +-Wa,-adhlns=$(<:.c=.lst) \ +$(patsubst %,-I%,$(EXTRAINCDIRS)) + + +# Set a "language standard" compiler flag. +# Unremark just one line below to set the language standard to use. +# gnu99 = C99 + GNU extensions. See GCC manual for more information. +#CFLAGS += -std=c89 +#CFLAGS += -std=gnu89 +#CFLAGS += -std=c99 +CFLAGS += -std=gnu99 + +ifdef EU_CODE + CFLAGS += -DEU_CODES +else ifdef NA_CODE + CFLAGS += -DNA_CODES +else + CFLAGS += -DEU_CODES -DNA_CODES +endif + +# Optional assembler flags. +# -Wa,...: tell GCC to pass this to the assembler. +# -ahlms: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs + + + +# Optional linker flags. +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref + + + +# Additional libraries + +# Minimalistic printf version +#LDFLAGS += -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires -lm below) +#LDFLAGS += -Wl,-u,vfprintf -lprintf_flt + +# -lm = math library +LDFLAGS += -lm + + + +# Programming support using avrdude. Settings and variables. + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +# + +AVRDUDE_PROGRAMMER = usbtiny +#AVRDUDE_PROGRAMMER = stk500v2 + +#AVRDUDE_PORT = com3 # programmer connected to serial device + +AVRDUDE_WRITE_FLASH = -B 5 -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + +AVRDUDE_FLAGS = -p $(MCU) -c $(AVRDUDE_PROGRAMMER) +#AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE += -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_FLAGS += -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_FLAGS += -v -v + + + + +# --------------------------------------------------------------------------- + +# Define directories, if needed. +DIRAVR = c:/winavr +DIRAVRBIN = $(DIRAVR)/bin +DIRAVRUTILS = $(DIRAVR)/utils/bin +DIRINC = . +DIRLIB = $(DIRAVR)/avr/lib + + +# Define programs and commands. +SHELL = sh + +CC = avr-gcc + +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size + + +# Programming support using avrdude. +AVRDUDE = avrdude + + +REMOVE = rm -f +COPY = cp + +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) -A $(TARGET).elf + + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: + + + + +# Define all object files. +OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + +# Default target. +all: begin gccversion sizebefore $(TARGET).elf $(TARGET).hex $(TARGET).eep \ + $(TARGET).lss $(TARGET).sym sizeafter finished end + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +finished: + @echo $(MSG_ERRORS_NONE) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +sizebefore: + @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi + +sizeafter: + @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + + + +# Convert ELF to COFF for use in debugging / simulating in +# AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ + --change-section-address .data-0x800000 \ + --change-section-address .bss-0x800000 \ + --change-section-address .noinit-0x800000 \ + --change-section-address .eeprom-0x810000 + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +reset: + $(AVRDUDE) $(AVRDUDE_FLAGS) + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +full: $(TARGET).hex + make burn-fuse + make program + +burn-fuse: + $(AVRDUDE) $(AVRDUDE_FLAGS) -B 250 -u -U lfuse:w:0xfd:m -U hfuse:w:0xdf:m + +read-fuse: + $(AVRDUDE) $(AVRDUDE_FLAGS) -u -U lfuse:r:l.txt:r + $(AVRDUDE) $(AVRDUDE_FLAGS) -u -U hfuse:r:h.txt:r + $(AVRDUDE) $(AVRDUDE_FLAGS) -u -U efuse:r:e.txt:r +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + avr-nm -n $< > $@ + + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + + + + +# Target: clean project. +clean: begin clean_list finished end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).obj + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).obj + $(REMOVE) $(TARGET).a90 + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lnk + $(REMOVE) $(TARGET).lss + $(REMOVE) $(OBJ) + $(REMOVE) $(LST) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + + +# Automatically generate C source code dependencies. +# (Code originally taken from the GNU make user manual and modified +# (See README.txt Credits).) +# +# Note that this will work with sh (bash) and sed that is shipped with WinAVR +# (see the SHELL variable defined above). +# This may not work with other shells or other seds. +# +%.d: %.c + set -e; $(CC) -MM $(ALL_CFLAGS) $< \ + | sed 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' > $@; \ + [ -s $@ ] || rm -f $@ + + +# Remove the '-' if you want to see the dependency files generated. +-include $(SRC:.c=.d) + + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion coff extcoff \ + clean clean_list program diff --git a/avr/ir grenade/main.c b/avr/ir grenade/main.c new file mode 100644 index 0000000..5b47b43 --- /dev/null +++ b/avr/ir grenade/main.c @@ -0,0 +1,290 @@ +/* +TV-B-Gone Firmware version 1.2 +for use with ATtiny85v and v1.2 hardware +(c) Mitch Altman + Limor Fried 2009 +Last edits, August 16 2009 + +With some code from: +Kevin Timmerman & Damien Good 7-Dec-07 + +Distributed under Creative Commons 2.5 -- Attib & Share Alike + +This is the 'universal' code designed for v1.2 - it will select EU or NA +depending on a pulldown resistor on pin B1 ! +*/ + +#include // this contains all the IO port definitions +#include +#include // definitions for power-down modes +#include // definitions or keeping constants in program memory +#include +#include "main.h" +#include "util.h" + + +/* +This project transmits a bunch of TV POWER codes, one right after the other, +with a pause in between each. (To have a visible indication that it is +transmitting, it also pulses a visible LED once each time a POWER code is +transmitted.) That is all TV-B-Gone does. The tricky part of TV-B-Gone +was collecting all of the POWER codes, and getting rid of the duplicates and +near-duplicates (because if there is a duplicate, then one POWER code will +turn a TV off, and the duplicate will turn it on again (which we certainly +do not want). I have compiled the most popular codes with the +duplicates eliminated, both for North America (which is the same as Asia, as +far as POWER codes are concerned -- even though much of Asia USES PAL video) +and for Europe (which works for Australia, New Zealand, the Middle East, and +other parts of the world that use PAL video). + +Before creating a TV-B-Gone Kit, I originally started this project by hacking +the MiniPOV kit. This presents a limitation, based on the size of +the Atmel ATtiny2313 internal flash memory, which is 2KB. With 2KB we can only +fit about 7 POWER codes into the firmware's database of POWER codes. However, +the more codes the better! Which is why we chose the ATtiny85 for the +TV-B-Gone Kit. + +This version of the firmware has the most popular 100+ POWER codes for +North America and 100+ POWER codes for Europe. You can select which region +to use by soldering a 10K pulldown resistor. +*/ + + +/* +This project is a good example of how to use the AVR chip timers. +*/ + + +/* +The hardware for this project is very simple: + ATtiny85 has 8 pins: + pin 1 RST + Button + pin 2 one pin of ceramic resonator MUST be 8.0 mhz + pin 3 other pin of ceramic resonator + pin 4 ground + pin 5 OC1A - IR emitters, through a '2907 PNP driver that connects + to 4 (or more!) PN2222A drivers, with 1000 ohm base resistor + and also connects to programming circuitry + pin 6 Region selector. Float for US, 10K pulldown for EU, + also connects to programming circuitry + pin 7 PB0 - visible LED, and also connects to programming circuitry + pin 8 +3-5v DC (such as 2-4 AA batteries!) + See the schematic for more details. + + This firmware requires using an 8.0MHz ceramic resonator + (since the internal oscillator may not be accurate enough). + + IMPORTANT: to use the ceramic resonator, you must perform the following: + make burn-fuse_cr +*/ + +/* This function is the 'workhorse' of transmitting IR codes. + Given the on and off times, it turns on the PWM output on and off + to generate one 'pair' from a long code. Each code has ~50 pairs! */ +void xmitCodeElement(uint16_t ontime, uint16_t offtime, uint8_t PWM_code ) +{ + // start Timer0 outputting the carrier frequency to IR emitters on and OC0A + // (PB0, pin 5) + TCNT0 = 0; // reset the timers so they are aligned + TIFR = 0; // clean out the timer flags + + if(PWM_code) { + // 99% of codes are PWM codes, they are pulses of a carrier frequecy + // Usually the carrier is around 38KHz, and we generate that with PWM + // timer 0 + TCCR0A =_BV(COM0A0) | _BV(WGM01); // set up timer 0 + TCCR0B = _BV(CS00); + } else { + // However some codes dont use PWM in which case we just turn the IR + // LED on for the period of time. + PORTB &= ~_BV(IRLED); + } + + // Now we wait, allowing the PWM hardware to pulse out the carrier + // frequency for the specified 'on' time + delay_ten_us(ontime); + + // Now we have to turn it off so disable the PWM output + TCCR0A = 0; + TCCR0B = 0; + // And make sure that the IR LED is off too (since the PWM may have + // been stopped while the LED is on!) + PORTB |= _BV(IRLED); // turn off IR LED + + // Now we wait for the specified 'off' time + delay_ten_us(offtime); +} + +/* transmit IR burst, using the miles tag II format + * one IR burst is ticks*600uS on, and 600uS off + * n=1 codes 0 + * n=2 codes 1 + * n=4 codes header + */ +void transmit_ir(uint8_t ticks) { + xmitCodeElement(ticks*600/10*TIMING_CORRECTION,600/10*TIMING_CORRECTION,1); // added some correction to transmit code +} + +void transmit_ir_byte(uint8_t data) { + uint8_t tick; + int8_t i; + //DEBUGP(putstring("byte burst ")); + for (i=7;i>=0;i--) { + tick = ((data>>i)&0x01); + //DEBUGP(putnum_ud(tick)); + transmit_ir(tick+1); + } + //DEBUGP(putstring("\r\n")); +} + +int main(void) { + uint8_t i; + + TCCR1 = 0; // Turn off PWM/freq gen, should be off already + TCCR0A = 0; + TCCR0B = 0; + // set OCR for Timer1 to output this POWER code's carrier frequency (lasertag milestag II uses 56kHz) + OCR0A = freq_to_timerval(56000); + + i = MCUSR; // Save reset reason + MCUSR = 0; // clear watchdog flag + WDTCR = _BV(WDCE) | _BV(WDE); // enable WDT disable + + WDTCR = 0; // disable WDT while we setup + + DDRB = _BV(LED) | _BV(IRLED) | _BV(TX); // set the visible and IR LED pins to outputs + PORTB = _BV(LED) | // visible LED is off when pin is high + _BV(IRLED) | // IR LED is off when pin is high + _BV(TX); // Turn on pullup on region switch pin + + DEBUGP(putstring_nl("\r\nHello cock suckers! Ready to swallow some infrared?\r\n")); + + // check the reset flags + if (i & _BV(BORF)) { // Brownout + // Flash out an error and go to sleep + flashslowLEDx(2); + tvbgone_sleep(); + } + + delay_ten_us(5000); // Let everything settle for a bit + + // blink half the time for 4 seconds + for (i=0;i<4;i++) { + PORTB &= ~_BV(LED); // turn on visible LED at PB0 by pulling pin to ground + delay_ten_us(50000);// wait 0.5s + PORTB |= _BV(LED); // turn off visible LED at PB0 by pulling pin to +3V + delay_ten_us(50000);// wait 0.5s + } + + // blink fast for 1 seconds + for (i=0;i<5;i++) { + PORTB &= ~_BV(LED); // turn on visible LED at PB0 by pulling pin to ground + delay_ten_us(10000); // wait 0.1s + PORTB |= _BV(LED); // turn off visible LED at PB0 by pulling pin to +3V + delay_ten_us(10000); // wait 0.1s + } + + // turn on watchdog timer immediately, this protects against + // a 'stuck' system by resetting it + wdt_enable(WDTO_8S); // 1 second long timeout + + DEBUGP(putstring("fire in the hole\r\n")); + transmit_ir(4); + transmit_ir_byte(0x83); + transmit_ir_byte(0x0b); + transmit_ir_byte(0xe8); // end byte not needed + + delay_ten_us(50000); // wait 0.1s + // the protprietary recorded version + transmit_ir(4); + transmit_ir_byte(0x84); + transmit_ir_byte(0x00); + transmit_ir_byte(0xa4); + + // We are done, no need for a watchdog timer anymore + wdt_disable(); + + // flash the visible LED on PB0 4 times to indicate that we're done + //delay_ten_us(65500); // wait maxtime + quickflashLEDx(4); + + tvbgone_sleep(); +} + + +/****************************** SLEEP FUNCTIONS ********/ + +void tvbgone_sleep( void ) +{ + // Shut down everything and put the CPU to sleep + TCCR0A = 0; // turn off frequency generator (should be off already) + TCCR0B = 0; // turn off frequency generator (should be off already) + PORTB |= _BV(LED) | // turn off visible LED + _BV(IRLED); // turn off IR LED + + wdt_disable(); // turn off the watchdog (since we want to sleep + delay_ten_us(1000); // wait 10 millisec + + MCUCR = _BV(SM1) | _BV(SE); // power down mode, SE enables Sleep Modes + sleep_cpu(); // put CPU into Power Down Sleep Mode +} + + +/****************************** LED AND DELAY FUNCTIONS ********/ + + +// This function delays the specified number of 10 microseconds +// it is 'hardcoded' and is calibrated by adjusting DELAY_CNT +// in main.h Unless you are changing the crystal from 8mhz, dont +// mess with this. +void delay_ten_us(uint16_t us) { + uint8_t timer; + while (us != 0) { + // for 8MHz we want to delay 80 cycles per 10 microseconds + // this code is tweaked to give about that amount. + for (timer=0; timer <= DELAY_CNT; timer++) { + NOP; + NOP; + } + NOP; + us--; + } +} + + +// This function quickly pulses the visible LED (connected to PB0, pin 5) +// This will indicate to the user that a code is being transmitted +void quickflashLED( void ) { + PORTB &= ~_BV(LED); // turn on visible LED at PB0 by pulling pin to ground + delay_ten_us(3000); // 30 millisec delay + PORTB |= _BV(LED); // turn off visible LED at PB0 by pulling pin to +3V +} + +// This function just flashes the visible LED a couple times, used to +// tell the user what region is selected +void quickflashLEDx( uint8_t x ) { + quickflashLED(); + while(--x) { + wdt_reset(); + delay_ten_us(15000); // 150 millisec delay between flahes + quickflashLED(); + } + wdt_reset(); // kick the dog +} + +// This is like the above but way slower, used for when the tvbgone +// crashes and wants to warn the user +void flashslowLEDx( uint8_t num_blinks ) +{ + uint8_t i; + for(i=0;i // this contains all the IO port definitions +#include // definitions for interrupts +#include "main.h" +#include "util.h" + +#define TXPORT PORTB +#define TX 1 + +#if (DEBUG == 1) + +#define SERIALDELAY 75 // to make 19200 baud +void serialdelay(void) { + uint16_t timer; + for (timer=0; timer <= SERIALDELAY; timer++) { + NOP; + } +} + + +void uart_putchar(char d) { + int i; + cli(); // turn off interrupts, make it nice & kleen + + TXPORT &= ~_BV(TX); + serialdelay(); + for (i=0; i< 8; i++) { + if (d & 0x1) { + TXPORT |= _BV(TX); + } else { + TXPORT &= ~_BV(TX); + } + serialdelay(); + d >>= 1; + } + TXPORT |= _BV(TX); + sei(); // turn on interrupts + serialdelay(); +} + +void printhex(uint8_t hex) { + hex &= 0xF; + if (hex < 10) + uart_putchar(hex + '0'); + else + uart_putchar(hex + 'A' - 10); +} + +void putnum_uh(uint16_t n) { + if (n >> 12) + printhex(n>>12); + if (n >> 8) + printhex(n >> 8); + if (n >> 4) + printhex(n >> 4); + printhex(n); + + return; +} + + +void putnum_ud(uint16_t n) { + uint8_t cnt=0, flag=0; + + while (n >= 10000UL) { flag = 1; cnt++; n -= 10000UL; } + if (flag) uart_putchar('0'+cnt); + cnt = 0; + while (n >= 1000UL) { flag = 1; cnt++; n -= 1000UL; } + if (flag) uart_putchar('0'+cnt); + cnt = 0; + while (n >= 100UL) { flag = 1; cnt++; n -= 100UL; } + if (flag) uart_putchar('0'+cnt); + cnt = 0; + while (n >= 10UL) { flag = 1; cnt++; n -= 10UL; } + if (flag) uart_putchar('0'+cnt); + cnt = 0; + uart_putchar('0'+n); + return; +} + +void ROM_putstring(const char *str, uint8_t nl) { + uint8_t i; + + for (i=0; pgm_read_byte(&str[i]); i++) { + uart_putchar(pgm_read_byte(&str[i])); + } + if (nl) { + uart_putchar('\n'); uart_putchar('\r'); + } +} + +#endif diff --git a/avr/ir grenade/util.h b/avr/ir grenade/util.h new file mode 100644 index 0000000..352a205 --- /dev/null +++ b/avr/ir grenade/util.h @@ -0,0 +1,21 @@ +#include + +uint8_t internal_eeprom_read(uint16_t addr); +void internal_eeprom_write(uint16_t addr, uint8_t data); +void delay_ms(uint16_t ms); +void uart_init(uint16_t baud); +void uart_putchar(char c); +char uart_getchar(void); +char uart_getch(void); +void putnum_ud(uint16_t n); +void putnum_uh(uint16_t n); +void printhex(uint8_t hex); +void ROM_putstring(const char *str, uint8_t); +uint16_t uart_read16(void); +void print_div(void); + +#define putstring(x) ROM_putstring(PSTR(x), 0) +#define putstring_nl(x) ROM_putstring(PSTR(x), 1) + +#define NOP __asm__ __volatile__ ("nop") +