.include "m1281def.inc"

; increment of 4 for src_addr
; csma_seed = 8 x src_addr
.equ src_addr = $aab8 ; place unique source address here
.equ csma_seed = low(src_addr)*$08 ; random backoff exponent - must be unique,<$0800 
.equ home_addr = $aab1 ; local node des_addr
.equ pan_id = $abcd ; system pan_id
.equ retries = $38 ; high nibble = frame retries,low nibble = 2x(csma retries)
.equ channel = $36 ; tx/rx channel, $2b -> $3a valid
.equ stepsize = $08 ; control stepsize
.equ hysteresis = $01 ; hysteresis on control setpoint
.equ delay = $02 ; motor turn on delay msb (32.768ms per bit)
.equ motor_time = $05 ; number of 128us intervals in motor on-time increments ($05 = 164ms)

.org 0
rjmp start
.org int4addr
rjmp wakeupshit15
.org int5addr
rjmp clearirq
.org OVF2addr
rjmp wakeup
.org ADCCaddr
rjmp wakeupadc
.org OC5Aaddr
rjmp timer5int

; lightsensor = pf0(adc0)
; shit15 data = pe4(int4)
; shit15 clock = pe0
; wind sensor = pd6(t1)
; current threshold = pe7(int7)
; direction = pg1
; brake = pg0
; pwm = pb7(oc0a)
; r0  frame length temporary register - write
; r1  frame length temporary register - read
; r2  adc msb temporary register
; r3  shit15 msb temporary register
; r4  shit15 lsb temporary register
; r5  adc lsb temporary register
; r6  control setpoint bottom
; r7  control setpoin top
; r8  wind sensor lsb
; r9  wind sensor msb
; r10 des_addr msb
; r11 des_addr lsb
; r12 shit15 humidity temporary register
; r13 ed_level buffer
; r14 motor state register for transmit
; r15 
; r16 temporary swap register for interrupts
; r17 temporary swap register for main
; r18 rf state register
; r19 motor state register
; r20 wait loop register
; r21 wait loop register
; r22 motor timer advance register
; r23 
; r24 temporary swap register for main
; r25 wakeup counter
; xregister is recieve buffer (r27(xh),r26(xl))
; yregister is buffer start (r29(yh),r28(yl))
; zregister is buffer end (r31(zh),r30(zl))
; data buffer set at 1k
; tregister is shit15 humidity/temperature irq differentiator
; joinrequest buffer is 256byte
; recieve buffer is 256byte

start: ; configure microcontroller registers
; start up time 6CK + 65ms
; set to 8MHz by internal rc oscillator
;turn off watchdog timer in case of watchdog reset
wdr ; reset wdt
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,$68
out portb,r16 ; enable pullup for miso and pb5,pb6 for buttons
ldi r16,$01
out spsr,r16 ; set up spi - mode0, ck/2
ldi r16,$50
out spcr,r16 ; set up spi - mode0, ck/2 (4MHz)
sbi portb,portb0 ; set ss pin high
cbi portb,portb4 ; set slp_tr low
sbi porta,porta7 ; pull reset high on rf unit
sbi ddra,dda7 ; set reset pin as output
ldi r16,$0c
sts eicrb,r16 ; configure int5 for rising edge
ldi r16,$20
out eimsk,r16 ; enable int5
ldi r16,high(home_addr) ; set up des_addr to something in system for start
mov r10,r16
ldi r16,low(home_addr) ; set up des_addr
mov r11,r16
clr zl ; set buffer end to beginning of sram
clr yl ; set buffer start to beginning of sram
ldi zh,$02 ; set buffer end to beginning of sram
ldi yh,$02 ; set buffer start to beginning of sram
ldi xh,$05 ; set recieve buffer to middle of sram
clr xl ; set recieve buffer to middle of sram
ldi r23,$ff ; initialize receieve buffer count
ldi r19,$80 ; set motor state register to damper-motor
clr r18 ; reset rf state register
clr r14 ; reset tx motor state register
ldi r25,$1e ; set wakeup counter to 60s
ldi r16,$3f
out portd,r16 ; turn on pullups for unused pins on portd since they might have long cables attached

