; ; i0.3.IO.88.web.v4.asm ; i0 three-wire output node Web form code ; IPv4 version ; 2-16-2 encoding ; ; Neil Gershenfeld ; CBA MIT 5/9/09 ; ; (c) Massachusetts Institute of Technology 2009 ; Permission granted for experimental and personal use; ; license for commercial sale available from MIT. ; ; bugs: ; two packets needed to switch to off or blink ; occasional hangs ; ; todo: ; set source address ; shift-add ASCII conversion ; .include "m88def.inc" ; ; definitions ; .equ Web_port = 80 ; Web server port .equ click_pin = PC0 ; i0 click pin .equ click_pins = PINC ; i0 click pins .equ click_port = PORTC ; i0 click port .equ click_direction = DDRC ; i0 click direction .equ click_count = 5 ; loop count to wait during click .equ settle_count = 10 ; loop count to wait for click to settle .equ delay_count = 15 ; loop count to wait between clicks .equ char_delay_count = 20 ; loop count for character delay .equ csma_count = 20 ; loop count for CSMA check .equ button_pin = PD2 ; button pin .equ button_pins = PIND ; button pins .equ button_port = PORTD ; button port .equ button_direction = DDRD ; button direction .equ mosfet_pin = PC1 ; MOSFET pin .equ mosfet_port = PORTC ; MOSFET port .equ mosfet_direction = DDRC ; MOSFET direction .equ LED_pin = PD0 ; LED pin .equ LED_port = PORTD ; LED port .equ LED_direction = DDRD ; LED direction .equ END = 192 ; SLIP definitions .equ ESC = 219 ; " .equ ESC_END = 220 ; " .equ ESC_ESC = 221 ; " .equ eeprom_source_address = 0 ; EEPROM addresses ; ; registers ; .def zero = R1 ; 0 .def one = R2 ; 1 .def double_count = R3 ; double loop count .def triple_space = R4 ; triple click spacing .def check_lo = R5 ; lo checksum accumulator .def check_hi = R6 ; hi checksum accumulator .def check_carry = R7 ; checksum carry accumulator .def dest_1 = R8 ; destination address byte 1 .def dest_2 = R9 ; destination address byte 2 .def dest_3 = R10 ; destination address byte 3 .def dest_4 = R11 ; destination address byte 4 .def temp = R16 ; temporary storage .def temp1 = R17 ; temporary storage .def temp2 = R18 ; temporary storage .def temp3 = R19 ; temporary storage .def txbyte = R20 ; transmit byte .def rxbyte = R21 ; receive byte .def click_space = R22 ; click spacing .def bit_count = R23 ; bit counter .def return = R24 ; subroutine return value .def loop_count = R26 ; loop counter (xl) .def loop_count_hi = R27 ; loop counter high (xh) ; R28, 29 used for yl, yh ; R30, 31 used for zl, zh ; ; macros ; ; read_SRAM register location ; .macro read_SRAM ldi zh, high(@1) ldi zl, low(@1) ld @0, z .endmacro ; ; copy ; copy bytes between two SRAM locations ; copy destination, source ; .macro copy ldi zh, high(@1) ldi zl, low(@1) ld temp, z ldi zh, high(@0) ldi zl, low(@0) st z, temp .endmacro ; ; compare ; compare two SRAM locations ; .macro compare ldi zh, high(@1) ldi zl, low(@1) ld temp, z ldi zh, high(@0) ldi zl, low(@0) ld temp1, z cp temp, temp1 .endmacro ; ; compare_eeprom ; compare SRAM and EEPROM location ; .macro compare_eeprom ldi temp, high(@1) out EEARH, temp ldi temp, low(@1) out EEARL, temp sbi EECR, EERE in temp1, EEDR ldi zh, high(@0) ldi zl, low(@0) ld temp, z cp temp, temp1 .endmacro ; ; compare_immediate ; compare SRAM location with a constant ; .macro compare_immediate ldi zh, high(@0) ldi zl, low(@0) ld temp, z cpi temp, @1 .endmacro ; ; store_immediate ; store immediate constant to SRAM ; .macro store_immediate ldi temp, @1 sts @0, temp .endmacro ; ; set_data message ; copy message to packet data ; .macro set_data ldi zh, high(@0*2) ldi zl, low(@0*2) ldi yh, high(data_start) ldi yl, low(data_start) set_data_loop: lpm temp, z+ st y+, temp cpi temp, 0 brne set_data_loop .endmacro ; ; putslip ; click char in txbyte, with SLIP mapping ; .macro putslip ldi temp, END cpse txbyte, temp rjmp putslipchar ; ; END char ; mov temp, txbyte ldi txbyte, ESC rcall putclick rcall char_delay ldi txbyte, ESC_END rcall putclick rcall char_delay mov txbyte, temp rjmp endputslip ldi temp, ESC cpse txbyte, temp rjmp putslipchar ; ; ESC char ; mov temp, txbyte ldi txbyte, ESC rcall putclick rcall char_delay ldi txbyte, ESC_ESC rcall putclick rcall char_delay mov txbyte, temp rjmp endputslip putslipchar: ; ; ordinary char, no escape needed ; rcall putclick rcall char_delay endputslip: .endmacro ; ; read_eeprom ; read EEPROM location to register ; .macro read_eeprom ldi temp, high(@1) out EEARH, temp ldi temp, low(@1) out EEARL, temp sbi EECR, EERE in @0, EEDR .endmacro ; ; write_eeprom ; write register to EEPROM ; .macro write_eeprom write_eeprom_loop: ; make sure EEPROM is ready for writing sbic EECR, EEPE rjmp write_eeprom_loop cbi EECR, EEPM1 cbi EECR, EEPM0 ldi temp, high(@0) out EEARH, temp ldi temp, low(@0) out EEARL, temp out EEDR, @1 sbi EECR, EEMPE sbi EECR, EEPE .endmacro ; ; write_sram_to_eeprom ; write SRAM location to EEPROM ; .macro write_sram_to_eeprom write_sram_to_eeprom_loop: ; make sure EEPROM is ready for writing sbic EECR, EEPE rjmp write_sram_to_eeprom_loop cbi EECR, EEPM1 cbi EECR, EEPM0 ldi temp, high(@0) out EEARH, temp ldi temp, low(@0) out EEARL, temp ldi zh, high(@1) ldi zl, low(@1) ld temp, z out EEDR, temp sbi EECR, EEMPE sbi EECR, EEPE .endmacro ; ; ascii_binary register, pointer ; convert ascii 0-255 to binary byte ; reads to space or null ; .macro ascii_binary clr @0 ascii_binary_loop: ld temp, @1+ cpi temp, ' ' breq ascii_binary_return cpi temp, 0 breq ascii_binary_return mov temp1, @0 lsl @0 lsl @0 lsl @0 add @0, temp1 add @0, temp1 subi temp, 48 add @0, temp rjmp ascii_binary_loop ascii_binary_return: .endmacro ; ; binary_to_ascii r, r1, r2, r3 ; convert byte in r to ascii chars in r1, r2, r3 ; .macro binary_to_ascii binary_to_ascii_200: cpi @0, 200 brlo binary_to_ascii_100 ldi @1, '2' subi @0, 200 rjmp binary_to_ascii_90 binary_to_ascii_100: cpi @0, 100 brlo binary_to_ascii_000 ldi @1, '1' subi @0, 100 rjmp binary_to_ascii_90 binary_to_ascii_000: ldi @1, '0' binary_to_ascii_90: cpi @0, 90 brlo binary_to_ascii_80 ldi @2, '9' subi @0, 90 rjmp binary_to_ascii_9 binary_to_ascii_80: cpi @0, 80 brlo binary_to_ascii_70 ldi @2, '8' subi @0, 80 rjmp binary_to_ascii_9 binary_to_ascii_70: cpi @0, 70 brlo binary_to_ascii_60 ldi @2, '7' subi @0, 70 rjmp binary_to_ascii_9 binary_to_ascii_60: cpi @0, 60 brlo binary_to_ascii_50 ldi @2, '6' subi @0, 60 rjmp binary_to_ascii_9 binary_to_ascii_50: cpi @0, 50 brlo binary_to_ascii_40 ldi @2, '5' subi @0, 50 rjmp binary_to_ascii_9 binary_to_ascii_40: cpi @0, 40 brlo binary_to_ascii_30 ldi @2, '4' subi @0, 40 rjmp binary_to_ascii_9 binary_to_ascii_30: cpi @0, 30 brlo binary_to_ascii_20 ldi @2, '3' subi @0, 30 rjmp binary_to_ascii_9 binary_to_ascii_20: cpi @0, 20 brlo binary_to_ascii_10 ldi @2, '2' subi @0, 20 rjmp binary_to_ascii_9 binary_to_ascii_10: cpi @0, 10 brlo binary_to_ascii_00 ldi @2, '1' subi @0, 10 rjmp binary_to_ascii_9 binary_to_ascii_00: ldi @2, '0' binary_to_ascii_9: mov @3, @0 ldi @0, 48 add @3, @0 .endmacro ; ; ascii_to_binary register, string ; z points to string (SRAM) ; reads to space or null ; .macro ascii_to_binary clr @0 ascii_to_binary_loop: ld temp, z+ cpi temp, ' ' breq ascii_to_binary_return cpi temp, 0 breq ascii_to_binary_return sbi temp, 42 add @0, temp ascii_to_binary_return: .endmacro ; ; find_char char ; increment z until char is found ; .macro find_char find_char_loop: ld temp, z+ cpi temp, '?' brne find_char_loop sbiw zl, 1 .endmacro ; ; find_string target string ; return: position ; set T if found ; x: string pointer (SRAM) ; y: string pointer match (SRAM) ; z: target pointer (program memory) ; .macro find_string ldi xh, high(@1) ldi xl, low(@1) ; ; loop over string ; find_string_loop: mov yh, xh mov yl, xl ld temp, x+ cpi temp, 0 ; return if starting pointer is at end of string breq find_string_no_match ldi zh, high(@0*2) ldi zl, low(@0*2) clr return ; ; loop over target ; find_string_match_loop: ld temp, y+ cpi temp, 0 ; return if current pointer is at end of string breq find_string_no_match lpm temp1, z+ cpi temp1, 0 ; match found if end of target reached breq find_string_match cp temp, temp1 ; advance pointer if chars don't match brne find_string_loop inc return ; increment count if chars match rjmp find_string_match_loop find_string_no_match: clt ; clear T for no match rjmp find_string_return find_string_match: sbiw yl, 1 ; point to last char after match set ; set T for match find_string_return: .endmacro ; ; code segment ; .cseg .org 0 rjmp reset ; ; get_i0_packet ; read an i0 packet to SRAM following starting SLIP END character, ; removing SLIP mapping ; set T for timeout ; get_i0_packet: ; ; set Z to point to start of SRAM ; ldi zl, low(ip_start) ldi zh, high(ip_start) get_i0_packet_mainloop: ; ; wait for start click ; clr loop_count get_i0_packet_waitloop: inc loop_count breq get_i0_packet_timeout ; time-out if count overflows sbic click_pins, click_pin ; check i0 pin for click rjmp get_i0_packet_waitloop ; ; read next byte ; rcall getclick ; ; return if T set ; brtc get_i0_packet_T_continue rjmp get_i0_packet_timeout get_i0_packet_T_continue: ; ; check for SLIP escape ; cpi rxbyte, ESC brne get_i0_packet_store_byte get_i0_packet_ESC: ; ; found escape, read next character after next click ; get_i0_packet_waitloop1: sbic click_pins, click_pin ; check i0 pin for click rjmp get_i0_packet_waitloop1 rcall getclick ; ; return if T set ; brtc get_i0_packet_ESC_continue rjmp get_i0_packet_timeout get_i0_packet_ESC_continue: cpi rxbyte, ESC_ESC brne get_i0_packet_END ; ; store an ESC ; ldi rxbyte, ESC st z+, rxbyte rjmp get_i0_packet_mainloop get_i0_packet_END: ; ; store an END ; ldi rxbyte, END st z+, rxbyte rjmp get_i0_packet_mainloop get_i0_packet_store_byte: ; ; store byte ; st z+, rxbyte ; ; go back for next byte if not END ; ldi temp, END cpse rxbyte, temp rjmp get_i0_packet_mainloop get_i0_packet_return: ; ; add null termination ; clr rxbyte st z, rxbyte ; ; save destination address and return ; read_SRAM dest_1, source_address read_SRAM dest_2, source_address+1 read_SRAM dest_3, source_address+2 read_SRAM dest_4, source_address+3 ret get_i0_packet_timeout: ; ; timeout, set T ; set ret ; ; click_duration ; delay during click ; click_duration: ldi temp, click_count click_duration_loop: dec temp brne click_duration_loop ret ; ; click_delay ; delay between clicks ; click_delay: ldi temp, delay_count click_delay_loop: dec temp brne click_delay_loop ret ; ; putclick ; send char in txbyte clicks ; putclick: ldi bit_count, 8 sec; set start bit ; ; set click pin to output ; sbi click_direction, click_pin ; ; send start clicks ; cbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay cbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay ; ; send data clicks ; putclick0: lsr txbyte; get next bit brcc putclick1 ; if carry set, send a 1 click cbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay sbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay rjmp putclick2; otherwise ... putclick1: sbi click_port, click_pin ; ... send a 0 click rcall click_duration sbi click_port, click_pin rcall click_delay cbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay putclick2: dec bit_count; if not all bits sent brne putclick0; send next bit ; ; send stop clicks ; cbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay cbi click_port, click_pin rcall click_duration sbi click_port, click_pin rcall click_delay ; ; set click pin to input with pull-up ; cbi click_direction, click_pin ; ; return ; ret ; ; getclick ; input an i0 byte to rxbyte following first click ; set T for timeout ; getclick: ; ; delay for first click to settle ; ldi loop_count, settle_count getclick_settle_start: dec loop_count nop ; to even out timing for breq brne getclick_settle_start ; ; time arrivial of second start click ; ldi click_space, (settle_count+1) ; +1 for overhead getclick_time_start: inc click_space breq getclick_timeout ; check for overflow sbic click_pins, click_pin ; check for click rjmp getclick_time_start mov triple_space, click_space add triple_space, click_space add triple_space, click_space ; ; decode data clicks ; clr rxbyte ldi bit_count, 8 getclick_bitloop: ; ; delay for click to settle ; ldi loop_count, settle_count getclick_settle: dec loop_count nop ; to even out timing for breq brne getclick_settle ; ; time arrivial of next click ; ldi loop_count, settle_count getclick_time: inc loop_count breq getclick_timeout ; check for overflow sbic click_pins, click_pin ; check for click rjmp getclick_time ; ; determine bit delay ; mov double_count, loop_count add double_count, loop_count cp double_count, triple_space brsh getclick_zero ; ; one bit ; sec ; set carry ror rxbyte ; shift in carry ; ; even out 0/1 timing ; mov loop_count, click_space getclick_space: dec loop_count nop ; to even out timing for breq brne getclick_space ; ; decrement counter and output if byte received ; dec bit_count brne getclick_bitloop rjmp getclick_end getclick_zero: ; ; zero bit ; clc ; clear carry ror rxbyte ; shift in carry ; ; decrement counter and output if byte received ; dec bit_count brne getclick_bitloop getclick_end: ; ; wait for stop clicks ; getclick_end_0_up: sbis click_pins, click_pin rjmp getclick_end_0_up getclick_end_1_down: sbic click_pins, click_pin rjmp getclick_end_1_down getclick_end_1_up: sbis click_pins, click_pin rjmp getclick_end_1_up getclick_end_2_down: sbic click_pins, click_pin rjmp getclick_end_2_down getclick_end_2_up: sbis click_pins, click_pin rjmp getclick_end_2_up ; ; byte received, clear T and return ; clt ret getclick_timeout: ; ; timeout, clear rxbyte, set T, and return ; clr rxbyte set ret ; ; char_delay ; delay between characters ; char_delay: ldi temp, char_delay_count char_delay_loop: dec temp brne char_delay_loop ret ; ; packet_delay ; delay between packets ; packet_delay: ldi temp, 255 packet_delay_loop: ldi temp1, 255 packet_delay_loop1: dec temp1 brne packet_delay_loop1 dec temp brne packet_delay_loop ret ; ; blink_delay ; LED blink delay ; blink_delay: ldi temp, 255 blink_delay_loop: ldi temp1, 255 blink_delay_loop1: ldi temp2, 2 blink_delay_loop2: dec temp2 brne blink_delay_loop2 dec temp1 brne blink_delay_loop1 dec temp brne blink_delay_loop ret ; ; print_packet ; send a packet, calculating header checksum and doing SLIP encoding ; print_packet: ; ; count data length and store in packet ; ldi zh, high(data_start) ldi zl, low(data_start) clr loop_count clr loop_count_hi count_data_loop: adiw loop_count, 1 ld temp, z+ cpi temp, 0 brne count_data_loop sbiw loop_count, 1 ; don't count the null termination adiw loop_count, udp_header_size sts udp_length, loop_count_hi sts udp_length+1, loop_count adiw loop_count, ip_header_size sts ip_length, loop_count_hi sts ip_length+1, loop_count ; ; find the IP header checksum and store in packet ; ldi zh, high(ip_start) ldi zl, low(ip_start) ldi loop_count, ip_header_size clr check_lo clr check_hi clr check_carry ip_checksum_loop: adiw zl, 1 ld temp, z dec loop_count sbiw zl, 1 ld temp1, z add check_lo, temp adc check_hi, temp1 adc check_carry, zero adiw zl, 2 dec loop_count brne ip_checksum_loop add check_lo, check_carry adc check_hi, zero com check_lo com check_hi sts ip_checksum, check_hi sts ip_checksum+1, check_lo ; ; CSMA check ; print_packet_CSMA: ldi temp, csma_count print_packet_CSMA_loop: sbis click_pins, click_pin rjmp print_packet_CSMA_delay dec temp brne print_packet_CSMA_loop rjmp print_packet_CSMA_continue print_packet_CSMA_delay: ldi temp, csma_count print_packet_CSMA_delay_loop: dec temp brne print_packet_CSMA_delay_loop rjmp print_packet_CSMA print_packet_CSMA_continue: ; ; send the packet ; ldi txbyte, END ; SLIP start rcall putclick rcall char_delay ldi zh, high(ip_start) ldi zl, low(ip_start) ldi loop_count, (ip_header_size + udp_header_size) print_header_loop: ; IP + UDP header ld txbyte, z putslip adiw zl, 1 dec loop_count brne print_header_loop ldi zh, high(data_start) ldi zl, low(data_start) print_data_loop: ; data ld txbyte, z+ cpi txbyte, 0 breq print_data_continue putslip rjmp print_data_loop print_data_continue: ldi txbyte, END ; SLIP end rcall putclick rcall char_delay ret ; ; button_pressed ; handle button actions ; button_pressed: ; ; blink to acknowledge ; rcall blink ; ; send Web form ; rcall send_Web_form ret ; ; blink ; blink the light ; blink: in temp, LED_port ldi temp1, (1 << LED_pin) eor temp, temp1 out LED_port, temp rcall blink_delay in temp, LED_port ldi temp1, (1 << LED_pin) eor temp, temp1 out LED_port, temp rcall blink_delay ret ; ; send_Web_form ; send the Web form ; send_Web_form: ; ; set up packet ; ldi zl, low(ip_start) ldi zh, high(ip_start) ; ; IP ; .equ ip_start = SRAM_START .equ ip_header_size = 20 ldi temp, 0x45 ; version = 4 (4 bits), header length = 5 32-bit words (4 bits) st z+, temp ldi temp, 0 ; type of service st z+, temp .equ ip_length = ip_start + 2 ldi temp, 0 ; packet length high byte (to be calculated) st z+, temp ldi temp, 0 ; packet length low byte (to be calculated) st z+, temp ldi temp, 0 ; identification (high byte) st z+, temp ldi temp, 0 ; identification (low byte) st z+, temp ldi temp, 0 ; flag (3 bits), fragment offset (13 bits) (high byte) st z+, temp ldi temp, 0 ; flag (3 bits), fragment offset (13 bits) (low byte) st z+, temp ldi temp, 255 ; time to live st z+, temp ldi temp, 17 ; protocol = 17 for UDP st z+, temp .equ ip_checksum = ip_length + 8 .equ ip_header_size_before_checksum = 10 ldi temp, 0 ; header checksum (to be calculated) st z+, temp ldi temp, 0 ; header checksum (to be calculated) st z+, temp .equ ip_header_size_after_checksum = 8 .equ source_address = ip_checksum + 2 read_eeprom temp, eeprom_source_address ; source address byte 1 st z+, temp read_eeprom temp, eeprom_source_address+1 ; source address byte 2 st z+, temp read_eeprom temp, eeprom_source_address+2 ; source address byte 3 st z+, temp read_eeprom temp, eeprom_source_address+3 ; source address byte 4 st z+, temp .equ destination_address = source_address + 4 st z+, dest_1 ; destination address byte 1 st z+, dest_2 ; destination address byte 2 st z+, dest_3 ; destination address byte 3 st z+, dest_4 ; destination address byte 4 ; ; UDP ; .equ udp_header_size = 8 .equ udp_start = ip_start + 20 .equ source_port = udp_start .equ destination_port = udp_start + 2 .equ udp_length = udp_start + 4 ldi temp, high(Web_port) ; source port st z+, temp ldi temp, low(Web_port) ; source port st z+, temp ldi temp, high(Web_port) ; destination port st z+, temp ldi temp, low(Web_port) ; destination port st z+, temp ldi temp, 0 ; payload length high byte (to be calculated) st z+, temp ldi temp, 0 ; payload length low byte (to be calculated) st z+, temp ldi temp, 0 ; payload checksum (not used) st z+, temp ldi temp, 0 ; payload checksum (not used) st z+, temp ; ; null-terminated messages ; .equ data_start = udp_start + 8 empty_message: .db 0,0 on_form: .db "HTTP/1.1 200 OK",13,10,"Content-Type: text/html",13,10,13,10 .db "

