;****************************************************************************** ;Author: Frank F. Hitzel, Braunschweig, Germany (2004) ;This software is distributed under the terms of the GNU General Public License ;****************************************************************************** .include "2313def.inc" rjmp RESET ; Reset Handler .org $004 rjmp TIM_COMP .org urxcaddr rjmp UART_RXC .org udreaddr rjmp UART_DRE ; UDR Empty Handler .def temp =r16 .def temp2 =r17 .def inpcursor =r23 .def rxstat =r24 ; bit0=1: line avail; bit0=0: no line; ; bit1=1: notify changes; bit1=0: don't notify .def changecount =r25 .def head =r1 .def tail =r2 .def rxptr =r3 .def portreg =r4 .def laststat =r5 .def getwordl =r6 .def getwordh =r7 .def timer_active =r8 ;bit0=1: timer_out0 active, bit1=1: timer_reg1_active, ... bit7 .def timer_stat =r9 ;bit0=0: on_timer_out0; bit0=1: off_timer_:out0; ... bit7 .def work1 =r10 .def work2 =r11 .def work =r12 .def savesreg =r13 ;only used in interrupts .equ ramstart =$60 .equ buflen =40 .equ rxbuflen =20 .equ frequency =10000000 ;.equ frequency =3690000 .equ timer_divi = (frequency / 1024) / 160 ;set timer_comp to 16 Hz .equ baud =9600 .equ bufend =RAMSTART + BUFLEN .equ rxbuf =RAMSTART .equ rxbufend =rxbuf+rxbuflen .equ parsebuf =rxbufend .equ parsebufend =parsebuf+rxbuflen .equ output_count =4 ;.equ output_count =8 .equ timers_start =bufend .equ timers_end =bufend + output_count*2*3 ;organization timer data in data segment: ;timers_start: ;.dw on_timer0 ;.dw on_timer1 ; ... ;.dw on_timern ;.dw off_timer0 ;.dw off_timer1 ;... ;.dw off_timern ;.dw timer0_counter ;.dw timer1_counter ;... ;.dw timern_counter ;timers_end: .dseg ;**************************** SAFE STATE TIMER .org timers_end safe_state: .BYTE 1 safe_timeout: .BYTE 2 safe_counter: .BYTE 2 .cseg .MACRO TIMERPROC ;******************** check timer mov yl,timer_active sbrs yl,@0 rjmp NEXT_TIMER ldi zl,timers_start + 2*output_count*2 + 2*@0 ld yl,Z+ ld yh,Z sbiw yh:yl,1 brne NOT_ZERO ;******************** time went up mov yl,timer_stat sbrc yl,@0 ;skip if output was cleared rjmp TIM_TIMER_FINISHED ;******************** turn output on .if output_count==4 ;activate output cbi PORTB,@0 + 4 .else cbi PORTB,@0 .endif mov yl,timer_stat ;mark timer status sbr yl,(1<<@0) mov timer_stat,yl ldi zl,timers_start + 2*output_count + 2*@0 ;set off-count ld yl,Z+ ld yh,Z tst yl brne OFF_NOT_ZERO tst yh brne OFF_NOT_ZERO ;******************** leave output on infinite time mov yl,timer_active ;deactivate timer cbr yl,(1<<@0) mov timer_active,yl rjmp NEXT_TIMER OFF_NOT_ZERO: ldi zl,timers_start + 2*output_count*2 + 2*@0 st Z+,yl st Z,yh rjmp NEXT_TIMER ;******************** turn output off and deactivate timer TIM_TIMER_FINISHED: .if output_count==4 ;deactivate output sbi PORTB,@0 + 4 .else sbi PORTB,@0 .endif mov yl,timer_active cbr yl,(1<<@0) mov timer_active,yl rjmp NEXT_TIMER ;******************** time not went up, write back decremented counter NOT_ZERO: dec zl st Z+,yl st Z,yh rjmp NEXT_TIMER NEXT_TIMER: .ENDMACRO ;*********************************************************************** TIM_COMP: in savesreg,SREG push yl push yh push zh push zl clr zh TIMERPROC 0 TIMERPROC 1 TIMERPROC 2 TIMERPROC 3 .if output_count==8 TIMERPROC 4 TIMERPROC 5 TIMERPROC 6 TIMERPROC 7 .endif ;******************** safe_timer lds yl,safe_timeout lds yh,safe_timeout+1 tst yl brne TIM_SAFE_NOT_ZERO tst yh breq TIM_COMP_RET ;no timer, return TIM_SAFE_NOT_ZERO: lds yl,safe_counter lds yh,safe_counter+1 sbiw yh:yl,1 breq TIM_SAFE_TIMER sts safe_counter,yl sts safe_counter+1,yh rjmp TIM_COMP_RET TIM_SAFE_TIMER: sts safe_timeout,yl sts safe_timeout+1,yl ;deactivate SAFE_TIMER lds yl,safe_state .if output_count==4 ori yl,$0F ;pull_ups on .endif out PORTB,yl ;activate safe_state TIM_COMP_RET: pop zl pop zh pop yh pop yl out SREG,savesreg reti ;*********************************************************************** UART_RXC: in savesreg,SREG push temp push zh push zl push yh push yl in temp,UDR sbic USR,FE ;skip next if no framing error rjmp IGNORE_RX clr ZH mov ZL,rxptr st Z+,temp cpi temp,$0D ;end of line brne RXC_NO_EOL ;we have a complete line here ldi ZL,rxbuf clr YH ldi YL,parsebuf RXC_MOVE_LP: ;copy line into parse buffer ld temp,Z+ st Y+,temp cpi temp,$0D brne RXC_MOVE_LP ldi ZL,rxbuf sbr rxstat,1 ;indicate we have a line rjmp RXC_NO_OVERFLW RXC_NO_EOL: cpi ZL,rxbufend brne RXC_NO_OVERFLW ldi ZL,rxbuf RXC_NO_OVERFLW: mov rxptr,ZL IGNORE_RX: pop yl pop yh pop zl pop zh pop temp out SREG,savesreg reti ;*********************************************************************** UART_DRE: in savesreg,SREG push temp cp head,tail brne DO_TRANS ; we have data.... cbi UCR,UDRIE ; no data, disable interrupts DRE_RETURN: pop temp out SREG,savesreg reti DO_TRANS: push ZL push ZH clr ZH mov ZL,tail ld temp,Z+ cpi ZL,bufend brne DRE_NO_OVER ldi ZL,$60 DRE_NO_OVER: mov tail,ZL out UDR,temp pop ZH pop ZL rjmp DRE_RETURN ;*********************************************************************** SWAIT: ldi temp2,$20 clr temp WAIT_LP: dec temp brne WAIT_LP dec temp2 brne WAIT_LP ret ;*********************************************************************** PUTBUF: ; put value in temp register into buffer cli cp head,tail clr ZH mov ZL,head st Z+,temp cpi ZL,bufend brne PB_NOOVER ldi ZL,$60 PB_NOOVER: mov head,ZL sbi UCR,UDRIE ; enable interrupts sei ret ;*************************************************************************** ;* ;* "mpy16u" - 16x16 Bit Unsigned Multiplication ;* ;* This subroutine multiplies the two 16-bit register variables ;* mp16uH:mp16uL and mc16uH:mc16uL. ;* The result is placed in m16u3:m16u2:m16u1:m16u0. ;* ;* Number of words :14 + return ;* Number of cycles :153 + return ;* Low registers used :None ;* High registers used :7 (mp16uL,mp16uH,mc16uL/m16u0,mc16uH/m16u1,m16u2, ;* m16u3,mcnt16u) ;* ;*************************************************************************** ;***** Subroutine Register Variables .def mc16uL =r16 ;multiplicand low byte .def mc16uH =r17 ;multiplicand high byte .def mp16uL =r18 ;multiplier low byte .def mp16uH =r19 ;multiplier high byte .def m16u0 =r18 ;result byte 0 (LSB) .def m16u1 =r19 ;result byte 1 .def m16u2 =r20 ;result byte 2 .def m16u3 =r21 ;result byte 3 (MSB) .def mcnt16u =r22 ;loop counter ;***** Code mpy16u: clr m16u3 ;clear 2 highest bytes of result clr m16u2 ldi mcnt16u,16 ;init loop counter lsr mp16uH ror mp16uL m16u_1: brcc noad8 ;if bit 0 of multiplier set add m16u2,mc16uL ;add multiplicand Low to byte 2 of res adc m16u3,mc16uH ;add multiplicand high to byte 3 of res noad8: ror m16u3 ;shift right result byte 3 ror m16u2 ;rotate right result byte 2 ror m16u1 ;rotate result byte 1 and multiplier High ror m16u0 ;rotate result byte 0 and multiplier Low dec mcnt16u ;decrement loop counter brne m16u_1 ;if not done, loop more ret ;************************************* PARSE NUMBER ;return WORD in getwordh:getwordl, return carry flag set if number too long GETWORD: mov work,inpcursor ;store position mov YL,inpcursor clr YH GETWORD_LENGTH: ;get length of number ld temp,Y+ cpi temp,'0' brlo GETWORD_AFTER cpi temp,('9'+1) brsh GETWORD_AFTER rjmp GETWORD_LENGTH GETWORD_AFTER: sbiw YH:YL,1 mov inpcursor,YL sub inpcursor,work breq GETWORD_ERR ;there is no numner... cpi inpcursor,6 brsh GETWORD_ERR ;number too long mov inpcursor,YL ldi zl,low(TRANSL_TAB << 1) ldi zh,high(TRANSL_TAB << 1) clr getwordh clr getwordl clr mc16uh GETWORD_LOOP: ld mc16ul,-Y subi mc16ul,'0' lpm ;load multiplicator adiw ZH:ZL,1 mov mp16ul,r0 lpm adiw ZH:ZL,1 mov mp16uh,r0 rcall mpy16u ;do multiplication add getwordl,m16u0 adc getwordh,m16u1 brcs GETWORD_ERR cp YL,work brne GETWORD_LOOP tst m16u2 brne GETWORD_ERR ;number too big clc ret GETWORD_ERR: sec ret ;*********************************************************************** WRITE_CONST_MSG: lpm adiw ZH:ZL,1 tst r0 breq WRITE_CONST_MSG_RET mov temp,r0 push ZH push ZL rcall PUTBUF pop ZL pop ZH rjmp WRITE_CONST_MSG WRITE_CONST_MSG_RET: ret ; This writes data terminated by $0D from RAM to output buffer ;*********************************************************************** WRITE_MSG: clr ZH WRITE_MSG_LP: ld temp,Z+ push ZL rcall PUTBUF pop ZL clr ZH cpi temp,$0D breq WRITE_MSG_RET rjmp WRITE_MSG_LP WRITE_MSG_RET: ldi temp,$0A ;write a 0A rcall PUTBUF ret ;*********************************************************************** SKIP_BLANKS: mov YL,inpcursor clr YH SKIP_LOOP: ld temp,Y cpi temp,' ' brne RET_SKIP_BLANKS inc YL rjmp SKIP_LOOP RET_SKIP_BLANKS: mov inpcursor,YL ret ;*********************************************************************** COMPCMD: ;parameter: Z is addr in prog mem mov YL,inpcursor clr YH COMPCMD_LOOP: lpm tst r0 brne COMPCMD_CONT mov inpcursor,YL ret ;return with zero flag set COMPCMD_CONT: adiw ZH:ZL,1 ld temp,Y+ cp temp,r0 brne RETCOMPCMD ;return with zero flag not set rjmp COMPCMD_LOOP RETCOMPCMD: ret ;*********************************************************************** RESET: ldi temp,low(RAMEND) out SPL,temp ;init Stack Pointer ldi temp,$60 ;init circle buffer mov head,temp mov tail,temp ldi temp,rxbuf mov rxptr,temp ;init rx clr rxstat .if output_count==4 ldi temp,$F0 ;Set high bits in PORTB to output .else ldi temp,$ff ;all bits are output if output_count==8 .endif out DDRB,temp ;Set PORTB to output ser temp out PORTB,temp in laststat,PINB ;save status ldi temp,(1 << TXEN)|(1 << RXEN)|(1 << RXCIE) ; init UART out UCR,temp ldi temp,(frequency / (16*baud)) - 1 out UBRR,temp clr zh sts safe_timeout,zh sts safe_timeout+1,zh ;disable safe_timer clr timer_stat clr timer_active clr temp ;timer setup out TCCR1A,temp ;disconnect OC1 and no PWM ldi temp,0b01101 ;select CK/1024 and clear counter on match ; ldi temp,0b01010 ;§§§§§§§§§§§§§§§§§§§§§ Testing out TCCR1B,temp ldi temp,high(timer_divi) out OCR1AH,temp ldi temp,low(timer_divi) ;timer interrupt every 16 Hz out OCR1AL,temp ldi temp,(1 << OCIE1A) out TIMSK,temp ;enable compare match interrupt ;rcall TEST MAIN_OK: lds zl,safe_timeout ;reset safe_timer lds zh,safe_timeout+1 sts safe_counter,zl sts safe_counter+1,zh MAIN: sei ; enable interrupts MAIN_LP: .if output_count==4 sbrs rxstat,1 rjmp NO_CHANGE_CHECK in temp,PINB andi temp,$0F cp temp,laststat breq MAIN_NO_CHANGE dec changecount brne NO_CHANGE_CHECK mov laststat,temp rcall dochange rjmp NO_CHANGE_CHECK MAIN_NO_CHANGE: ser changecount NO_CHANGE_CHECK: .endif sbrs rxstat,0 ;skip if we have a line rjmp MAIN_LP cli cbr rxstat,1 ;clear line-there-bit ldi inpcursor,parsebuf rcall skip_blanks ldi zl,low(cmdinfo << 1) ldi zh,high(cmdinfo << 1) rcall compcmd brne NEXTCMD1 rcall doinfo rjmp MAIN_OK NEXTCMD1: ldi zl,low(cmdon << 1) ldi zh,high(cmdon << 1) rcall compcmd brne NEXTCMD2 rcall doon rjmp MAIN_OK NEXTCMD2: ldi zl,low(cmdoff << 1) ldi zh,high(cmdoff << 1) rcall compcmd brne NEXTCMD3 rcall dooff rjmp MAIN_OK NEXTCMD3: ldi zl,low(cmdstatus << 1) ldi zh,high(cmdstatus << 1) rcall compcmd brne NEXTCMD4 rcall dostatus rjmp MAIN_OK NEXTCMD4: .if output_count==4 ldi zl,low(cmdchanges << 1) ldi zh,high(cmdchanges << 1) rcall compcmd brne NEXTCMD5 rcall dochanges rjmp MAIN_OK .endif NEXTCMD5: ldi zl,low(cmdarm << 1) ldi zh,high(cmdarm << 1) rcall compcmd brne NEXTCMD6 rcall doarm ;rcall test2 rjmp MAIN_OK NEXTCMD6: ldi zl,low(cmdreset << 1) ldi zh,high(cmdreset << 1) rcall compcmd brne NEXTCMD7 rcall doreset rjmp MAIN_OK NEXTCMD7: ldi zl,low(cmdtimers << 1) ldi zh,high(cmdtimers << 1) rcall compcmd brne NEXTCMD8 rcall dotimers rjmp MAIN_OK NEXTCMD8: ldi zl,low(cmddisarm << 1) ldi zh,high(cmddisarm << 1) rcall compcmd brne NEXTCMD9 rcall dodisarm rjmp MAIN_OK NEXTCMD9: ldi zl,low(cmdsafe << 1) ldi zh,high(cmdsafe << 1) rcall compcmd brne NEXTCMD10 rcall dosafe rjmp MAIN_OK NEXTCMD10: ldi zl,low(cmdhello << 1) ldi zh,high(cmdhello << 1) rcall compcmd brne NEXTCMD11 rcall OK_RET ;just return "ok" rjmp MAIN_OK NEXTCMD11: ldi zl,low(MSG_ERR << 1) ldi zh,high(MSG_ERR << 1) rcall WRITE_CONST_MSG; rjmp MAIN ;************************************* COMMAND ? DOINFO: ldi zl,low(MSG_INFO << 1) ldi zh,high(MSG_INFO << 1) rcall WRITE_CONST_MSG; ret ;************************************* PARSE NUMBER GET_NUM: mov YL,inpcursor clr YH ld temp,Y cpi temp,$0d brne GET_NUM_NOT_LAST sez ret ;that was it GET_NUM_NOT_LAST: cpi temp,'0' brlo GET_NUM_ERR cpi temp,'0'+output_count brsh GET_NUM_ERR subi temp,'0' inc inpcursor ;character was processed clc clz ret ;returns binary GET_NUM_ERR: clz sec ;indicate error ret ;************************************* return temp as a bit shifted from right SHIFT_NUM: mov temp2,temp ldi temp,1 clc tst temp2 SHIFT_NUM_LOOP: breq SHIFT_NUM_RET rol temp dec temp2 rjmp SHIFT_NUM_LOOP SHIFT_NUM_RET: ret ;******************************************************* ERROR & RETURN ERR_RET: ldi zl,low(MSG_ERR << 1) ldi zh,high(MSG_ERR << 1) rcall WRITE_CONST_MSG; ret ;******************************************************* ERROR & RETURN OK_RET: ldi zl,low(MSG_OK << 1) ldi zh,high(MSG_OK << 1) rcall WRITE_CONST_MSG; ret ;******************************************************* COMMAND DOON DOON: clr portreg DOON_NEXT: rcall skip_blanks rcall get_num breq DOON_RDY brcs ERR_RET .IF output_count==4 subi temp,-4 ;upper bits are output .ENDIF rcall shift_num or portreg,temp rjmp DOON_NEXT DOON_RDY: com portreg in temp,PORTB and temp,portreg ;.IF output_count==4 ; ori temp,$0F ;pull-ups on, is this necessary?? ;.ENDIF out PORTB,temp rjmp OK_RET ;******************************************************* COMMAND DOOFF DOOFF: clr portreg DOOFF_NEXT: rcall skip_blanks rcall get_num breq DOOFF_RDY brcs ERR_RET .IF output_count==4 subi temp,-4 ;upper bits are output .ENDIF rcall shift_num or portreg,temp rjmp DOOFF_NEXT DOOFF_RDY: in temp,PORTB or temp,portreg out PORTB,temp rjmp OK_RET JMP_ERR_RET2: rjmp ERR_RET ;******************************************************* COMMAND DOSTATUS DOSTATUS: .IF output_count==4 in temp,PORTB andi temp,$F0 ;only upper bits are output in temp2,PINB andi temp2,$0F ;only lower bits are input or temp2,temp .ELSE in temp2,PORTB ;all bits are output .ENDIF ldi inpcursor,8 ;register not used, we use it here DOSTATUS_LOOP: rol temp2 brcs DOSTATUS_CSET ldi temp,'1' rjmp DOSTATUS_PUT DOSTATUS_CSET: ldi temp,'0' DOSTATUS_PUT: rcall putbuf dec inpcursor brne DOSTATUS_LOOP ldi temp,' ' rcall putbuf lds zl,safe_timeout lds zh,safe_timeout+1 or zl,zh breq STAT_SAFE_OFF ldi temp,'1' rjmp STAT_SAFE STAT_SAFE_OFF: ldi temp,'0' STAT_SAFE: rcall putbuf ldi temp,13 rcall putbuf ldi temp,10 rcall putbuf ret .if output_count==4 ;******************************************************* COMMAND DOCHANGES DOCHANGES: rcall skip_blanks rcall get_num cpi temp,2 brsh JMP_ERR_RET2 clc bst temp,0 bld rxstat,1 in temp,PINB andi temp,$0F mov laststat,temp rjmp OK_RET ;******************************************************* COMMAND DOCHANGE DOCHANGE: in temp2,PINB .IF output_count==4 ldi inpcursor,4 ;register not used, we use it here DOCHANGE_SHIFT: ;shift 4 bits left lsl temp2 dec inpcursor brne DOCHANGE_SHIFT .ENDIF ldi inpcursor,output_count DOCHANGE_LOOP: lsl temp2 brcs DOCHANGE_CSET ldi temp,'1' rjmp DOCHANGE_PUT DOCHANGE_CSET: ldi temp,'0' DOCHANGE_PUT: rcall putbuf dec inpcursor brne DOCHANGE_LOOP ldi temp,13 rcall putbuf ldi temp,10 rcall putbuf ret .endif ;******************************************************* COMMAND DOARM DOARM: rcall skip_blanks rcall get_num breq JMP_ERR_RET brcs JMP_ERR_RET mov portreg,temp ;save port_num rcall skip_blanks rcall GETWORD brcs JMP_ERR_RET tst getwordl brne DOARM_NOTZERO1 tst getwordh breq JMP_ERR_RET ;on-time is zero DOARM_NOTZERO1: ldi temp,$0f ;wait time too long cp temp,getwordh brlo JMP_ERR_RET rcall DOARM_SHIFT ;multiply by 16 mov work1,getwordl ;save on-time mov work2,getwordh rcall skip_blanks rcall GETWORD brcs JMP_ERR_RET ldi temp,$0f ;wait time too long cp temp,getwordh brlo JMP_ERR_RET rcall DOARM_SHIFT ;multiply by 16 mov temp,portreg lsl temp ;temp *= 2 (timer sind words) cli ;avoid timer clr zh ldi zl,timers_start add zl,temp st Z+,work1 ;store on-time st Z,work2 subi zl,-((output_count*2)-1) ;move to off-area st Z+,getwordl ;store off-time st Z,getwordh subi zl,-((output_count*2)-1) ;move to counter-area st Z+,work1 ;store current counter st Z,work2 mov temp,portreg .if output_count==4 subi temp,-4 .endif rcall SHIFT_NUM ;bit to temp in temp2,PORTB or temp2,temp out PORTB,temp2 ;switch off output .if output_count==4 mov temp,portreg rcall SHIFT_NUM ;bit to temp, upper bits are output .endif or timer_active,temp ;activate timer com temp and timer_stat,temp ;status=on sei ;reenable timer rjmp OK_RET DOARM_SHIFT: ;shift getwordh:getwordl 4 bit left ldi temp,4 DOARM_SHIFTLP: lsl getwordl rol getwordh dec temp brne DOARM_SHIFTLP ret JMP_ERR_RET: rjmp ERR_RET ;******************************************************* COMMAND DODISARM DODISARM: rcall skip_blanks rcall get_num breq JMP_ERR_RET brcs JMP_ERR_RET cli rcall SHIFT_NUM ;bit to temp com temp and timer_active,temp sei rjmp OK_RET ;******************************************************* COMMAND DORESET (reset timer) DORESET: rcall skip_blanks rcall get_num breq JMP_ERR_RET brcs JMP_ERR_RET mov portreg,temp rcall shift_num mov temp2,timer_active ;is timer active? and temp2,temp breq JMP_ERR_RET cli mov temp2,timer_stat ;is time up? and temp2,temp breq RESET_OK sei rjmp ERR_RET RESET_OK: mov temp,portreg lsl temp ;temp *= 2 clr zh ldi zl,timers_start add zl,temp ld getwordl,Z+ ;restore on-counter ld getwordh,Z subi zl,-(output_count*2*2-1) st Z+,getwordl st Z,getwordh sei rjmp OK_RET ;******************************************************* COMMAND DOTIMERS DOTIMERS: mov temp2,timer_active ldi inpcursor,output_count ;register not used, we use it here .if output_count==4 swap temp2 ;move to upper bits .endif DOTIMERS_LOOP: rol temp2 brcs DOTIMERS_CSET ldi temp,'0' rjmp DOTIMERS_PUT DOTIMERS_CSET: ldi temp,'1' DOTIMERS_PUT: rcall putbuf dec inpcursor brne DOTIMERS_LOOP ldi temp,13 rcall putbuf ldi temp,10 rcall putbuf ret ;******************************************************* COMMAND DOSAFE DOSAFE: rcall skip_blanks rcall getword brcs JMP_ERR_RET cli tst getwordh brne DOSAFE_NOT_ZERO tst getwordl brne DOSAFE_NOT_ZERO clr zh sts safe_timeout,zh sts safe_timeout+1,zh ;disable timer sei rjmp OK_RET DOSAFE_NOT_ZERO: ;enable SAFE_TIMER rcall DOARM_SHIFT ;shift timer 4 bits to the left clr zh ldi zl,safe_timeout st Z+,getwordl st Z,getwordh ldi zl,safe_counter ;init counter st Z+,getwordl st Z,getwordh rcall skip_blanks clr zl ;use zl for state ldi temp2,output_count DOSAFE_LOOP: rcall GET_NUM brcs DOSAFE_ERR cpi temp,2 brsh DOSAFE_ERR com temp andi temp,1 lsl zl or zl,temp dec temp2 brne DOSAFE_LOOP .IF output_count==4 swap zl .ENDIF sts safe_state,zl sei rjmp OK_RET DOSAFE_ERR: clr zh sts safe_timeout,zh sts safe_timeout+1,zh ;disable timer sei rjmp ERR_RET ;******************************************************* TEST ;TEST: ; ldi zl,low(cmdsafetest << 1) ; ldi zh,high(cmdsafetest << 1) ; clr yh ; ldi yl,parsebuf ;TST_LP: ; lpm ; adiw ZH:ZL,1 ; st y+,r0 ; tst r0 ; brne TST_LP ; sbr rxstat,1 ; ret .org ((PC >> 1) << 1) + 2 CMDINFO: .db '?',0 CMDON: .db "activate",0,0 CMDOFF: .db "deactivate",0,0 CMDSTATUS: .db "status",0,0 CMDCHANGES: .db "changes",0,0,0 CMDARM: .db "arm",0 CMDDISARM: .db "disarm",0,0 CMDRESET: .db "reset",0 CMDTIMERS: .db "timers",0,0 CMDSAFE: .db "safe",0,0 CMDHELLO: .db "hello",0 MSG_OK: .db "ok",13,10,0,0 MSG_ERR: .db "error",13,10,0 MSG_INFO: .db "DoubleFox I/O Rev. 1.2a",13,10,0,0 ;CMDSAFETEST: ; .db "safe 1 1010",13,0,0 ;CMDRESETTEST: ; .db "reset 0",13,0,0 TRANSL_TAB: .dw 1 .dw 10 .dw 100 .dw 1000 .dw 10000