;turn off watchdog timer in case of watchdog reset
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,$06
sts wdtcsr,r16 ; turn off wdt, 1s timer


;wait for rf unit to stabilize
ldi r21,$04 ; load the wait timer to 3 cycles (x3084/ck)
rcall waitloop1 ; wait ~(9252/8MHz = 1.2ms) for rf unit to stabilize

cbi porta,porta7 ; pull reset low to reset rf unit if watchdog reset
nop ; delay so reset has time to activate
nop
nop
nop
nop
nop
nop
nop
nop
nop
sbi porta,porta7 ; pull reset high to start

;wait for rf unit to stabilize
ldi r21,$04 ; load the wait timer to 3 cycles (x3084/ck)
rcall waitloop1 ; wait ~(9252/8MHz = 1.2ms) for rf unit to stabilize

;setup analog inputs
ldi r16,$01
sts didr0,r16 ; turn off input stage for adc0 pin
ldi r16,$c0
sts admux,r16 ; use internal 2.56v as voltage reference,sample adc0

;setup motor control pins as output (no pwm at the moment)
cbi portg,portg1 ; make sure pins are off
cbi portb,portb7 ; turn pwm off
sbi portg,portg0 ; turn brake on
sbi ddrg,ddg1 ; direction
sbi ddrg,ddg0 ; brake
sbi ddrb,ddb7 ; pwm (on/off for now)
sbi portg,portg0 ; turn on brake pin to shut off transistors

;setup t1 as windspeed counter
ldi r16,$06
sts tccr1b,r16 ; set t1 to external clock on t0 falling edge

;setup t2 as rtc at 4s 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
out tifr2,r16 ; clear all pending interrupts
ldi r16,$01
sts timsk2,r16 ; enable t2 overflow interrupt

;setup shit15 - pe0 is data, pe4 is clock
sbi ddre,dde0 ; set clock as output
cbi porte,porte4 ; make sure pullups are off for data
rcall shit15setup

;configure rf unit registers

;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

;enable irqs
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

;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

;clear pending irqs on micro
ldi r16,$ff
out eifr,r16 ; clear any interrupt flags that are set

;enable interrupts on micro
sei ; turn on interrupts

rcall rxonaack ; put the rf unit in rx_aack_on state

repeat: ; handle backlogged data

cpse zh,yh ; check if buffer has data
rjmp handle ; go to data handler
cpse zl,yl ; check if buffer has data
rjmp handle ; go to data handler
in r17,pinb ; get button press data
andi r17,$60 ; mask off button bits
ldi r24,$60 ; invert button bits
eor r17,r24 ; invert button bits
mov r24,r19 ; move current motor state to temp register
andi r24,$60 ; mask off button state
cp r24,r17 ; check if button state has changed
breq repeat ; continue checking if no change
andi r19,$9b ; turn off control bit and clear button state in motor state register
ori r19,$08 ; set manual bit in motor state register
or r19,r17 ; set current button state in motor state register
or r14,r17 ; store button presses to tx motor state register
cpi r17,$60 ; check if both buttons are pressed
breq buttonstop
cpi r17,$40 ; check if open button is pressed
breq openbutton
cpi r17,$20 ; check if close button is pressed
breq closebutton
andi r19,$97 ; else shut off manual bit and button bits in motor state register

buttonstop: ; turn off motor via buttonpress

ldi r17,$08 ; turn off timer
sts tccr5b,r17 ; turn off timer
ldi r17,$00
sts timsk5,r17 ; disable t5 interrupts
cbi portb,portb7 ; stop motor
sbi portg,portg0 ; turn on brake
rjmp repeat ; return to state checking

openbutton: ; open motor via buttonpress

ldi r17,$08 ; turn off timer
sts tccr5b,r17 ; turn off timer
ldi r17,$00
sts timsk5,r17 ; disable t5 interrupts
cbi portg,portg0 ; turn brake off
sbi portg,portg1 ; set direction to open
sbi portb,portb7 ; turn on motor
ori r19,$01 ; set direction open
rjmp repeat ; return to state checking