",13,10 .db "light: on",13,10 .db "off ",13,10 .db "
",13,10 .db "blink:
",13,10 .db 0,0 off_form: .db "HTTP/1.1 200 OK",13,10,"Content-Type: text/html",13,10,13,10 .db "

",13,10 .db "light: on",13,10 .db "off ",13,10 .db "
",13,10 .db "blink:
",13,10 .db 0,0 ; ; select form ; sbic LED_port, LED_pin rjmp Web_send_on Web_send_off: set_data(off_form) rjmp Web_send_set_action Web_send_on: set_data(on_form) ; ; set form action addresses ; Web_send_set_action: ldi zh, high(data_start) ldi zl, low(data_start) ; ; radio action ; find_char '?' rcall set_address ; ; text action ; find_char '?' rcall set_address ; ; send packet ; rcall print_packet ret ; ; set_address ; z points to ASCII IP source address to be set in packet ; set_address: read_eeprom temp, eeprom_source_address binary_to_ascii temp, temp1, temp2, temp3 st z+, temp1 st z+, temp2 st z+, temp3 adiw zl, 1 read_eeprom temp, eeprom_source_address+1 binary_to_ascii temp, temp1, temp2, temp3 st z+, temp1 st z+, temp2 st z+, temp3 adiw zl, 1 read_eeprom temp, eeprom_source_address+2 binary_to_ascii temp, temp1, temp2, temp3 st z+, temp1 st z+, temp2 st z+, temp3 adiw zl, 1 read_eeprom temp, eeprom_source_address+3 binary_to_ascii temp, temp1, temp2, temp3 st z+, temp1 st z+, temp2 st z+, temp3 adiw zl, 1 ret ; ; toggle_light ; toggle the light ; toggle_light: in temp, LED_port ldi temp1, (1 << LED_pin) eor temp, temp1 out LED_port, temp ret ; ; main program ; reset: ; ; set fuse low byte to 0x7E for 20 MHz resonator ; ; set clock divider to /1 ; ldi temp, (1 << CLKPCE) ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0) sts CLKPR, temp sts CLKPR, temp1 ; ; set stack pointer to top of RAM ; ldi temp, high(RAMEND) out SPH, temp ldi temp, low(RAMEND) out SPL, temp ; ; init click pin for input with pull-up ; sbi click_port, click_pin cbi click_direction, click_pin ; ; init button for input with pull-up ; sbi button_port, button_pin cbi button_direction, button_pin ; ; init LED for output ; cbi LED_port, LED_pin sbi LED_direction, LED_pin ; ; init MOSFET pin for output ; cbi mosfet_port, mosfet_pin sbi mosfet_direction, mosfet_pin ; ; init registers ; clr zero ; 0 clr one ; 1 inc one ; " ; ; set source address if not assigned ; read_eeprom temp, eeprom_source_address cpi temp, 255 brne source_address_assigned source_address_not_assigned: ; ; turn on light, start counter, and wait for button to be pressed ; sbi LED_port, LED_pin clr temp1 clr temp2 clr temp3 source_address_not_assigned_loop: add temp1, one adc temp2, zero adc temp3, zero sbic button_pins, button_pin rjmp source_address_not_assigned_loop ; ; wait for button to be released ; source_address_not_button_release: sbis button_pins, button_pin rjmp source_address_not_button_release ; ; move address to EEPROM, acknowledge and turn off light ; write_eeprom eeprom_source_address+3, temp1 write_eeprom eeprom_source_address+2, temp2 write_eeprom eeprom_source_address+1, temp3 ldi temp1, 169 write_eeprom eeprom_source_address, temp1 rcall blink rcall blink cbi LED_port, LED_pin source_address_assigned: ; ; start event loop ; mainloop: ; ; wait for the button to be pressed or a click to arrive ; waitloop: sbis click_pins, click_pin ; check i0 pin for click rjmp click sbic button_pins, button_pin ; check for button rjmp waitloop ; ; button pressed ; button: ; ; wait for button to be released ; button_release: sbis button_pins, button_pin rjmp button_release rcall button_pressed rjmp mainloop ; ; click arrived ; click: ; ; check for i0 SLIP start of packet (END character) ; rcall getclick ldi temp, END cpse rxbyte, temp ; ; not start of packet, go back and wait for next char ; rjmp mainloop ; ; found start, get rest of i0 packet ; rcall get_i0_packet ; ; return if T set ; brtc check_address_1 rjmp mainloop ; ; check to see if incoming destination address matches ; check_address_1: compare_eeprom destination_address, eeprom_source_address brne check_broadcast_1 check_address_2: compare_eeprom destination_address+1, eeprom_source_address+1 brne check_broadcast_1 check_address_3: compare_eeprom destination_address+2, eeprom_source_address+2 brne check_broadcast_1 check_address_4: compare_eeprom destination_address+3, eeprom_source_address+3 breq check_port_1 ; ; address doesn't match, check for broadcast ; check_broadcast_1: compare_immediate destination_address, 255 breq check_broadcast_2 rjmp mainloop check_broadcast_2: compare_immediate destination_address+1, 255 breq check_broadcast_3 rjmp mainloop check_broadcast_3: compare_immediate destination_address+2, 255 breq check_broadcast_4 rjmp mainloop check_broadcast_4: compare_immediate destination_address+3, 255 breq check_port_1 rjmp mainloop ; ; address matches, check for Web port ; check_port_1: compare_immediate destination_port, high(Web_port) breq check_port_2 rjmp mainloop check_port_2: compare_immediate destination_port+1, low(Web_port) breq check_port_3 rjmp mainloop check_port_3: ; ; Web port, check for query ; check_light_on: find_string light_on, data_start light_on: .db "?light=on",0 brtc check_light_off sbi LED_port, LED_pin rjmp check_light_continue check_light_off: find_string light_off, data_start light_off: .db "?light=off",0 brtc check_light_blink cbi LED_port, LED_pin rjmp check_light_continue check_light_blink: find_string light_blink, data_start light_blink: .db "?blink=",0 brtc check_light_continue ascii_binary temp3, y check_light_blink_loop: rcall blink dec temp3 brne check_light_blink_loop check_light_continue: ; ; send form and return to main loop ; rcall send_Web_form rjmp mainloop