.include "m1281def.inc"

; unique id placement point for ease of implementation
.equ group_id = $37 ; place unique id here, must be one of $2b -> $3a, inclusive
; use the same number for all transmitters within a group.
; do not have more than one transmitter per group on at a time (its probably
; ok to do so during testing, but is to avoided if possible).

; use increments of 4 for src_addr and des_addr
; csma_seed = 8 x src_addr
.equ src_addr = ((256 * group_id) + $90) ; place unique source address here
.equ csma_seed = low(src_addr)*$08 ; random backoff exponent - must be unique,<$0800 
.equ des_addr1 = ((256 * group_id) + $a0) ; des_addr of slave node 1
.equ des_addr2 = ((256 * group_id) + $b0) ; des_addr of slave node 2
.equ des_addr3 = ((256 * group_id) + $c0) ; des_addr of slave node 3
.equ des_addr4 = ((256 * group_id) + $d0) ; des_addr of slave node 4
.equ pan_id = $a4c3 ; system pan_id
.equ retries = $38 ; high nibble = frame retries,low nibble = 2x(csma retries)
.equ channel = group_id ; tx/rx channel, $2b -> $3a valid
.equ led_rate1 = $0100 ; 2.1s led oscillation rate 1 (T(s) = led_rate x 1024 / 125000)
.equ led_rate2 = $0200 ; 4.2s led oscillation rate 2
.equ led_rate3 = $0100 ; ramp time
.equ on_time = $4e20 ; led on time (time (ms) = 1.024ms x on_time)
.equ off_time = $4e20 ; led off time (time (ms) = 1.024ms x off_time)
.equ level1 = $02cc ; led constant light level for mode7 ($03ff max)
.equ ratio1 = $b3 ; 70% ratio of max light level for mode3 ($ff max)
.equ ratio2 = $80 ; 50% ratio of max light level for mode5 ($ff max)

; LED modes:
;
; mode0 (r21=$00) = all leds off
; mode1 (r21=$01) = just turned on - green on for 20s - blue off
; mode2 (r21=$02) = just turned off - blue on for 20s - green off
; mode3 (r21=$03) = oscillate blue and green at rate1, ratio1
; mode4 (r21=$04) = continue with mode3 until light goes off
; mode5 (r21=$05) = oscillate green at rate2, ratio2 - blue at full
; mode6 (r21=$06) = continue with mode5 until light goes off
; mode7 (r21=$07) = green on at constant level - blue off
; mode8 (r21=$08) = ramp green down to 0%, ramp blue up to 100%
; mode9 (r21=$09) = ramp green up to 70%, ramp blue down to 0%

; RF modes:
;
; mode0 (r18=$00) = RF unit off
; mode1 (r18=$01) = RF in TX,just sent packet1
; mode2 (r18=$02) = RF in TX,just sent packet2
; mode3 (r18=$03) = RF in TX,just sent packet3
; mode4 (r18=$04) = RF in TX,just sent packet4
; mode5 (r18=$05) = RF completed all TX
; mode6 (r18=$06) = RF in RX,waiting for broadcast

.org 0
rjmp start
.org int5addr
rjmp clearirq
.org OVF2addr
rjmp wakeup
.org OVF4addr
rjmp timer4_int
.org OC5Aaddr
rjmp timer5_int

; PIN ASSIGNMENTS:
;
; PB5 = LED1 (OC1A) = green
; PB6 = LED2 (OC1B) = blue
; PG0 = IR CLK
; PG1 = IR DATA
; PG2 = PIR DATA
;
; REGISTER ASSIGNMENTS:
;
; r0  temporary data register
; r1  temporary data register
; r2  temporary data register
; r3  temporary data register
; r4  last mode register
; r5  
; r6  
; r7  
; r8  temporary data register
; r9  temporary data register
; r10 last transmission counter lsb
; r11 last transmission counter msb
; r12 
; r13 
; r14 
; r15 
; r16 temporary register
; r17 temporary data register
; r18 rf state register
; r19 timer register 0
; r20 timer register 1
; r21 led mode register
; r22 wakeup delay timer
; r23 data transmit register
; r24 sleep command register
; r25 pir/ir data register
; xl  green led brightness counter lsb
; xh  green led brightness counter msb
; yl  blue led brightness counter lsb
; yh  blue led brightness counter msb
; zl  lpm pointer lsb
; zh  lpm pointer msb

start: ; configure microcontroller registers
; using internal 8MHz RC oscillator
; system clock set to 1MHZ by /8 prescaler in fuse bits
ldi r16,high(RAMEND)
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16,low(RAMEND)
out SPL,r16
ldi r16,$17
out ddrb,r16 ; set ss,sclk,mosi,slp_tr as output
ldi r16,8
out portb,r16 ; enable pullup for miso
ldi r16,1
out spsr,r16 ; set up spi
ldi r16,$50
out spcr,r16 ; set up spi
sbi portb,portb0 ; set ss pin high
cbi portb,portb4 ; set slp_tr low
sbi ddra,dda7 ; set reset pin as output
cbi porta,porta7 ; initiate a reset of rf unit
nop ; wait appropriate hold time (>625ns)
sbi porta,porta7 ; pull reset high on rf unit
ldi r16,$0c
sts eicrb,r16 ; configure int5 for rising edge
ldi r16,$20
out eimsk,r16 ; enable int5
sbi ddrb,ddb5 ; set PB5 to output for LED1
sbi ddrb,ddb6 ; set PB6 to output for LED2
sbi ddrg,ddg0 ; set PG0 to output for IR CLK
sbi portg,portg0 ; set IR CLK to high to sleep the IR sensor
cbi portb,portb5 ; turn leds off
cbi portb,portb6
clr r18 ; initialize rf state register
clr r25 ; initialize sensor register
clr r23 ; initialize data register
ldi r24,$29 ; initialize rf state register to sleep mode
ldi r21,$00 ; set led mode register to mode0 = green leds off
ldi r16,$00
mov r10,r16 ; initialize last transmission register
mov r11,r16