closebutton: ; close motor via buttonpress

ldi r17,$08 ; turn off timer
sts tccr5b,r17 ; turn off timer
ldi r17,$00
sts timsk5,r17 ; disable t5 interrupts
cbi portg,portg0 ; turn brake off
cbi portg,portg1 ; set direction to closed
sbi portb,portb7 ; turn on motor
andi r19,$fe ; set direction closed
rjmp repeat ; return to state checking

handle: ; respond to recieved data packets

ld r17,z+ ; get data frame length from buffer
mov r1,r17 ; move frame length to counter
cpi r17,$08 ; check if packet is the right length
brne resetbuffer ; reset buffer if not
ld r17,z+ ; get header byte from buffer
dec r1
cpi r17,$08 ; check if right packet type
brne resetbuffer
ld r17,z+ ; lsb src_addr - ignore
dec r1
ld r17,z+ ; msb src_addr - ignore
dec r1
ld r17,z+ ; get command byte
dec r1
cpi r17,$08 ; check if motor control command
breq motor ; control motor
rjmp resetbuffer ; else finish off

motor: ; control motor

ld r17,z+ ; get motor command
dec r1
sbrc r19,3 ; do not modify if under manual control
rjmp resetbuffer ; commands past this point are overriden by manual control
cpi r17,$08 ; check if damper full open
breq open
cpi r17,$06 ; check if damper full close
breq close
cpi r17,$0a ; check if damper stop
breq stop
cpi r17,$0c ; check if damper set by speed
brne resetbuffer ; else end
ld r17,z+ ; get control setpoint
dec r1
cpi r17,(hysteresis + $01) ; check if setpoint is too low
brlo setpointclose ; completely shut
cpi r17,($ff - hysteresis) ; check if setpoint is too high
brsh setpointopen ; completely open
subi r17,hysteresis ; put hysterisis in
mov r6,r17 ; move setpoint to control bottom
subi r17,($00 - 2*(hysteresis)) ; put hysterisis in
mov r7,r17 ; move setpoint to control top
ori r19,$04 ; turn on control bit in motor state register
ldi r17,$08 ; turn off timer
sts tccr5b,r17 ; turn off timer
ldi r17,$00
sts timsk5,r17 ; disable t5 interrupts
cbi portb,portb7 ; stop motor
sbi portg,portg0 ; turn on brake
rjmp resetbuffer

resetbuffer: ; reset buffer pointer

ldi r17,$00
add zl,r1 ; add remaining packet count
adc zh,r17 ; increment zh if zl overflow
sbrc zh,2 ; check if buffer at 1k
ldi zh,$02 ; reset buffer pointer to bottom of buffer
rjmp repeat ; get next packet from buffer

open: ; open damper command

andi r19,$fb ; turn off control bit
ld r17,z+ ; get step size packet
dec r1
rcall motortime ; start motor timer
cbi portg,portg0 ; turn brake off
sbi portg,portg1 ; set direction to open
sbi portb,portb7 ; turn on motor
ori r19,$01 ; set direction open
rjmp resetbuffer

stop: ; stop motor

ldi r17,$08 ; turn off timer
sts tccr5b,r17 ; turn off timer
ldi r17,$00
sts timsk5,r17 ; disable t5 interrupts
andi r19,$fb ; turn off control bit
cbi portb,portb7 ; stop motor
sbi portg,portg0 ; turn on brake
rjmp resetbuffer

close: ; close damper command

andi r19,$fa ; turn off control bit and set direction to closed
ld r17,z+ ; get step size packet
dec r1
rcall motortime ; start motor timer
cbi portg,portg0 ; turn brake off
cbi portg,portg1 ; set direction to closed
sbi portb,portb7 ; turn on motor
rjmp resetbuffer

setpointclose: ; go to full closed because setpoint is too low for control

andi r19,$fa ; turn off control bit and set direction closed
ldi r17,$ff
rcall motortime
cbi portg,portg0 ; turn brake off
cbi portg,portg1 ; set direction to closed
sbi portb,portb7 ; turn on motor
rjmp resetbuffer

