;---------------------------------------------------------------------------; ; RS-232 Data Switch Firmware ; ; ; ; File: MAIN.ASM ; ; ; ; This file contains the mainline code which controls the operation of the ; ; switch, as well as several central subroutines. ; ;---------------------------------------------------------------------------; main segment code unit rseg main $nolist $include(globals.asm) $list extrn code(putchar) extrn code(getline) extrn code(prtstr) extrn code(matchtoken) extrn code(date_cmd) extrn code(name_cmd) extrn code(list_cmd) extrn code(baud_cmd) extrn code(break_cmd) extrn code(dtr_cmd) extrn code(dcd_cmd) extrn code(call_cmd) extrn code(getnum) extrn code(getnumquiet) extrn code(skipspc) extrn code(printnum) extrn code(crlf) extrn code(clear_cmd) extrn code(off_cmd) extrn code(link_cmd) extrn code(unlink_cmd) extrn code(getpassword) extrn code(bgetchar) extrn code(mode_cmd) extrn code(mask_cmd) extrn code(clear) extrn code(auto_cmd) extrn code(isconnected) extrn code(help_cmd) extrn code(run_cmd) extrn code(dl_cmd) public idle public prompt public bye public setown public fixtbl public connect public vconnect public setbaud public getport public handle_event public checknorm public checkmaint ;--------------------------------------------------------------------------- ; Module: idle ; ; Description: ; This code is executed when no port is in command mode. It simply waits ; for events (DTR on/off, break) to be signaled from the interrupt routine, ; and calls the event handler when it gets one. When a break request is ; enqueued by the event handler, it unqueues it and enters command mode. ; ; Inputs: n/a ; Outputs: n/a ; ; Loop, processing events, until a break request is enqueued. idle: mov myport,#0 idle2: jb queueflag,idle_gotbrk idle_waitevent: jnb attnflag,idle2 lcall handle_event sjmp idle ; Read the entry at the head of the break queue. idle_gotbrk: mov dptr,#brkqueue movx a,@dptr mov r5,a ; Move the second entry down to the head position. If this ; is the terminating zero, reset the queue flag. mov a,#1 movc a,@a+dptr movx @dptr,a jnz idle_dqloop clr queueflag sjmp q_empty ; If the queue was not empty, move all the remaining entries ; down by one position. idle_dqloop: inc dptr mov a,#1 movc a,@a+dptr movx @dptr,a jnz idle_dqloop ; Since the queue is not empty, and the queue flag still set, ; the current requester only gets 30 seconds. mov waittimer,#30 ; Initialize "myport" to the port number of the requester. q_empty: mov myport,r5 ; Temporarily disconnect connections listening to this port. ; This is so they do not see the commands being typed. The ; connections remain set up in the logical connection table, ; and will be restored on exit from command mode. mov r6,#1 dcloop: mov dptr,#c_sourcetbl-1 mov a,r6 movc a,@a+dptr cjne a,myport,dcloopend mov r0,6 mov r1,#15 lcall connect dcloopend: inc r6 cjne r6,#maxport+1,dcloop ; Set up a bidirectional connection between the reqeusting ; port and the CPU. mov r0,#0 mov r1,5 lcall connect mov r0,5 mov r1,#0 lcall connect ; Set the baud rate. lcall guessbaud ; If a timeout occurred or the current user dropped DTR, abort ; the logon procedure. jnb byeflag,checkinit ljmp bye ; If this is the first entry into command mode, print the ; signon screen, prompt for passwords, and put the user into ; maintenance mode. checkinit: jb signonflag,setperm setb signonflag mov dptr,#signonmsg lcall prtstr lcall initpw lcall crlf clr restrictflag setb maintflag sjmp prompt ; Check the restriction table, and set restricted mode if ; required. setperm: clr maintflag clr restrictflag mov a,myport mov dptr,#restrictbl-1 movc a,@a+dptr jz prompt mov dptr,#restrictmsg lcall prtstr setb restrictflag ;--------------------------------------------------------------------------- ; Module: prompt ; ; Description: ; This is the top level command entry point. It prints a prompt, waits ; for an input string, decodes the command, and jumps to the appropriate ; command routine. ; ; Inputs: n/a ; Outputs: n/a ; ; If the current command session is being timed out, print ; the number of seconds remaining before the prompt. prompt: jnb queueflag,nprompt mov r1,#'0' mov r2,#2 mov a,waittimer lcall printnum ; Print a ">" prompt and wait for a command. nprompt: mov a,#'>' lcall putchar mov r0,#80 lcall getline ; If a timeout occurred or the user dropped DTR, abort the ; session. jnb byeflag,line_ok ljmp bye ; Just print another prompt if a null command was entered. line_ok: lcall skipspc jz prompt ; First, give any external routines a chance to intercept ; the command. lcall extdec ; Decode the first word of the input string, and print an ; error message if it does not match any of the commands. mov dptr,#cmdtbl lcall matchtoken jnz got_cmd mov dptr,#invalidcmd lcall prtstr sjmp prompt ; Dispatch a command by executing the appropriate entry from ; the jump table. got_cmd: mov b,#3 mul ab mov dptr,#jmptbl-3 jmp @a+dptr ; Command jump table jmptbl: ljmp help_cmd ; User commands ljmp bye ljmp baud_cmd ljmp call_cmd ljmp clear_cmd ljmp date_cmd ljmp help_cmd ljmp list_cmd ljmp link_cmd ljmp off_cmd ljmp unlink_cmd ljmp maint_cmd ; Level change commands ljmp normal_cmd ljmp restrict_cmd ljmp auto_cmd ; Maintenance commands ljmp break_cmd ljmp dcd_cmd ljmp dtr_cmd ljmp mask_cmd ljmp mode_cmd ljmp name_cmd ljmp run_cmd ljmp dl_cmd ; Error message invalidcmd: db 'Invalid command.',13,10,0 ; Command table. cmdtbl: db '?',0,'BYE',0,'BAUD',0,'CALL',0,'CLEAR',0,'DATE',0 db 'HELP',0,'LIST',0,'LINK',0,'OFF',0,'UNLINK',0,'MAINT',0 db 'NORMAL',0,'RESTRICT',0,'AUTOCONNECT',0,'BREAK',0 db 'DCD',0,'DTR',0,'MASK',0,'MODE',0,'NAME',0 db 'RUN',0,'DOWNLOAD',0,0 ;--------------------------------------------------------------------------- ; Module: bye ; ; Description: ; This routine handles exit from command mode. It is reached either ; directly by a "bye" command, or called when any other condition requires ; exit from command mode. ; ; Inputs: n/a ; Outputs: n/a ; ; First, wait for any last character to be transmitted. bye: jnb scon.1,bye ; Disconnect CPU's serial input. mov r0,#0 mov r1,#15 lcall connect ; Restore any logical connections which were suspended when ; command mode was entered (any which have the command ; port as their source). mov r5,#1 rcloop: mov dptr,#c_sourcetbl-1 mov a,r5 movc a,@a+dptr cjne a,myport,rc_nofix mov r0,5 mov r1,a lcall connect rc_nofix: inc r5 cjne r5,#maxport+1,rcloop ; Reconnect whatever the command port was listening to. mov a,myport mov dptr,#c_sourcetbl-1 movc a,@a+dptr mov r0,myport mov r1,a lcall connect ; Go to idle mode (this may immediately cause a break request ; to be dequeued and another port to enter command mode). ljmp idle ;--------------------------------------------------------------------------- ; Function: vconnect ; ; Description: ; This routine establishes a logical (virtual) connection. A physical ; connection is only set up if neither end of the connection involves the ; port which is currently in command mode. ; ; Inputs: R0 - Destination port ; R1 - Source port ; ; Outputs: None ; ; Compute the address of the corresponding logical connection ; table entry. vconnect: mov a,r0 dec a add a,#c_sourcetbl-256*(c_sourcetbl/256) mov dpl,a clr a addc a,#c_sourcetbl/256 mov dph,a ; Install the source port in the table. mov a,r1 movx @dptr,a ; Drop into "connect" to make the connection a physical one, ; if it does not involve the command port. cjne a,myport,notfromme ret notfromme: mov a,r0 cjne a,myport,connect ret ;--------------------------------------------------------------------------- ; Function: connect ; ; Description: ; This routine establishes a physical connection. ; ; Inputs: R0 - Destination port ; R1 - Source port ; ; Outputs: None ; ; Since each connection register contains the data for ; two ports, compute the address in the connection table ; of the connection pair of which the requested connection ; is a member. connect: mov dptr,#connectbl mov a,r0 clr acc.0 add a,dpl mov dpl,a jnc nocarry5 inc dph ; Disable interrupts, and branch depending on whether the ; connection affects the high (odd port) or low (even port) ; half of a connection register. ; NOTE: It is safe to disable interrupts here, since the ; sequence of instructions executed takes much less than the ; 256 instruction cycles executed between interrupts. We ; do not ever want to miss an interrupt, since interrupts ; are counted to maintain the time and date. nocarry5: mov a,r0 clr ie.7 jb acc.0,oddport ; Handle a connection involving bits 0-3 of a connection ; register. First, load the connection into the physical ; connection table, and retain it in the low nybble of R2. mov a,r1 movx @dptr,a anl a,#0fh mov r2,a ; Increment the data pointer, get the value of the next ; connection entry, and put this into the high nybble of ; the accumulator. inc dptr movx a,@dptr anl a,#0fh swap a sjmp setreg ; Handle a connection involving bits 4-7 of a connection ; register. First, get the even connection table entry to ; see what must be loaeded into bits 0-3, and retain this ; in R2. oddport: movx a,@dptr anl a,#0fh mov r2,a ; Increment the data pointer, store the connection in the ; (now odd) entry in the connection table, and retain the ; value in the high nybble of the accumulator. mov a,r1 inc dptr movx @dptr,a anl a,#0fh swap a ; Combine R2 and A to obtain the value to load into the ; connection register. setreg: orl a,r2 mov r2,a ; Compute the address of the connection register. mov dptr,#connregbase mov a,r0 rr a add a,dpl mov dpl,a jnc nocarry6 inc dph ; Load the connection register, reenable interrupts, and ; exit. nocarry6: mov a,r2 movx @dptr,a setb ie.7 ret ;--------------------------------------------------------------------------- ; Function: setbaud ; ; Description: ; This routine sets the baud rate for the 8031's built-in serial port. ; ; Inputs: A - baud rate code (1 = 110 bps, 2 = 300 bps, ... 7 = 19200 bps). ; ; Outputs: None ; ; Wait for any last character to be transmitted. setbaud: jnb scon.1,setbaud mov r0,a ; Stop the baud rate counter. clr tcon.6 ; Load SMOD and TH1 from the tables. mov dptr,#baudth1tbl-1 movc a,@a+dptr mov th1,a mov dptr,#baudsmodtbl-1 mov a,r0 movc a,@a+dptr jz clearsmod orl pcon,#80h sjmp baud_done clearsmod: anl pcon,#7fh baud_done: mov scon,#52h ; Restart the baud rate counter and exit. setb tcon.6 ret ; Tables of values for TH1 and SMOD. baudth1tbl: db 0,0a0h,0e8h,0f4h,0fah,0fdh,0fdh baudsmodtbl: db 0,0,0,0,0,0,1 ;--------------------------------------------------------------------------- ; Function: guessbaud ; ; Description: ; This routine sets the baud rate for a command session. It prompts ; with "" at the most recently used baud rate, then waits for a ; character. If the character received is not a CR, it tries the next ; most recently used baud rate and repeats. It cycles through all the ; baud rates and starts over if necessary, until a CR is received or an ; event causes the session to be aborted. ; ; If another port is waiting for attention, allow the current user to ; continue until either his 30 seconds are up, or he has been idle for ; 30 seconds (this may be less than 30 seconds after the request came ; in). ; ; The baud rate guessing procedure is complicated by two things: ; (a) A character at a low baud rate may come out as more than one ; character at a high baud rate. ; (b) The 8031 discards characters whose start bits are invalid. ; This makes it necessary to detect characters manually by polling the ; serial input for the leading 1-0 transition of the start bit. After ; this has been seen, a delay loop is executed for 1/10 second to to ; solve problem (a). Then the 8031's serial input status is checked, ; and an invalid character considered to have been received even if the ; 8031 indicates nothing. This sloves problem (b). ; ; Inputs: myport - contains port number whose table is to be used. ; ; Outputs: None ; guessbaud: clr byeflag ; Compute the address of the baud rate table to be used. mov a,myport mov b,#7 mul ab mov dptr,#baudtbl-7 add a,dpl mov dpl,a jnc nocarry7 inc dph ; Try 7 entries from the table before repeating. nocarry7: mov r1,#7 ; Main loop. Get a baud rate from the table, set this baud ; rate, and prompt "". guessloop: movx a,@dptr push dpl push dph lcall setbaud mov dptr,#returnstr lcall prtstr pop dph pop dpl ; Start the idle timer at 30 seconds. mov idletimer,#30 ; Wait for one of the following conditions. waitstart: jnb attnflag,waitstart2 ; (1) The interrupt routine indicates that an event should ; be handled - go and service it. push dpl push dph lcall handle_event pop dph pop dpl jb byeflag,byebye waitstart2: jnb queueflag,waitstart3 ; (2) A request is queued - check timers and exit if either ; has expired. mov a,idletimer jz waitabort mov a,waittimer jnz waitstart3 ; (2A) A timer has expired. Print "Timeout" and exit. waitabort: mov dptr,#guesststr lcall prtstr setb byeflag byebye: ret waitstart3: jb p3.0,waitstart ; (3) The CPU's serial input is low. This indicates a start ; bit, i.e. the user is sending a character. Debounce ; the start bit by checking the input four more times, ; and ignoring the transition if it goes away. mov r0,#4 wait2: jb p3.0,waitstart djnz r0,wait2 ; Having detected a start bit, we wish to delay at least ; the time it takes to receive one character at 110 baud. ; 1/10 second is used. This equals 92160 instruction cycles. ; 92160 / 770 = 120 mov r0,#120 clr a ; The following 3 instructions will waste 770 * R0 ; instruction cycles. wait3: inc a ; 1 * 256 cycles cjne a,#0,wait3 ; 2 * 256 cycles djnz r0,wait3 ; 2 cycles ; Having made sure that enough time has passed to receive ; a character at any baud rate, we now check if a carriage ; return is sitting in the serial receive register. jnb scon.0,notreturn mov a,sbuf clr scon.0 clr acc.7 cjne a,#13,notreturn ; A carriage return has been received. Leave the current ; baud rate set, move it to the front of the baud rate table, ; print a CRLF, and exit. movx a,@dptr mov r3,a mov a,myport lcall fixtbl ljmp crlf ; No character was received, or the received character was ; not CR. Loop until the end of the baud rate table is ; reached. notreturn: inc dptr djnz r1,guessloop ; Start over at the most recently used baud rate. sjmp guessbaud returnstr: db 13,10,' ',0 guesststr: db 'Timeout.',13,10,0 ;--------------------------------------------------------------------------- ; Function: getport ; ; Description: ; This routine gets a port identifier from the current command line. ; This may be a number or a name from the port name table. "skipspc" ; must have been called before this routine and the buffer pointer must ; point to a non-null, non-space character. The function prints an ; error message if unable to get a valid port id. ; ; Inputs: None ; ; Outputs: A - port number or zero if invalid port entered. ; ; Use the token matcher to check if a port name was entered. getport: mov dptr,#nametbl lcall matchtoken jnz gotport ; Whatever is on the command line matched none of the port ; names, so it must be a number. mov r2,#' ' lcall getnumquiet ; If the number is invalid, zero, or greater than the highest ; port number, give an error message. jb badflag,badport mov a,r1 jz badport cjne a,#maxport+1,get2 get2: jnc badport gotport: ret badport: mov dptr,#portstr lcall prtstr clr a ret portstr: db 'Invalid port name/number entered.',13,10,0 ;--------------------------------------------------------------------------- ; Function: handle_event ; ; Description: ; This routine handles events signaled by the interrupt routine by the ; attention flag. It must be called whenever this flag is found to be ; set. It will process the event(s) and clear the flag, then return. ; ; For each port, one of the following three events may have occurred, ; and will be acted upon as shown: ; (a) A break was received. If valid, then enqueue the port on the ; break queue, and make sure the current session is timed out. ; (b) DTR disappeared for a port. Clear all its connections, and signal ; that it should be dropped out of command mode if it is the currently ; active port. ; (c) DTR was asserted for a port. If the port has an autoconnect ; set up, process it. ; ; Inputs: None ; ; Outputs: queueflag - if set, indicates that another port has sent a break ; and is waiting for attention. ; byeflag - if set, indicates that the current port should be ; taken out of command mode immediately (its DTR has ; disappeared). ; waittimer - started at 30 seconds if the queueflag is set. ; ; Clear the attention flag right away so if another event ; occurs while we are processing the current ones, it will ; be set again, and the new event won't be missed. handle_event: clr attnflag ; Scan the break flag table for non-zero entries. mov r5,#1 mov dptr,#brkflagtbl break_loop: movx a,@dptr jz nobreak clr a movx @dptr,a ; A break is indicated on the curretn port. Find if it should ; be ignored for any reason. ; 1. Ignore breaks coming from own port. mov a,myport clr c subb a,r5 jz nobreak ; 2. Ignore breaks from ports where DTR is not ignored and ; not asserted. push dpl push dph mov a,r5 mov dptr,#dtrtimtbl-1 movc a,@a+dptr jz checkconn mov a,r5 mov dptr,#dtrcnttbl-1 movc a,@a+dptr jnz ignoreit ; 3. Ignore breaks coming from a port which someone else ; owns a connection to - these ports are not allowed ; to enter command mode. checkconn: mov a,r5 mov dptr,#c_sourcetbl-1 movc a,@a+dptr clr c subb a,#15 jz break_ok mov dptr,#c_owntbl-1 mov a,r5 movc a,@a+dptr clr c subb a,r5 jz break_ok ignoreit: pop dph pop dpl sjmp nobreak ; The break signal is valid. Put the port on the break ; queue by scanning it until the terminating zero is found, ; then adding the port number there. If the port number ; is already found in the queue while traversing it, then ; don't add it again. break_ok: mov dptr,#brkqueue brkq_loop: movx a,@dptr jz brkq_end clr c subb a,r5 jz no_insert inc dptr sjmp brkq_loop brkq_end: mov a,r5 movx @dptr,a inc dptr clr a movx @dptr,a no_insert: pop dph pop dpl ; If the queue flag is already set, then the timer timing ; out the current user's session is already ticking, so ; don't start it again. jb queueflag,nobreak ; Set the queue flag and start the timer at 30 seconds. setb queueflag mov waittimer,#30 ; Loop until all ports are done. nobreak: inc dptr inc r5 cjne r5,#maxport+1,break_loop ; Handle DTR events. DTR events only occur if DTR detection ; for a given port is enabled, so we don't need to check ; this again. Each entry in the DTR flag table may have ; one of the following values: ; 0: No event ; 1: DTR went on ; 2: DTR went off mov r6,#1 ; Compute the address of the current table entry. h_dtr_loop: mov a,r6 dec a add a,#dtrflagtbl-256*(dtrflagtbl/256) mov dpl,a clr a add a,#dtrflagtbl/256 mov dph,a ; Since table entries can take on more than two values, ; disable interrupts while reading one. This is so that ; a "DTR off" event does not overwrite a "DTR on" event, ; for example, between the time we read it and the time ; we clear the entry to zero. clr ie.7 movx a,@dptr mov r5,a clr a movx @dptr,a setb ie.7 cjne r5,#1,notdtron ; Handle a "DTR on" event. This may need an autoconnect ; to be processed. ; Find if the port is already connected to something; if ; so, no autoconnect can be done. mov a,r6 lcall isconnected jnz notdtroff ; The port is free, check if it has an autoconnect set up. mov dptr,#autoconntbl-1 mov a,r6 movc a,@a+dptr jz notdtroff ; An autoconnect was set up, make sure the far end port ; is available also. mov r5,a lcall isconnected jnz notdtroff ; Both ports are available, so establish the connection. Make ; both ends of it owned by the autoconnecting port. push 0 push 1 push 2 ; Connect. mov r0,5 mov r1,6 lcall vconnect mov r0,6 mov r1,5 lcall vconnect ; Set connection ownership. mov r0,myport mov myport,r6 mov a,r5 lcall setown mov a,r6 lcall setown mov myport,r0 pop 2 pop 1 pop 0 sjmp notdtroff notdtron: cjne r5,#2,notdtroff ; Handle a "DTR off" event. Clear all connections owned by ; the port. push 0 push 1 lcall clear pop 1 pop 0 ; If the port is currently in command mode, indicate that ; it should be dropped immediately. mov a,r6 cjne a,myport,notdtroff setb byeflag ; Loop until all ports are done. notdtroff: inc r6 cjne r6,#maxport+1,h_dtr_loop handle_done: ret ;--------------------------------------------------------------------------- ; Function: setown ; ; Description: ; This function sets the "ownership" of a connection, i.e. it stores who ; set the connection up. ; ; Inputs: A - port number. ; ; Outputs: None ; setown: dec a add a,#c_owntbl-256*(c_owntbl/256) mov dpl,a clr a addc a,#c_owntbl/256 mov dph,a mov a,myport movx @dptr,a ret ;--------------------------------------------------------------------------- ; Function: fixtbl ; ; Description: ; This function rearranges the "most recently used baud rate" list for ; the given port, to put the current baud rate at the head of the list. ; ; Inputs: A - port number. ; R3 - Baud rate code (1 to 7) ; ; Outputs: None ; ; Compute the address of the port's baud rate list. fixtbl: dec a mov b,#7 mul ab mov dptr,#baudtbl add a,dpl mov dpl,a clr a addc a,dph mov dph,a ; Store the baud rate code at the start of the list, then ; traverse the list, moving all entries up by one, until ; the old position of the baud rate code is found and the ; list has therefore been rearranged completely. mov 0,r3 fixloop: movx a,@dptr xch a,r0 movx @dptr,a inc dptr mov a,r3 cjne a,0,fixloop ret ; Initial Signon Message ; ---------------------- signonmsg: db 13,10,13,10,'RS-232 DATA SWITCH',13,10,13,10 db 'Designed and built by Markus Wandel.',13,10 db 'Firmware version 1.00, July 21, 1989.',13,10,0 ;--------------------------------------------------------------------------- ; Function: copypw ; ; Description: ; This function copies a password from the input buffer to a password ; storage location. ; ; Inputs: DPTR - pointer to password storage location ; ; Outputs: None ; copypw: lcall bgetchar movx @dptr,a inc dptr jnz copypw ret ;--------------------------------------------------------------------------- ; Function: checkpw ; ; Description: ; This function checks that the password currently in the input buffer ; matches a stored one. ; ; Inputs: DPTR - pointer to stored passsword. ; ; Outputs: A - 0: Passwords matched ; FFH: Passwords did not match. ; checkpw: lcall bgetchar mov r0,a movx a,@dptr cjne a,0,failpw inc dptr jnz checkpw ret failpw: mov a,#0ffh ret ;--------------------------------------------------------------------------- ; Function: initpw ; ; Description: ; This function prompts for the initial values of both passwords, and ; stores them. ; ; Inputs: None ; ; Outputs: None ; ; Get the maintenance password. Prompt for verification and ; repeat until the same password is entered twice. initpw: mov dptr,#superpassmsg lcall prtstr lcall getpassword mov dptr,#superpwd lcall copypw mov dptr,#reentermsg lcall prtstr lcall getpassword mov dptr,#superpwd lcall checkpw jz super_ok mov dptr,#nomatchmsg lcall prtstr sjmp initpw ; Get the restricted mode escape password the same way. super_ok: mov dptr,#userpassmsg lcall prtstr lcall getpassword mov dptr,#userpwd lcall copypw mov dptr,#reentermsg lcall prtstr lcall getpassword mov dptr,#userpwd lcall checkpw jz user_ok mov dptr,#nomatchmsg lcall prtstr sjmp super_ok user_ok: ret ;--------------------------------------------------------------------------- ; Function: restrict_cmd ; ; Description: ; This function implements the "restrict" command. It drops from whatever ; access level is currently set to "restricted". ; ; Inputs: None ; ; Outputs: restrictflag is set. ; restrict_cmd: clr maintflag setb restrictflag mov dptr,#restrictmsg lcall prtstr ljmp prompt ;--------------------------------------------------------------------------- ; Function: normal_cmd ; ; Description: ; This function implements the "normal" command. If the current access ; level is "restricted", it prompts for and verifies the restricted mode ; escape password. ; ; Inputs: None ; ; Outputs: restrictflag and maintflag both reset if successful. ; normal_cmd: jnb restrictflag,normal_ok ; Access level is restricted, so check password. mov dptr,#passmsg lcall prtstr lcall getpassword jb byeflag,goodbye mov dptr,#userpwd lcall checkpw jz normal_ok ; Password was incorrect, print message and exit. sorry: mov dptr,#sorrymsg lcall prtstr ljmp prompt ; Password OK or not in restricted level - go to normal level. normal_ok: clr maintflag clr restrictflag ljmp prompt goodbye: ljmp bye ;--------------------------------------------------------------------------- ; Function: maint_cmd ; ; Description: ; This function implements the "maint" command. Unless the access level ; is already "maintenance", it prompts for the maintenance password. ; ; Inputs: None ; ; Outputs: maintflag set and restrictflag reset if successful. ; maint_cmd: jb maintflag,maint_ret ; Ask for and verify password. mov dptr,#passmsg lcall prtstr lcall getpassword jb byeflag,goodbye mov dptr,#superpwd lcall checkpw jnz sorry ; Password OK, so set flags. setb maintflag clr restrictflag maint_ret: ljmp prompt ;--------------------------------------------------------------------------- ; Functions: checkmaint, checknorm ; ; Description: ; These functions check that the access level is "maintenance", or at ; least "normal", respectively. If it is not, they print an error ; message and return a fail indication. ; ; Inputs: None ; ; Outputs: A - 0: Access level is high enough. ; FFH: Access level is too low. ; checkmaint: clr a jnb maintflag,fail ret checknorm: clr a jnb restrictflag,cn_ret fail: mov dptr,#authmsg lcall prtstr mov a,#0ffh cn_ret: ret ; Password and access level related strings ; ----------------------------------------- passmsg: db 'Enter password: ',0 sorrymsg: db 'Incorrect password.',13,10,0 superpassmsg: db 13,10,'Enter maintenance password: ',0 userpassmsg: db 13,10,'Enter restricted mode password: ',0 reentermsg: db 'Enter again to verify: ',0 nomatchmsg: db 'Passwords did not match, try again.',13,10,0 restrictmsg: db 'RESTRICTED MODE',13,10,0 authmsg: db 'Not authorized.',13,10,0 end