;turn off watchdog timer
wdr ; reset wdt
ldi r16,$00 ; clear all resets
out mcusr,r16 ; turn off wdrf
ldi r16,$1e
sts wdtcsr,r16 ; enable writing of wdt
ldi r16,$00
sts wdtcsr,r16 ; turn off wdt

;setup power reduction registers
ldi r16,$ab
sts prr0,r16 ; turn off adc,usart0,t0,t1,twi
ldi r16,$3f
sts prr1,r16 ; turn off t5,t4,t3,usart3,usart2,usart1
ldi r16,$90
out acsr,r16 ; turn off comparator

;setup t2 as rtc at 2s interval wakeup
ldi r16,$20
sts assr,r16 ; set t2 to assynchronous mode
ldi r16,$06
sts tccr2b,r16 ; set t2 prescaler to /256 - 2s wakeup period

;make sure t2 is done rewriting itself
checkassr:

lds r16,assr
andi r16,$1f ; check assr(4:0) clear
brne checkassr

ldi r16,$07
sts tifr2,r16 ; clear all pending interrupts
ldi r16,$01
sts timsk2,r16 ; enable t2 overflow interrupt

;configure rf unit registers

;wait
ldi r20,$80 ; load the wait timer to 128 cycles (x10/ck)
rcall wait2 ; wait ~(1280/1MHz = 1.2ms) for rf unit to stabilize

;go to trx_off state
rcall txoff ; go to trx_off state on rf unit

;setup clkm
ldi r16,$c3 ; load first data byte - write trx_ctrl_0 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
clr r16 ; load second data byte - turn off clkm
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup short_addr_0
ldi r16,$e0 ; load first data byte - write short_addr_0 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,low(src_addr) ; load second data byte - src_addr lsb
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup short_addr_1
ldi r16,$e1 ; load first data byte - write short_addr_1 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,high(src_addr) ; load second data byte - src_addr msb
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup pan_id_0
ldi r16,$e2 ; load first data byte - write pan_id_0 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,low(pan_id) ; load second data byte - pan_id lsb
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup pan_id_1
ldi r16,$e3 ; load first data byte - write pan_id_1 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,high(pan_id) ; load second data byte - pan_id msb
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup phy_cc_ca - set channel id
ldi r16,$c8 ; load byte - write phy_cc_ca register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,channel ; load data byte - 
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup phy_tx_pwr - turn crc on
ldi r16,$c5 ; load byte - write phy_tx_pwr register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,$80 ; load data byte - auto_crc=on,pwr=+3dbm
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup xah_ctrl - set frame and csma retries
ldi r16,$ec ; load byte - write xah_ctrl register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,retries ; load data byte - frame and csma retries
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup csma_seed_1
ldi r16,$ee ; load byte - write csma_seed_1 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,high(csma_seed) ; load data byte - min_be=0,aack_set=0,i_am_coord=0,csma(10:8)
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;setup csma_seed_0
ldi r16,$ed ; load first data byte - write csma_seed_1 register
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send data
ldi r16,low(csma_seed) ; load data byte - csma(7:0)
rcall spiwrite ; send data
sbi portb,portb0 ; pull ss high

;clear pending irqs on rf unit 
ldi r16,$8f ; load first data byte - read register irq_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte and clear pending irqs
sbi portb,portb0 ; pull ss high

;enable irqs on rf unit
ldi r16,$ce ; load first data byte - write register irq_mask command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$08 ; load second data byte - trx_end only
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

;enable wdt to reduce lockups during sleep or interrupts
wdr ; reset wdt
ldi r16,$1e
sts wdtcsr,r16 ; enable writing of wdt
ldi r16,$28
sts wdtcsr,r16 ; turn on wdt, 4s timer

;clear pending irqs on micro
ser r16
out eifr,r16 ; clear any interrupt flags that are set

;enable interrupts on micro
sei ; turn on interrupts

sleepstate: ; sleep while waiting for ON command

sbi portb,portb4 ; pull slp_tr high to enter sleep mode
ldi r16,$07
out smcr,r16 ; set to power-save mode and enable sleep mode
ldi r22,$05 ; set up repeat timer to 5 cycles

sleepstate1:

sleep
nop
nop
nop
dec r22
brne sleepstate1 ; return to sleep if not yet 60s
clr r16
out smcr,r16 ; disable sleep mode
cbi portb,portb4 ; pull slp_tr low to exit sleep mode
ldi r20,$28 ; load wait timer to 40 cycles (x10/ck)
rcall wait2 ; wait ~(400/1MHZ = 400us) for rf unit clock to stabilize
rcall checktxoff ; check to see if rf unit is in tx_off state
rcall rxonaack ; put rf unit into rx state
ldi r18,$06 ; set RF state to RX,waiting for broadcast
ldi r19,$a0 ; sample rf for ~500ms

long_wait: ; long wait time (~3ms for every bit in r19)

ldi r20,$ff ; setup wait2 to full cycle (~3ms)
rcall wait2
cpi r24,$d6 ; check if set to ON state
breq turn_on
dec r19
brne long_wait ; keep waiting if not done yet
rcall forcetxoff ; turn off rf unit
ldi r18,$00 ; set RF state to OFF
rjmp sleepstate ; go to sleep