setpointopen: ; go to full open because setpoint is too high for control

andi r19,$fb ; turn off control bit
ldi r17,$ff
rcall motortime
cbi portg,portg0 ; turn brake off
sbi portg,portg1 ; set direction to open
sbi portb,portb7 ; turn on motor
ori r19,$01 ; set direction open
rjmp resetbuffer

motortime: ; have motor on for a certain amount of time

mov r22,r17 ; move motortime to counter
ldi r17,(motor_time)
sts ocr5ah,r17 ; set counter top to packet time
ldi r17,$00
sts ocr5al,r17 ; set counter top to packet time
sts tcnt5h,r17 ; set counter to zero
sts tcnt5l,r17 ; set counter to zero
ldi r17,$2f
out tifr5,r17 ; clear all t5 interrupt flags
ldi r17,$02
sts timsk5,r17 ; turn on t5 interrupt
ldi r17,$0d
sts tccr5b,r17 ; turn on counter, set to 128us period
ret

timer5int: ; turn off motor

in r16,sreg ; get sreg
push r16 ; push sreg on stack
dec r22 ; decrement 3rd byte counter
brne timer5intdone ; dont do anything if not done
cbi portb,portb7 ; stop motor
sbi portg,portg0 ; turn on brake
ldi r16,$08 ; turn off timer
sts tccr5b,r16 ; turn off timer
ldi r16,$00
sts timsk5,r16 ; disable t5 interrupts

timer5intdone: ; finish off

pop r16 ; get off stack
out sreg,r16 ; return sreg
reti ; return from interrupt

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

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

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

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

joinrecieve: ; get new des_addr

cpi r18,$04 ; check if waiting for joinack
brne rxrequest ; dont accpet joinack if not waiting for joinack
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 - src_addr(7:0)
mov r11,r16
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - src_addr(15:8)
mov r10,r16
;dont bother with the rest of the data - it doesnt matter
;ldi r16,$00 ; load data byte - blank for reading
;rcall spiwrite ; send byte - do not save fcs(7:0)
;ldi r16,$00 ; load data byte - blank for reading
;rcall spiwrite ; send byte - do not save fcs(15:8)
;ldi r16,$00 ; load data byte - blank for reading
;rcall spiwrite ; send byte - lqi
sbi portb,portb0 ; pull ss high
sbiw yh:yl,$02 ; reset data buffer to begining of join request
ldi r18,$10 ; set state register to retry transmit
rcall transmit ; set rf unit to tx_on_aret state
rcall transmitpacket ; transmit data
ret ; done

rxreadinterrupt: ; empty rx buffer while in interrupt

;ed_level is taken first because it is only valid for 224us after interrupt fires
ldi r16,$87 ; load data byte - read ed_level
cbi portb,portb0 ; pull ss low
rcall spiwrite ; send byte
ldi r16,$00 ; load data byte - blank byte for reading
rcall spiwrite ; send byte
mov r13,r16 ; move ed_level to temporary buffer
sbi portb,portb0 ; pull ss high

;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
subi r16,$06 ; decrease frame length for bits to be removed
st y+,r16 ; move frame length to buffer
subi r16,$03 ; decrease frame length for buffer fitting
mov r0,r16 ; move frame length to temporary register
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)
st y+,r16
cpi r16,$06 ; check if command byte is $06 (join acknowledge)
breq joinrecieve ; get new home_addr if $06
cpi r16,$08 ; check if data to tethered node
breq notrequest1 ; load data to buffer, else discard packet

rxrequest: ; finish off

sbi portb,portb0 ; pull ss high
sbiw yh:yl,$02 ; reset data buffer to begining of join request
ret ; done

notrequest1: ; continue with data loading

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)

getdatarf1: ; keep loading data till frame compelete

ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte
st y+,r16 ; move byte to buffer
dec r0 ; decrement frame length byte
brne getdatarf1 ; keep decrementing until done
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save fcs(7:0)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - do not save fcs(15:8)
ldi r16,$00 ; load data byte - blank for reading
rcall spiwrite ; send byte - lqi
sbi portb,portb0 ; pull ss high
st y+,r16 ; move lqi to buffer
st y+,r13 ; move ed_level to buffer
sbrc yh,2 ; check if buffer at 1k
ldi yh,$02 ; reset buffer pointer to bottom of buffer
ret ; done writing data

