;:ts=8 ; Internal memory allocation ; 00-07: Register bank 0 -- used for non-interrupt code ; 08-0F: Register bank 1 -- used for interrupt code ; 10-17: Register bank 2 \ ; 18-1F: Register bank 3 > misc. variables go here ; 20-2F: Bit addressable space / ; 30-7F: Generic memory -- used for stack .equ ireg0, 8 .org 0x10 year: .skip 1 month: .skip 1 day: .skip 1 hours: .skip 1 minutes: .skip 1 seconds: .skip 1 year_copy: .skip 1 month_copy: .skip 1 day_copy: .skip 1 hours_copy: .skip 1 minutes_copy: .skip 1 seconds_copy: .skip 1 tickcnt1: .skip 1 tickcnt2: .skip 1 keycode: .skip 1 keyout: .skip 1 .flag cdflag,0x20.0 .flag secflag,0x20.1 .flag ovflag,0x20.2 .flag ioflag,0x20.3 ; 0: keypad/LCD 1: host .flag quietflag,0x20.4 .flag badflag,0x20.5 .flag menuflag,0x20.6 .flag xoffflag,0x20.7 .flag eventiosave,0x21.0 .flag showtime,0x21.1 .flag inring,0x21.2 .flag validpause,0x21.3 .flag rflag,0x21.4 .flag lflag,0x21.5 .flag ringflag,0x21.6 .flag toneflag,0x21.7 .flag seentone,0x22.0 .flag hungupflag,0x22.1 .flag flashflag,0x22.2 .flag flashphase,0x22.3 .org 0x28 keytimer: .skip 1 tabpos: .skip 1 bufptr: .skip 1 ticktimer1: .skip 1 ; External memory allocation .equ bufsize,127 .equ bufpage,0x22 .org 0x100*bufpage inbuf: .skip bufsize+1 c4save: .skip 1 silenttimer: .skip 2 ringtimer: .skip 1 ringcount: .skip 1 pickupcount: .skip 1 listentimer: .skip 1 lasttone: .skip 1 tonetimer: .skip 1 pickuptone: .skip 1 flashnum: .skip 1 flashtimer: .skip 1 .equ pwlength,10 password: .skip pwlength+1 weekday: .skip 1 c8save: .skip 1 sersave: .skip 1 .org 0x2300 initlcd: .skip 3 lputs: .skip 3 wrtlcd: .skip 3 lputchar: .skip 3 ljmp kgetchar daysthismonth: .skip 3 getdate: .skip 3 setdate: .skip 3 putchar: .skip 3 puts: .skip 3 printnum: .skip 3 printdate: .skip 3 prttime: .skip 3 lcd_input: .skip 3 lcd_parsenum: .skip 3 inputdate: .skip 3 crlf: .skip 3 tab: .skip 3 sputs: .skip 3 skipspc: .skip 3 bgetchar: .skip 3 matchtoken: .skip 3 getnum: .skip 3 getnumquiet: .skip 3 toupper: .skip 3 sputchar: .skip 3 ljmp handle_event initmsgtbl: .skip 3 msg_cmd: .skip 3 prompt: .skip 3 flash_cmd: .skip 3 handle_flash: .skip 3 clearline2: .skip 3 initflash: .skip 3 prtspc: .skip 3 cancelflash: .skip 3 password_cmd: .skip 3 localmode: .skip 3 localmenu: .skip 3 lsetpass: .skip 3 lbrowsemsgs: .skip 3 rings_cmd: .skip 3 pickup_cmd: .skip 3 lsetrings: .skip 3 lsetpick: .skip 3 gettone: .skip 3 gettone2: .skip 3 hangup: .skip 3 tdelay: .skip 3 lsetclock: .skip 3 date_cmd: .skip 3 keydispatch: .skip 3 sgetchar: .skip 3 getline: .skip 3 sersel: .skip 3 speak: .skip 3 saynum: .skip 3 compute_day: .skip 3 printwday: .skip 3 irmenu: .skip 3 lcd_select: .skip 3 printhex2: .skip 3 phonemenu: .skip 3 pickup: .skip 3 rsendcmd: .skip 3 rputchar: .skip 3 rreceivereply: .skip 3 rreceivechar: .skip 3 rfixserial: .skip 3 stackcheck: .skip 3 prt2dig: .skip 3 timer_cmd: .skip 3 inittimertbl: .skip 3 llisttimers: .skip 3 gettimeraddr: .skip 3 bumptentry: .skip 3 comparedates: .skip 3 .org 0x9000 rnametbl: .skip 256 .equ numtimers,10 .equ eventspertimer,10 .equ tentrysize,7+eventspertimer .equ maxevent,100 timertbl: .skip tentrysize*numtimers he_contextsave: .skip 9 ; Save area for A, R0-R7 he_datesave: .skip 6 ; Save area for date_copy variables. .org 0x3400 ;----------------------------------------------------------------------- ; Keypad character input routine ; ; Returns the last valid character detected by the interrupt ; server, if any. kgetchar: lcall handle_event clr A xch A,keyout ret ;--------------------------------------------------------------------------- ; ; The following is called from every possible wait loop. This allows us ; to do processing "nearly concurrently" with everything running without ; having to be at interrupt level. Stuff running from here has to save ; basically all context as the caller doesn't. ; ; secflag: The time has changed to a new second, or the caller wishes the ; clock to be redisplayed in the current second (i.e. may be set ; more than once per second). ; showtime: Enables the clock display. ; ; Things trashed: cdflag, B ; Before we go saving tons of context, merge all the event ; indicators together. If none are set, just leave. handle_event: mov C,P1.4 ; attention line from IR proc. cpl C ; (active low) orl C,secflag ; "time has changed" flag jc he_savecontext ret ; Save the important processor context: DPTR, A, R0-R7 he_savecontext: push DPL push DPH mov dptr,#he_contextsave movx @dptr,a mov a,R0 inc dptr movx @dptr,a mov R0,#1 he_saveloop: inc dptr mov a,@r0 movx @dptr,a inc r0 cjne r0,#8,he_saveloop ; Check if the IR processor indicates that the remote ; control state has changed. jb P1.4,he_checksecond ; Fetch the state (causing the IR processor to clear the ; attention line). setb cdflag mov a,#25 lcall rsendcmd lcall rreceivechar push ACC lcall rfixserial pop ACC ; Handling for the remote control buttons: ; ; POWER Equivalent to keypad ".", does not generate ; events. ; 0-9 If the "menumode" flag is set, these simulate ; keypad buttons and don't generate events. ; Otherwise they do. ; Others Generate events. jz he_remevent cjne a,#11,notpower mov keyout,#'.' sjmp he_checksecond notpower: jnb menuflag,he_remevent cjne a,#10,notzero mov keyout,#'0' sjmp he_checksecond notzero: mov B,a clr C subb a,#10 mov a,B jnc he_remevent add a,#'0' mov keyout,a sjmp he_checksecond ; Continue here if the remote control state change was not ; handled as a keypad button. he_remevent: nop ; Check if once-a-second processing must be done. he_checksecond: jbc secflag,he_dosecond ljmp event_exit ; Save the "date_copy" variables, which we need to overwrite ; for displaying the time, etc. he_dosecond: mov R0,#year_copy mov dptr,#he_datesave he_saveloop2: mov a,@r0 movx @dptr,a inc r0 inc dptr cjne r0,#seconds_copy+1,he_saveloop2 ; The time has changed. Run through all the timers to see ; if any of them have come up. Do this reasonably ; efficiently as there may be a lot of timer entries. mov dptr,#timertbl mov R5,#0 ; Timer number in R5, timer base address in DPTR he_tcloop: cjne R5,#numtimers,he_tcloop2 ljmp he_doclock he_tcloop2: movx a,@dptr jnz he_notnever ; Skip over a disabled timer entry. mov a,#tentrysize add a,DPL mov DPL,a jnc he_tcloop inc DPH inc R5 sjmp he_tcloop ; We've hit an enabled timer. Check if it has expired. he_notnever: lcall getdate lcall comparedates jc he_notyet ; We've hit a timer whose time is up. For now, just bump ; it up. lcall gettimeraddr lcall bumptentry ; Since we've trashed the DPTR, we must recompute it to ; continue stepping through the timer table. he_notyet: inc R5 lcall gettimeraddr ljmp he_tcloop ; If "showtime" is on, then update the time display on ; the LCD. he_doclock: jnb showtime,sec_exit clr cdflag lcall stackcheck mov C,ioflag mov eventiosave,C clr ioflag clr cdflag mov a,#0x80 lcall wrtlcd lcall getdate lcall prttime mov a,#' ' lcall lputchar mov dptr,#weekday movx a,@dptr lcall printwday mov a,#' ' lcall lputchar lcall printdate mov C,eventiosave mov ioflag,C sec_exit: mov dptr,#he_datesave mov R0,#year_copy he_restorelp2: movx a,@dptr mov @r0,a inc r0 inc dptr cjne r0,#seconds_copy+1,he_restorelp2 event_exit: mov R0,#1 mov dptr,#he_contextsave+2 he_restoreloop: movx a,@dptr mov @r0,a inc dptr inc r0 cjne r0,#8,he_restoreloop mov dptr,#he_contextsave movx a,@dptr inc dptr mov r0,a movx a,@dptr xch a,r0 pop DPH pop DPL event_ret: ret