turn_off: ; shut off lights and sleep rf unit and micro

rcall forcetxoff ; turn off rf unit
ldi r18,$00 ; set RF state to OFF
ldi r16,$00 ; turn off t4
sts tccr4b,r16 ; turn off t4
sts timsk4,r16 ; disable all t4 interrupts
rcall mode2 ; do led off function

turn_off_wait: ; wait till turn off function is done

nop
nop
nop
cpi r21,$02 ; check if done
breq turn_off_wait

;turn off remaining parts
ldi r16,$00 ; turn off t3/t1/t5
sts tccr5b,r16 ; turn off t5
sts tccr1b,r16 ; turn off t1
sts timsk5,r16 ; disable all t5 interrupts
sts tccr1a,r16 ; disable OC1A and OC1B
ldi r16,$ab
sts prr0,r16 ; disable adc,usart0,t1,t0,twi
ldi r16,$3f
sts prr1,r16 ; disable t5,t4,t3,usart3,usart2,usart1
cbi portb,portb5 ; turn off leds
cbi portb,portb6
ldi r21,$00 ; set led mode register to mode0 = green leds off
rjmp sleepstate ; go to sleep

turn_on: ; turn on rf unit and lights

ldi r16,$a3 ; enable t1
sts prr0,r16 ; turn off adc,usart0,t0,twi
ldi r16,$0f ; enable t4,t5
sts prr1,r16 ; turn off usart3,usart2,usart1
ldi r16,$a3 ; set up t1 for fast pwm mode
sts tccr1a,r16 ; set OC1A and OC1B to invert mode, T1 to fast PWM mode
ldi r16,$00
sts ocr1ah,r16 ; turn off green leds
sts ocr1al,r16
sts ocr1bh,r16 ; turn off blue leds
sts ocr1bl,r16
ldi r16,$0a
sts tccr1b,r16 ; set to fast PWM mode, set to clk/8 (125kHz)
rcall mode1 ; do led turn on function

turn_on_wait: ; wait until turn on function is done

nop
nop
nop
cpi r21,$01 ; check if done
breq turn_on_wait
ldi r16,$00 ; reset t4 counter
sts tcnt4h,r16
sts tcnt4l,r16
ldi r16,$01
sts timsk4,r16 ; turn on overflow interrupt
ldi r16,$02
sts tccr4b,r16 ; set t4 to normal mode, clk/8
rcall mode7 ; turn on mode7

test0: ; wait for 3 off commands before acting

nop
nop
rcall main ; check sensors
cpi r24,$29 ; check if off command recieved
brne test0
clr r24

test1: ; wait for 3 turn off commands before acting

nop
nop
rcall main ; check sensors
cpi r24,$29 ; check if off command recieved
brne test1
clr r24

test2: ; wait for 3 turn off commands before acting

nop
nop
rcall main ; check sensors
cpi r24,$29 ; check if off command recieved
brne test2
rjmp turn_off ; shut off rf unit

main:

clr r23 ; reset data register
sbic ping,ping2 ; check for PIR motion
ldi r23,$02 ; load PIR data
rcall ir_read ; get ir data
cpi r17,$80 ; check if above threshold
brlo donothing ; if not check if any data collected
ori r23,$01 ; add ir data

donothing: ; check if any data to be sent

tst r23 ; check if any data to be sent
breq main_done ; if no data, finish off
or r25,r23 ; else add data to sensor register
rcall send_data ; send off rf data

main_done: ; finish off

ret ; return to previous task

ir_read: ; read data from IR unit

clr r17 ; initialize data register
cbi portg,portg0 ; pull IR CLK low to initialize IR sensor
ldi r19,$20 ; setup to wait 32 x wait2 cycles (32 x 3ms = 96ms)

keepwaiting: ; delay for >70ms for data to be ready

ldi r20,$ff ; setup wait2 to full cycle (~3ms)
rcall wait2
dec r19
brne keepwaiting ; keep waiting if not done yet
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$80 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$40 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$20 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$10 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$08 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$04 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$02 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to clock data
ldi r20,$09 ; wait for ~.1ms
rcall wait2
cbi portg,portg0 ; pull IR ClK low to clock data
ldi r20,$09 ; wait ~.1ms
rcall wait2
sbic ping,ping1 ; check if IR DATA is high
ori r17,$01 ; set bit if data is set
sbi portg,portg0 ; pull IR CLK high to end data transfer
ldi r20,$ff ; wait for ~3ms to end data transfer
rcall wait2
ret ; return to previous task

send_data: ; transmit data

rcall forcetxoff
rcall txonaret ; put the rf unit in tx_aret_on state
rcall transmitpacket1 ; send packet1
ldi r18,$01 ; set RF state to packet1

check_if_done: ; wait till all packets are sent

nop
nop
nop
cpi r18,$05 ; check for done tx code
brne check_if_done
rcall forcetxoff ; got RX
rcall rxonaack
ldi r18,$06 ; set RF state to RX
ret ; return to task

txoff: ; send trx_off command to rf unit and wait till stable

ldi r16,$c2 ; load first data byte - write register trx_state command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$08 ; load second data byte - data trx_off bit
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

checktxoff: ; check current state to see if in tx_off state

ldi r16,$81 ; load first data byte - read register trx_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load second data byte - blank for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
cpi r16,$08
brne checktxoff
ret ; return to previous duty

forcetxoff: ; send trx_off command to rf unit and wait till stable