transmit: ; set rf unit to tx_on_aret state

;check to see if not in rx_busy 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,$11 ; check if in busy_rx
breq transmit ; keep checking till in a new state
cpi r16,$1f ; check if in state transition
breq transmit ; keep checking till in a new state
cpi r16,$12 ; check if in busy_tx state
breq transmit ; keep checking till in a new state
rcall pllon ; go to pll on state
;check if there is data pending in rx buffer
ldi r16,$8f ; load first data byte - read register irq_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
sbrc r16,3 ; check if trx_end interrupt flag is set
rcall rxreadinterrupt ; empty rx buffer
rcall txonaret ; put the rf unit in tx_aret_on state
ret ; return to previous duty

waitloop1: ; wait timer (~3084 cycles per value in r21)

ser r20
rcall wait2
nop
nop
nop
nop
nop
nop
nop
nop
dec r21
brne waitloop1
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

gotorx: ; return to rx_on_aack state

;check successful transmit before switching back to rx
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 gotorx1 ; skip if success
cpi r18,$01 ; check if this is the first failure
brne gotorx3 ; if not - finish off
rcall transmitrequest ; get new des_addr and retransmit
ldi r18,$02 ; set joinrequest state bit
pop r16 ; get off stack
out sreg,r16 ; return sreg
reti ; clear interrupt and return to previous duty

gotorx1: ; turn on rx_on_aack state

rcall pllon ; go to pll_on state
rcall rxonaack ; go to rx_on_aack state
cpi r18,$02 ; check if last state was a joinrequest
brne gotorx2 ; finish off if not waiting for joinrequest ack
ldi r18,$04 ; set rf state to joinrequest ack waiting
;turn off watchdog timer
wdr ; reset wdt
in r16,mcusr ; get reset flag status
andi r16,$f7 ; mask off wdrf to 0
out mcusr,r16 ; turn off wdrf
ldi r16,$1e
sts wdtcsr,r16 ; enable writing of wdt
ldi r16,$06
sts wdtcsr,r16 ; turn off wdt, 1s timer
pop r16 ; get off stack
out sreg,r16 ; return sreg
reti ; return to previous task

gotorx3: ; set to rx_an_aack state

rcall pllon ; go to pll_on state
rcall rxonaack ; go to rx_on_aack state

gotorx2: ; finish off

clr r14 ; reset tx motor state register
ldi r18,$00 ; reset rf state to complete
;turn off watchdog timer
wdr ; reset wdt
in r16,mcusr ; get reset flag status
andi r16,$f7 ; mask off wdrf to 0
out mcusr,r16 ; turn off wdrf
ldi r16,$1e
sts wdtcsr,r16 ; enable writing of wdt
ldi r16,$06
sts wdtcsr,r16 ; turn off wdt, 1s timer
pop r16 ; get off stack
out sreg,r16 ; return sreg
reti ; return to previous task

clearirq: ; clear irq register and irq line

in r16,sreg ; get sreg
push r16 ; push sreg on stack
ldi r16,$8f ; load first data byte - read register irq_status command to clear interrupt
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_on
breq datacollect ; get data
cpi r16,$11 ; check if in busy_rx
breq datacollect ; 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
rjmp gotorx ; else change state back to rx

;removed checkcrc because crc is automatically checked with rx_aack

datacollect: ; get data from rf unit

rcall rxreadinterrupt ; get data from rf unit
pop r16 ; get off stack
out sreg,r16 ; return sreg
reti ; done writing data

wakeup: ; check if time to take data

in r16,sreg ; get sreg
push r16 ; push sreg on stack
dec r25 ; decrement wakeup counter
breq wakeup1 ; take data if 60s
pop r16 ; get sreg off stack
out sreg,r16 ; return sreg
reti

wakeup1: ; take data and return to previous task

;enable watchdog timer to eliminate lock up bug
wdr ; reset wdt
ldi r16,$1e
sts wdtcsr,r16 ; enable writing of wdt
ldi r16,$0e
sts wdtcsr,r16 ; turn on wdt, 1s timer

push r17 ; push r17 on stack
lds r8,tcnt1l ; move windspeed lsb to temporary register
lds r9,tcnt1h ; move windspeed msb to temporary register
clr r16 ; reset activity level counter
sts tcnt1h,r16
sts tcnt1l,r16
;motor control code
sbrs r19,2 ; check if in control mode
rjmp wakeupend ; finish off if not
cp r9,r6 ; check if speed too low
brlo incrementup ; move motor open
cp r9,r7 ; check if speed to high
brsh incrementdown ; move motor closed

wakeupend: ; else finish off

or r14,r19 ; move motor state register to tx motor state register
rcall shit15temp ; initiate shit15 read - humidity included
ldi r16,$df ; take measurement from adc0
sts adcsra,r16 ; turn on adc,clear interrupt flag,enable interrupt,set to /128 (62.5kHz)
ldi r25,$1e ; reset wakeup counter to 60s
pop r17 ; get r17 off stack
pop r16 ; get sreg off stack
out sreg,r16 ; return sreg
reti

incrementup: ; open with motor a few steps

ldi r17,stepsize ; set increment length
rcall motortime ; move packet to motor timer
cbi portg,portg0 ; turn brake off
sbi portg,portg1 ; set direction to open
sbi portb,portb7 ; turn on motor
ori r19,$01 ; set direction open
rjmp wakeupend ; finish off

incrementdown: ; close with motor a few steps

ldi r17,stepsize ; set increment length
rcall motortime ; move packet to motor timer
cbi portg,portg0 ; turn brake off
cbi portg,portg1 ; set direction to closed
sbi portb,portb7 ; turn on motor
andi r19,$fe ; set direction closed
rjmp wakeupend ; finish off

wakeupadc: ; wakeup and return to previous task

in r16,sreg ; get sreg
push r16 ;  push sreg on stack
lds r5,adcl ; load lsb to r5
lds r2,adch ; load msb to r2
pop r16 ; get off stack
out sreg,r16 ; return sreg
reti

shit15setup: ; set the device to low res mode
;talk to shit15, only works for cpu clock <=2MHZ
;code modded with nops to operate at 8MHz
;data pin can never be output high - leave pullup off
;needs external pullup resistor for proper operation
;sleep operation disabled for this application
;always read temperature before humidity

rcall shit15reset ; reset the device in case its fuxxored
rcall startshit15 ; send start sequence

;data sequence - register write command $06
;nops added to keep clock at 1MHz
sbi porte,porte0 ; clock high - data bit one
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit two
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit three
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit four
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit five
nop
nop
cbi porte,porte0 ; clock low
cbi ddre,dde4 ; data high
nop ; data takes time to rise and needs setup time
nop
nop
nop
nop
nop
sbi porte,porte0 ; clock high - data bit six
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit seven
nop
nop
cbi porte,porte0 ; clock low
sbi ddre,dde4 ; data low
sbi porte,porte0 ; clock high - data bit eight
nop
nop
cbi porte,porte0 ; clock low

rcall shit15ack0 ; wait for ack from shit15

;data sequence - register write data $01
;nops added to keep clock at 1MHz
sbi ddre,dde4 ; data low
sbi porte,porte0 ; clock high - data bit one
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit two
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit three
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit four
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit five
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit six
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit seven
nop
nop
cbi porte,porte0 ; clock low
cbi ddre,dde4 ; data high
nop ; data takes time to rise and needs setup time
nop
nop
nop
nop
nop
sbi porte,porte0 ; clock high - data bit eight
nop
nop
cbi porte,porte0 ; clock low

rcall shit15ack0 ; wait for ack from shit15
ret ;done setting up the device

shit15temp: ; read temperature data from shit15
;send read temp commmand
rcall startshit15 ; send start sequence