ldi r16,$c2 ; load first data byte - write register trx_state command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$03 ; load second data byte - data force_trx_off bit
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

checkforcetxoff: ; check current state to see if in tx_off state

nop ; delay for a bit to make sure the device is off
nop
nop
nop
ldi r16,$81 ; load first data byte - read register trx_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load second data byte - blank for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
cpi r16,$08
brne forcetxoff ; redo if not off - only takes 1us to turn off (changed due to lock up bug of getting stuck in check loop)
ret ; return to previous duty

pllon: ; send pll_on command to rf unit

ldi r16,$c2 ; load first data byte - write register trx_state command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$09 ; load second data byte - data pll_on bit
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

checkpllon: ; check current state to see if in pll_on state

ldi r16,$81 ; load first data byte - read register trx_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load second data byte - blank for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
cpi r16,$09
brne checkpllon
ret ; return to previous duty

txonaret: ; send trx_aret_on command to rf unit and wait till stable

ldi r16,$c2 ; load first data byte - write register trx_state command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$19 ; load second data byte - data trx_aret_on bit
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

checktxonaret: ; check current state to see if in tx_aret_on state

ldi r16,$81 ; load first data byte - read register trx_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load second data byte - blank for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
cpi r16,$19
brne checktxonaret
ret ; return to previous duty

rxonaack: ; send rx_aack_on command to rf unit and wait till stable

ldi r16,$c2 ; load first data byte - write register trx_state command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$16 ; load second data byte - data rx_aack_on bit
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

checkrxonaack: ; check current state to see if in rx_aack_on state

ldi r16,$81 ; load first data byte - read register trx_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load second data byte - blank for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
cpi r16,$16
brne checkrxonaack
ret ; return to previous duty

spiwrite: ; read and write data over spi

out spdr,r16 ; write transmitted byte to spi

wait: ; read spi register to check when done

in r16,spsr
sbrs r16,spif
rjmp wait
in r16,spdr ; write recieved byte to spi register
ret ; return to previous duty

wait2: ; wait timer (~12 cylces per value in r20)

nop
nop
nop
nop
nop
nop
nop
nop
dec r20
brne wait2
ret ; return to previous duty

clearirq: ; clear irq register and irq line

push r16 ; save temp register
in r16,sreg ; get sreg
push r16 ; push sreg on stack
ldi r16,$8f ; load first data byte - read register irq_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high

checkrf: ; check rf unit state

ldi r16,$81 ; load first data byte - read register trx_status command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load second data byte - blank for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
cpi r16,$16 ; check if in rx_aack_on
breq datacollect ; go to get data
cpi r16,$11 ; check if in busy_rx_aack
breq datacollect ; go to get data
cpi r16,$1f ; check if in state transition
breq checkrf ; keep checking till in a new state
cpi r16,$12 ; check if in busy_tx state
breq checkrf ; keep checking till in a new state
;else check successful transmit before switching back to sleep
ldi r16,$82 ; load data byte - read trx_state to get trac_status
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load data byte - blank byte for reading
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
andi r16,$e0 ; mask off trac_status
cpi r16,$60 ; check if success or data_pending success
brlo success ; skip if success

;place failure function here - not sure what that would be that is
; different than what i do for success

;ldi r18,$40 ; else set to shutdown
;pop r16 ; get off stack
;out sreg,r16 ; return sreg
;pop r16 ; return temporary register
;reti ; return from interrupt

success: ; tx success

cpi r18,$01 ; check if packet1 just sent
breq transmit2 ; send off next packet
cpi r18,$02 ; check if packet2 just sent
breq transmit3 ; send off next packet
cpi r18,$03 ; check if packet3 just sent
breq transmit4 ; send off next packet
cpi r18,$04 ; check if packet4 just sent
brne irqdone ; should place failure mode here - not sure what that would be
ldi r18,$05 ; set RF state to TX done

irqdone: ; finish interrupt and return

pop r16 ; get off stack
out sreg,r16 ; return sreg
pop r16 ; return temporary register
reti ; clear interrupt and return to previous duty

transmit2: ; transmit packet2

rcall transmitpacket2
ldi r18,$02 ; set RF state to TX packet2
rjmp irqdone ; finish off

transmit3: ; transmit packet3

rcall transmitpacket3
ldi r18,$03 ; set RF state to TX packet3
rjmp irqdone ; finish off

transmit4: ; transmit packet4

rcall transmitpacket4
ldi r18,$04 ; set RF state to TX packet4
rjmp irqdone ; finish off

datacollect: ; get data from rf unit

;get data from recieve buffer
ldi r16,$20 ; load data byte - read buffer command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - frame length byte
cpi r16,$10 ; check if frame length matches data packet
brne rx_done ; finish off if not
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save fcf(7:0)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save fcf(15:8)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - seq (used as command byte)
cpi r16,$00 ; check if command byte is $00 (ON/OFF beacon)
brne rx_done ; finish off if not
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save des_panid(7:0)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save des_panid(15:8)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save des_addr(7:0)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save des_addr(15:8)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save src_addr(7:0)
cpi r16,$54 ; check if from correct source (remote)
brne rx_done ; finish off if not
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save src_addr(15:8)
cpi r16,$bb ; check if from correct source (remote)
brne rx_done ; finish off if not
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - data byte
mov r0,r16 ; save data byte to temporary data register
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - check sequence 1
cpi r16,$ab ; check if correct
brne rx_done ; finish off if not
ldi r16,$00; load data byte - blank for reading
rcall spiwrite ; send byte - check sequence 2
cpi r16,$46 ; check if correct
brne rx_done ; finish off if not
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - check sequence 3
cpi r16,$37 ; check if correct
brne rx_done ; finish off if not
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - check sequence 4
cpi r16,$d2 ; check if correct
brne rx_done ; finish off if not
mov r24,r0 ; move data to rf state register
clr r10 ; reset last tranmission register
clr r11