;data sequence - read temperature command $03
sbi porte,porte0 ; clock high - data bit one
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit two
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit three
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit four
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit five
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit six
nop
nop
cbi porte,porte0 ; clock low
cbi ddre,dde4 ; data high
nop ; data takes time to rise and needs setup time
nop
nop
nop
nop
nop
sbi porte,porte0 ; clock high - data bit seven
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit eight
nop
nop
cbi porte,porte0 ; clock low
;sbi ddre,dde4 ; data low - if last databyte is 1 - leave it high for ack

rcall shit15ack0 ; wait for ack from shit15

sbi eimsk,4 ; enable int4
ret ; return to previous task and wait for shit15 to be done

wakeupshit15: ; collect data from shit15
in r16,sreg ; get sreg
push r16 ; push sreg on stack
brts shit15humread ; skip if its a humidity read
cbi eimsk,4 ; disable int4 as pe4 will still be low when returning
rcall shit15read ; read out temperature data from shit15 (msb)
rcall shit15ack3 ; acknowledge reciept of bit
mov r3,r16 ; move msb to another register
rcall shit15read ; read out temperature data from shit15 (lsb)
rcall shit15ack4 ; end transmission ack
mov r4,r16 ;  move lsb to another register
rcall shit15humidity
pop r16 ; get off stack
out sreg,r16 ; return sreg
set ; set tregister to indicate humidity request in progress
reti ; continue with previous task

shit15humread: ; read out humidity data from shit 15
rcall shit15read ; read out humidity data from shit15 (msb)
rcall shit15ack3 ; acknowledge reciept of bit
rcall shit15read ; read out humidity data from shit15 (lsb)
rcall shit15ack4 ; end transmission ack
mov r12,r16 ; move humidity data to temporary register
ldi r18,$01 ; set rf state to first transmit
rcall transmit ; set rf unit to tx state
rcall transmitpacket ; send data off
pop r16 ; get off stack
out sreg,r16 ; return sreg
clt ; reset to temperature read
reti ; return with previous task

shit15humidity: ; read humidity data from shit15
;send read humidity command
rcall startshit15 ; send start sequence

;data sequence - read humidity command $05
;nops added to keep clock at 1MHz
sbi porte,porte0 ; clock high - data bit one
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit two
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit three
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit four
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit five
nop
nop
cbi porte,porte0 ; clock low
cbi ddre,dde4 ; data high
nop ; data takes time to rise and needs setup time
nop
nop
nop
nop
nop
sbi porte,porte0 ; clock high - data bit six
nop
nop
cbi porte,porte0 ; clock low
sbi ddre,dde4 ; data low
sbi porte,porte0 ; clock high - data bit seven
nop
nop
cbi porte,porte0 ; clock low
cbi ddre,dde4 ; data high
nop ; data takes time to rise and needs setup time
nop
nop
nop
nop
nop
sbi porte,porte0 ; clock high - data bit eight
nop
nop
cbi porte,porte0 ; clock low
;sbi ddre,dde4 ; data low - if last databyte is 1 - leave it high for ack

rcall shit15ack0 ; wait for acknowledge from shit15
sbi eimsk,4 ; enable int4
ret ; return to previous task and wait for shit15 to take data

shit15ack4: ; end transmission ack
;nops added to keep clock at 1MHz
sbi porte,porte0 ; clock high - ack
nop
nop
cbi porte,porte0 ; clock low
ret ; return to previous task

shit15ack3: ; data recipet acknowledge
;nops added to keep clock at 1MHz
sbi ddre,dde4 ; pull data low
sbi porte,porte0 ; clock high - ack
nop
nop
cbi porte,porte0 ; clock low
cbi ddre,dde4 ; release data line
ret ; return to previous task