rx_done: ; finish off

sbi portb,portb0 ; pull ss high in case not done above
pop r16 ; get off stack
out sreg,r16 ; return sreg
pop r16 ; return temporary register
reti ; done writing data

transmitpacket1: ; transmit a packet1

sbi portb,portb4 ; pull slp_tr high to begin transmit
nop ; delay to make sure the pin is high long enough
cbi portb,portb4 ; pull slp_tr low

ldi r16,$60 ; load data byte - write buffer command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$10 ; load frame length byte - total bytes excluding this one, +2
rcall spiwrite ; send byte
ldi r16,$61 ; load fcf(7:0) byte - $61 for data packet
rcall spiwrite ; send byte
ldi r16,$88 ; load fcf(15:8) byte - $88 for data packet
rcall spiwrite ; send byte
ldi r16,$02 ; load sequence byte - command(data)
rcall spiwrite ; send byte
ldi r16,low(pan_id) ; load destination panid(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(pan_id) ; load destination panid(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(des_addr1) ; load destination address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(des_addr1) ; load destination address(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(src_addr) ; load source address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(src_addr) ; load source address(15:8) byte
rcall spiwrite ; send byte
mov r16,r23 ; load data byte - sensor values
rcall spiwrite ; send byte
ldi r16,$67 ; load data byte - check sequence 1
rcall spiwrite ; send byte
ldi r16,$c1; load data byte - check sequence 2
rcall spiwrite ; send byte
ldi r16,$8a ; load data byte - check sequence 3
rcall spiwrite ; send byte
ldi r16,$9f ; load data byte - check sequence 4
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
ret ; return to previous duty

transmitpacket2: ; transmit a packet2

sbi portb,portb4 ; pull slp_tr high to begin transmit
nop ; delay to make sure the pin is high long enough
cbi portb,portb4 ; pull slp_tr low

ldi r16,$60 ; load data byte - write buffer command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$10 ; load frame length byte - total bytes excluding this one, +2
rcall spiwrite ; send byte
ldi r16,$61 ; load fcf(7:0) byte - $61 for data packet
rcall spiwrite ; send byte
ldi r16,$88 ; load fcf(15:8) byte - $88 for data packet
rcall spiwrite ; send byte
ldi r16,$02 ; load sequence byte - command(data)
rcall spiwrite ; send byte
ldi r16,low(pan_id) ; load destination panid(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(pan_id) ; load destination panid(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(des_addr2) ; load destination address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(des_addr2) ; load destination address(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(src_addr) ; load source address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(src_addr) ; load source address(15:8) byte
rcall spiwrite ; send byte
mov r16,r23 ; load data byte - sensor values
rcall spiwrite ; send byte
ldi r16,$67 ; load data byte - check sequence 1
rcall spiwrite ; send byte
ldi r16,$c1; load data byte - check sequence 2
rcall spiwrite ; send byte
ldi r16,$8a ; load data byte - check sequence 3
rcall spiwrite ; send byte
ldi r16,$9f ; load data byte - check sequence 4
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
ret ; return to previous duty

transmitpacket3: ; transmit a packet3

sbi portb,portb4 ; pull slp_tr high to begin transmit
nop ; delay to make sure the pin is high long enough
cbi portb,portb4 ; pull slp_tr low

ldi r16,$60 ; load data byte - write buffer command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$10 ; load frame length byte - total bytes excluding this one, +2
rcall spiwrite ; send byte
ldi r16,$61 ; load fcf(7:0) byte - $61 for data packet
rcall spiwrite ; send byte
ldi r16,$88 ; load fcf(15:8) byte - $88 for data packet
rcall spiwrite ; send byte
ldi r16,$02 ; load sequence byte - command(data)
rcall spiwrite ; send byte
ldi r16,low(pan_id) ; load destination panid(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(pan_id) ; load destination panid(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(des_addr3) ; load destination address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(des_addr3) ; load destination address(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(src_addr) ; load source address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(src_addr) ; load source address(15:8) byte
rcall spiwrite ; send byte
mov r16,r23 ; load data byte - sensor values
rcall spiwrite ; send byte
ldi r16,$67 ; load data byte - check sequence 1
rcall spiwrite ; send byte
ldi r16,$c1; load data byte - check sequence 2
rcall spiwrite ; send byte
ldi r16,$8a ; load data byte - check sequence 3
rcall spiwrite ; send byte
ldi r16,$9f ; load data byte - check sequence 4
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
ret ; return to previous duty

transmitpacket4: ; transmit a packet4

sbi portb,portb4 ; pull slp_tr high to begin transmit
nop ; delay to make sure the pin is high long enough
cbi portb,portb4 ; pull slp_tr low

ldi r16,$60 ; load data byte - write buffer command
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$10 ; load frame length byte - total bytes excluding this one, +2
rcall spiwrite ; send byte
ldi r16,$61 ; load fcf(7:0) byte - $61 for data packet
rcall spiwrite ; send byte
ldi r16,$88 ; load fcf(15:8) byte - $88 for data packet
rcall spiwrite ; send byte
ldi r16,$02 ; load sequence byte - command(data)
rcall spiwrite ; send byte
ldi r16,low(pan_id) ; load destination panid(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(pan_id) ; load destination panid(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(des_addr4) ; load destination address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(des_addr4) ; load destination address(15:8) byte
rcall spiwrite ; send byte
ldi r16,low(src_addr) ; load source address(7:0) byte
rcall spiwrite ; send byte
ldi r16,high(src_addr) ; load source address(15:8) byte
rcall spiwrite ; send byte
mov r16,r23 ; load data byte - sensor values
rcall spiwrite ; send byte
ldi r16,$67 ; load data byte - check sequence 1
rcall spiwrite ; send byte
ldi r16,$c1; load data byte - check sequence 2
rcall spiwrite ; send byte
ldi r16,$8a ; load data byte - check sequence 3
rcall spiwrite ; send byte
ldi r16,$9f ; load data byte - check sequence 4
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
ret ; return to previous duty

wakeup: ; clear interrupts and return to previous task
nop
nop
nop
push r16 ; save temp register
in r16,sreg ; get sreg
push r16 ; save sreg
ldi r16,$01
add r10,r16 ; increment time since last transmission register
clr r16
adc r11,r16 ; increment msb of last transmission register
brcs error ; reset program if no transmission in past 36 hours
wdr ; reset watchdog timer
pop r16 ; get off stack
out sreg,r16 ; return sreg
pop r16 ; return temporary register
reti

error: ; idle till watchdog resets the program

nop
nop
nop
rjmp error ; keep waiting

mode1: ; LED mode1 = turn on green led for 20s

ldi r16,$00 ; reset t5
sts tcnt5h,r16
sts tcnt5l,r16
ldi r16,high(on_time) ; set up oscillation time
sts ocr5ah,r16
ldi r16,low(on_time)
sts ocr5al,r16
ldi r16,$02
sts timsk5,r16 ; enable t5 output compare match A interrupt
ldi r16,$05 ; turn on t5
sts tccr5b,r16 ; set to clk/1024 (976Hz)
ldi r16,$ff ; turn on green leds full brightness
sts ocr1ah,r16
sts ocr1al,r16
ldi r16,$00 ; turn off blue leds
sts ocr1bh,r16
sts ocr1bl,r16
ldi r21,$01 ; set green led mode register to mode1
ret ; return to previous task

mode2: ; LED mode2 = turn on blue led for 20s

ldi r16,$00 ; reset t5
sts tcnt5h,r16
sts tcnt5l,r16
ldi r16,high(off_time) ; set up oscillation time
sts ocr5ah,r16
ldi r16,low(off_time)
sts ocr5al,r16
ldi r16,$02
sts timsk5,r16 ; enable t5 output compare match A interrupt
ldi r16,$05 ; turn on t5
sts tccr5b,r16 ; set to clk/1024 (976Hz)
ldi r16,$ff ; turn on blue leds full brightness
sts ocr1bh,r16
sts ocr1bl,r16
ldi r16,$00 ; turn off green leds
sts ocr1ah,r16
sts ocr1al,r16
ldi r21,$02 ; set green led register to off
ret ; return to previous task

mode3: ; LED mode3 = oscillate at a fixed rate - green

cpi r21,$03 ; check if already in mode3
breq mode3_done ; finish off if already in mode3
cpi r21,$04 ; check if already in mode3
breq mode3_done ; finish off if already in mode3
ldi r16,$00 ; reset t5
sts tcnt5h,r16
sts tcnt5l,r16
ldi r16,high(led_rate1) ; set up oscillation time
sts ocr5ah,r16
ldi r16,low(led_rate1)
sts ocr5al,r16
ldi r16,$02
sts timsk5,r16 ; enable t5 output compare match A interrupt
ldi r16,$0a ; turn on t5
sts tccr5b,r16 ; set to ctc mode, set to clk/8 (125kHz)
ldi xh,$24 ; intialize green led brightness register
clr xl
ldi yh,$20 ; intialize blue led brightness register
clr yl

mode3_done: ; finish off

ldi r21,$03 ; set led mode register to mode3
ret ; return to previous task

mode5: ; LED mode5 = oscillate at a fixed rate - blue

cpi r21,$05 ; check if already in mode5
breq mode5_done ; finish off if already in mode5
cpi r21,$06 ; check if already in mode5
breq mode5_done ; finish off if already in mode5
ldi r16,$00 ; reset t5
sts tcnt5h,r16
sts tcnt5l,r16
ldi r16,high(led_rate2) ; set up oscillation time
sts ocr5ah,r16
ldi r16,low(led_rate2)
sts ocr5al,r16
ldi r16,$02
sts timsk5,r16 ; enable t5 output compare match A interrupt
ldi r16,$0a ; turn on t5
sts tccr5b,r16 ; set to ctc mode, set to clk/8 (125kHz)
ldi r16,$3f ; set blue leds to full
sts ocr1bh,r16
sts ocr1bl,r16
ldi xh,$20 ; intialize green led brightness register
clr xl

mode5_done: ; finish off

ldi r21,$05 ; set led mode register to mode5
ret ; return to previous task

mode3_int:

rjmp mode3_int1

mode5_int:

rjmp mode5_int1

mode8_int:

rjmp mode8_int1

mode9_int:

rjmp mode9_int1

timer5_int: ; do timer interrupt operation for blue led

push r16 ; save temp register
in r16,sreg ; get sreg
push r16 ; save sreg
cpi r21,$01 ; check if in mode1
breq mode1_int
cpi r21,$02 ; check if in mode2
breq mode2_int
cpi r21,$03 ; check if in mode3
breq mode3_int
cpi r21,$04 ; check if in mode4
breq mode3_int
cpi r21,$05 ; check if in mode5
breq mode5_int
cpi r21,$06 ; check if in mode6
breq mode5_int
cpi r21,$07 ; check if in mode7
breq mode7_int
cpi r21,$08 ; check if in mode8
breq mode8_int
cpi r21,$09 ; check if in mode9
breq mode9_int

;else if no known modes
ldi r16,$00
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
sts ocr1bh,r16 ; turn off blue leds
sts ocr1bl,r16
sts ocr1ah,r16 ; turn off green leds
sts ocr1al,r16
ldi r21,$00 ; set led mode register to mode0 = all leds off
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode1_int: ; turn off green leds

ldi r16,$00
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
sts ocr1ah,r16 ; turn off green leds
sts ocr1al,r16
sts ocr1bh,r16 ; make sure blue leds are off
sts ocr1bl,r16
ldi r21,$00 ; set led mode register to mode0 = green leds off
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode2_int: ; turn off blue leds

ldi r16,$00
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
sts ocr1bh,r16 ; turn off blue leds
sts ocr1bl,r16
sts ocr1ah,r16 ; make sure green leds are off
sts ocr1al,r16
ldi r21,$00 ; set led mode register to mode0 = blue leds off
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode7_int: ; t5 should not be active in mode7 - so just shut it off

ldi r16,$00
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode3_int1: ; increment PWM value for green and blue leds

movw z,y ; move blue led counter to lpm register
lpm r0,z+
lpm r1,z+
movw r9:r8,r1:r0 ; prepare to scale
ldi r16,ratio1 ; fetch brightness ratio
rcall scale ; scale values
movw y,z ; move blue led counter back
sts ocr1bh,r9 ; change blue led brightness
sts ocr1bl,r8
movw z,x ; move green led counter to lpm register
lpm r0,z+
lpm r1,z+
movw r9:r8,r1:r0 ; prepare to scale
ldi r16,ratio1 ; fetch brightness ratio
rcall scale ; scale values
andi zh,$27
movw x,z ; move green led counter back
sts ocr1ah,r9 ; change green led brightness
sts ocr1al,r8
cpi yh,$28 ; check if at end of count
breq mode3_count_end
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode3_count_end: ; wrap count around or shut off

cpi r21,$04 ; check if fade out
breq mode3_end
ldi yh,$20 ; re-intialize blue led counter
clr yl
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode3_end: ; go to mode7 if done

mov r16,r4 ; get last command value
cpi r16,$01 ; check if IR sensor activated in past 500ms
breq mode3_ir
cpi r16,$03 ; check if IR sensor activated in past 500ms
breq mode3_ir
cpi r16,$00 ; check if no commands recieved
breq mode3_end1
ldi yh,$20 ; else re-intialize blue led counter
clr yl
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode3_end1: ; go to mode7

ldi r16,$00 ; turn off counter
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
rcall mode7
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode3_ir: ; transition to mode5

ldi r16,$00 ; turn off counter
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
rcall mode8 ; transition to mode5
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode8_int1: ; increment/decrement PWM values for the leds

ldi r16,$03 ; check if blue at top
cpi yl,$ff
cpc yh,r16
brlo mode8_int_inc ; increment if not done
ldi r16,$00 ; check if green at bottom
cpi xl,$01
cpc xh,r16
brsh mode8_int_dec ; decrement if not done
ldi r16,$00 ; else were done with this operation
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
mov r16,r4 ; get last command value
cpi r16,$00 ; check if no sensor activated in past 500ms
breq mode8_end1
cpi r16,$02 ; check if PIR sensor activated in past 500ms
breq mode8_end1
rcall mode5 ; else transition to mode5
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode8_end1: ; transition to mode9

rcall mode9
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode8_int_inc: ; increment blue counter

adiw y,$01 ; else increment blue counter
sts ocr1bh,yh ; set blue leds to new value
sts ocr1bl,yl
ldi r16,$00 ; check if green at bottom
cpi xl,$01
cpc xh,r16
brlo mode8_int_done ; skip decrement if already done

mode8_int_dec: ; decrement green counter

sbiw x,$01 ; else decrement green counter
sts ocr1ah,xh ; set green leds to new value
sts ocr1al,xl

mode8_int_done: ; check if green at bottom

pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode9_int1: ; increment/decrement PWM values for the leds

ldi r16,$02 ; check if green at top
cpi xl,$cc
cpc xh,r16
brlo mode9_int_inc ; increment if not done
ldi r16,$00 ; check if blue at bottom
cpi yl,$01
cpc yh,r16
brsh mode9_int_dec ; decrement if not done
ldi r16,$00 ; else were done with this operation
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
mov r16,r4 ; get last command value
cpi r16,$00 ; check if no sensor activated in past 500ms
breq mode9_end1
cpi r16,$02 ; check if PIR sensor activated in past 500ms
breq mode9_end2
rcall mode8 ; else transition to mode8
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode9_end1: ; transition to mode7

rcall mode7
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode9_end2: ; transition to mode3

rcall mode3
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode9_int_inc: ; increment green counter

adiw x,$01 ; else increment green counter
sts ocr1ah,xh ; set green leds to new value
sts ocr1al,xl
ldi r16,$00 ; check if blue at bottom
cpi yl,$01
cpc yh,r16
brlo mode9_int_done ; skip decrement if already done

mode9_int_dec: ; decrement blue counter

sbiw y,$01 ; else decrement blue counter
sts ocr1bh,yh ; set blue leds to new value
sts ocr1bl,yl

mode9_int_done: ; check if green at bottom

pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode5_int1: ; increment PWM value for green led

movw z,x ; move green led counter to lpm register
lpm r0,z+
lpm r1,z+
movw r9:r8,r1:r0 ; prepare to scale
ldi r16,ratio2 ; fetch brightness ratio
rcall scale ; scale values
movw x,z ; move green led counter back
sts ocr1ah,r9 ; change green led brightness
sts ocr1al,r8
cpi zh,$28 ; check if at end of count
breq mode5_count_end
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode5_count_end: ; wrap count around or shut off

cpi r21,$06 ; check if fade out
breq mode5_end
ldi xh,$20 ; re-intialize green led counter
clr xl
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode5_end: ; shut off blue led and turn off counter

mov r16,r4 ; get last command value
cpi r16,$02 ; check if PIR sensor activated in past 500ms
breq mode5_end1
cpi r16,$00 ; check if no command recieved
breq mode5_end1
ldi xh,$20 ; else re-intialize green led counter
clr xl
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

mode5_end1: ; transition to mode7 or mode3

ldi r16,$00
sts tccr5b,r16 ; turn off t5
sts timsk5,r16 ; disable all t5 interrupts
rcall mode9 ; begin transition to mode7 or mode3
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

timer4_int: ; update current led modes

push r16 ; save temp register
in r16,sreg ; get sreg
push r16 ; save sreg
cpi r25,$00 ; check if no sensor activity in past 500ms
breq done_command
cpi r25,$01 ; check if IR sensor activated in past 500ms
breq ir_command
cpi r25,$02 ; check if PIR sensor activated in past 500ms
breq pir_command
cpi r25,$03 ; check if both PIR and IR activated in past 500ms
breq ir_command

timer4_done: ; finish off

mov r4,r25 ; backup last state
clr r25 ; reset led state register
pop r16
out sreg,r16 ; restore sreg
pop r16 ; restore temp register
reti

done_command: ; do finish off function

cpi r21,$03 ; check if in mode3
breq end_mode3
cpi r21,$05 ; check if in mode5
breq end_mode5
rjmp timer4_done

end_mode3: ; end mode3 since no new data was recieved

ldi r21,$04 ; set green led state to end function
rjmp timer4_done

end_mode5: ; end mode5 since no new data was recieved

ldi r21,$06 ; set blue led state to end function
rjmp timer4_done

ir_command: ; do ir sensor function

cpi r21,$03 ; check if in mode3
breq end_mode3
cpi r21,$07 ; check if in mode7
brne timer4_done
rcall mode8
rjmp timer4_done ; finish off

pir_command: ; do pir sensor function

cpi r21,$05 ; check if in mode5
breq end_mode5
cpi r21,$07 ; check if in mode7
brne timer4_done
rcall mode3 ; turn on slow oscillation green
rjmp timer4_done ; finish off

mode7: ; put leds in mode7 - green leds on at low brightness, blue off

cpi r21,$07 ; check if already in mode7
breq mode7_done ; finish off
ldi r16,high(level1) ; turn on green leds
sts ocr1ah,r16
ldi r16,low(level1)
sts ocr1al,r16
ldi r16,$00 ; turn off blue leds
sts ocr1bh,r16
sts ocr1bl,r16
ldi r21,$07 ; set green led mode register to mode7

mode7_done: ; finish off

ret ; return to previous task

mode8: ; put leds in mode8 - ramp green down, ramp blue up

cpi r21,$08 ; check if already in mode8
breq mode8_done ; finish off
ldi r16,$00 ; reset t5
sts tcnt5h,r16
sts tcnt5l,r16
ldi r16,high(led_rate3) ; set up ramp time
sts ocr5ah,r16
ldi r16,low(led_rate3)
sts ocr5al,r16
ldi r16,$02
sts timsk5,r16 ; enable t5 output compare match A interrupt
ldi r16,$0a ; turn on t5
sts tccr5b,r16 ; set to ctc mode, set to clk/8 (125kHz)
lds xl,ocr1al ; fetch current green value
lds xh,ocr1ah ; store to counter register
lds yl,ocr1bl ; fetch current blue value
lds yh,ocr1bh ; store to counter register
ldi r21,$08 ; set led mode register to mode8

mode8_done: ; finish off

ret ; return to previous task

mode9: ; put leds in mode9 - ramp green up, ramp blue down

cpi r21,$09 ; check if already in mode9
breq mode9_done ; finish off
ldi r16,$00 ; reset t5
sts tcnt5h,r16
sts tcnt5l,r16
ldi r16,high(led_rate3) ; set up ramp time
sts ocr5ah,r16
ldi r16,low(led_rate3)
sts ocr5al,r16
ldi r16,$02
sts timsk5,r16 ; enable t5 output compare match A interrupt
ldi r16,$0a ; turn on t5
sts tccr5b,r16 ; set to ctc mode, set to clk/8 (125kHz)
lds xl,ocr1al ; fetch current green value
lds xh,ocr1ah ; store to counter register
lds yl,ocr1bl ; fetch current blue value
lds yh,ocr1bh ; store to counter register
ldi r21,$09 ; set led mode register to mode9

mode9_done: ; finish off

ret ; return to previous task

scale: ; scale values for led brightness, mutiplicands in r9:r8, and r16

mul r9,r16 ; unsigned Ah x unsigned B
movw r3:r2,r1:r0 ; store result
mul r8,r16 ; unsigned Al x unsigned B
clr r16 ; create null register
add r2,r1 ; add results
adc r3,r16
movw r9:r8,r3:r2 ; put result back into same register
ret ; return to previous task

.org $1000
.include "sine_10b.asm"