shit15read: ; read data from shit15
;nops added to keep clock at 1MHz and meet data valid time of 250ns
clr r16 ; clear the register where incoming data will be written
sbi porte,porte0 ; clock high - data bit one
sbic pine,pine4 ; check if data is low
sbr r16,$80 ; write data bit one to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit two
sbic pine,pine4 ; check if data is low
sbr r16,$40 ; write data bit two to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit three
sbic pine,pine4 ; check if data is low
sbr r16,$20 ; write data bit three to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit four
sbic pine,pine4 ; check if data is low
sbr r16,$10 ; write data bit four to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit five
sbic pine,pine4 ; check if data is low
sbr r16,$08 ; write data bit five to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit six
sbic pine,pine4 ; check if data is low
sbr r16,$04 ; write data bit six to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit seven
sbic pine,pine4 ; check if data is low
sbr r16,$02 ; write data bit seven to register
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high - data bit eight
sbic pine,pine4 ; check if data is low
sbr r16,$01 ; write data bit eight to register
cbi porte,porte0 ; clock low
ret ; return to previous activity

startshit15: ; start sequence
;nops added to keep clock at 1MHz
cbi ddre,dde4 ; set data high
cbi porte,porte0 ; make sure clock is low
nop
nop
sbi porte,porte0 ; pull clock high
sbi ddre,dde4 ; set data low
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
cbi ddre,dde4 ; data high
nop ; data takes time to rise and needs setup time
nop
nop
nop
nop
nop
cbi porte,porte0 ; clock low
sbi ddre,dde4 ; data low
ret ; return to previous task

shit15ack0: ; ack sequence for sending data

cbi ddre,dde4 ; release data line

shit15ack2: ; check that data line is low
;nops added to keep clock at 1MHz
sbic pine,pine4
rjmp shit15ack2
sbi porte,porte0 ; clock high - ack
nop
nop
cbi porte,porte0 ; clock low

shit15ack1: ; check that line has been released

sbis pine,pine4 ; check that line has been released
rjmp shit15ack1
ret ; return to previous task

shit15reset: ; reset sequence if it gets out of phase
;status register preserved
;must be followed by data start sequence
;nops added to slow it down to 1MHz
cbi ddre,dde4 ; data high
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
nop
nop
sbi porte,porte0 ; clock high
nop
nop
cbi porte,porte0 ; clock low
ret ; return to previous task

transmitrequest: ; transmit a request frame

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,$0b ; load data byte - frame length byte
rcall spiwrite ; send byte
ldi r16,$40 ; load data byte - fcf(7:0) - broadcast,no ack
rcall spiwrite ; send byte
ldi r16,$88 ; load data byte - fcf(15:8) - short address,pan_ids equal
rcall spiwrite ; send byte
ldi r16,$01 ; load data byte - seq(7:0) - command(request)
rcall spiwrite ; send byte
ldi r16,low(pan_id) ; load data byte - pan_id(7:0)
rcall spiwrite ; send byte
ldi r16,high(pan_id) ; load data byte - pan_id(15:8)
rcall spiwrite ; send byte
ldi r16,$ff ; load data byte - destination address (7:0) - broadcast
rcall spiwrite ; send byte
ldi r16,$ff ; load data byte - destination address (15:0) - broadcast
rcall spiwrite ; send byte
ldi r16,low(src_addr) ; load data byte - source address (7:0)
rcall spiwrite ; send byte
ldi r16,high(src_addr) ; load data byte - source address (15:8)
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
ret ; return to previous duty

transmitpacket: ; transmit a packet

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,$13 ; 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,$07 ; load sequence byte - command (data from tethered node)
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
mov r16,r11 ; load destination address(7:0) byte
rcall spiwrite ; send byte
mov r16,r10 ; 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,r14 ; load data byte - motor state register
rcall spiwrite ; send byte
mov r16,r12 ; load data byte - humidity
rcall spiwrite ; send byte
mov r16,r4 ; load data byte - temperature0
rcall spiwrite ; send byte
mov r16,r3 ; load data byte - temperature1
rcall spiwrite ; send byte
mov r16,r8 ; load data byte - windspeed lsb
rcall spiwrite ; send byte
mov r16,r9 ; load data byte - windspeed msb
rcall spiwrite ; send byte
mov r16,r5 ; load data byte - light lsb
rcall spiwrite ; send byte
mov r16,r2 ; load data byte - light msb
rcall spiwrite ; send byte
sbi portb,portb0 ; pull ss high
ret ; return to previous duty







