.title KRTCON Terminal emulator .ident "V03.62" ; /62/ 27-Jul-93 Billy Youdelman ; ; correct comments to indicate r3 is not preserved between tasks ; fixed error handling for suspend/resume CONSOLE logging ; added handling for logfile errors ; move senbrk here ; speed up keyboard input processing at high data rates ; /BBS/ 1-Dec-91 Billy Youdelman V03.61 ; ; this module has been extensively modified and will now run fine ; under any monitor including SJ if it's built with timer support ; ; pulled RT-11 multi-terminal and sj monitor w/o twait stuff.. ; ; set/reset a list of "activation" chars under TSX which ; allows non-printing chars input at the terminal, such as ^O, ; to be passed to the remote system during the connect mode ; ; display handler speed (fixed for 19.2k too) when connecting ; display escape sequence when entering CONNECT ; disallow typing TSX lead-in char to TT when running under TSX ; allow suppression of sign-on text, for use with krttra ; skip TT input routine once done flag is set ; tt input now uses con8bit ala TT output ; added MILNET option to wakeup (XON) MILNET TACs ; added send a control char via esc_char "^x" ala VTCOM ; added esc_char "Z" command to hose/refresh handler ; Copyright 1986 Change Software, Inc ; ; 07-MAY-1986 10:55 Brian Nelson .include "IN:KRTMAC.MAC" .iif ndf KRTINC .error <; .include for IN:KRTMAC.MAC failed> .mcall .CMKT ,.MRKT ,.RSUM ,.SCCA ,.SPFUN .mcall .SPND ,.TTINR ,.TTOUTR,.TWAIT ,.WRITC BRKDRV = 202 ; /62/ wc=0 ends break, else begin it STSDRV = 204 ; low byte status, high byte version $XLV51 = 16. ; RT-11 V5.1 XL/XC version number .macro beep mov #bell ,r0 ; load a bell .ttoutr ; try to beep, but don't wait for it.. .endm beep .macro schedule taskheader mov r0 ,-(sp) ; this is a completion routine mov taskheader,r0 ; top of task's entry in scheduler mov sp ,state(r0) ; flag task is now ready to run mov (sp)+ ,r0 .endm schedule .sbttl Local buffers .psect condat ,rw,d,lcl,rel,con brkwrk: .word 0 ,0 ,0 ,0 ; /62/ break mark time work area cancel: .word 0 ,0 ,0 ,0 ; .cmkt work area crflag: .word 0 ; if <> last char was a CR done: .word 0 ; set this <> to exit scheduler iopend: .word 0 ; if <> XL write completion is pending rmbuff: .word 0 ; one word buffer for writes to XL rt.v51: .word 0 ; if <> XL is from RT-11 V5.1 scca: .word 0 ,0 ,0 ; trap ^C here short: .word 0 ,1 ; wait one tick stsmark:.word 0 ,0 ,0 ,0 ; status watcher mark time work area ttmark: .word 0 ,0 ,0 ,0 ; ttdone mark time work area twait: .word 0 ,0 ; .twait work area xkmark: .word 0 ,0 ,0 ,0 ; xktime mark time work area xkwork: .word 0 ,0 ,0 ,0 ,0 ,0 ; writes to handler work area .sbttl Task scheduler data table ; these are NOT saved and may be used only within the then active task ; r0 = scratch ; r1 = scratch ; r2 = scratch ; r3 = not currently in use ; /62/ ; this register is preserved between tasks ; r4 = one word TT input buffer ; r5 = pointer to CURRENT task's entry in table TASKADDR = 0 ; task's starting address STATE = 2 ; if <> run this task next time thru ; taskaddr state ; /62/ rmhead MUST follow tthead in tlist: ; /62/ this table, see note in rmproc xkhead::.word xkproc ,0 ; XL data out to TT tthead: .word ttproc ,0 ; get TT input rmhead: .word rmproc ,0 ; send it to XL sthead: .word stproc ,0 ; check XL status .word 0 ; terminate table hdsize = tthead - xkhead ; each entry is this long ; marktime intervals .psect $pdata ststime:.word 0 ,0 ; /62/ init puts 0.5 sec in ticks here ttwait: .word 0 ,3 ; poll TT for input every 3 ticks xktime: .word 0 ,2 ; wait to clear stuffed output buffer .psect $code .sbttl Initialization .enabl lsb doconn::tst linksts ; link already open? bne 10$ ; ya, no need to init calls ttyini ,<#0> ; open the link device tst r0 ; ok? beq 10$ ; ya return ; nope, bail out 10$: .scca #scca ,#scca+4 ; kill ^C, this is reset by setcc .cmkt #cancel ,#40 ; then dump setcc's mark timer calls t.ttyini,<#-1> ; init terminal (w/flag for ^W) tst conmsg ; display sign-on text? bne 29$ ; nope.. message wrtall #ttname ; spell out the device name message < DTE speed: > ; "DTE" as path speed may be different call ttspeed ; get speed tst r0 ; wuz it gettable? bne 21$ ; /62/ yup.. message ; nope br 22$ ; continue 21$: call L10266 ; write speed in r0 as dec num to TT 22$: .newline message mov conesc ,r0 ; get esc char dec r0 ; lis.ct here has no null entry movb lis.ct(r0),r0 ; make it printable call writ1ch ; write it to TT message ,cr 29$: clr conmsg ; reset sign-on bypass flag mov sp ,logini ; /62/ force logerr msg into the clear clr r4 ; init TT input buffer tst milnet ; MILNET mode on? beq 40$ ; no mov #xon+,r4 ; ya, stuff a couple XONs for remote 40$: .spfun #rtwork,#xc.control,#stsdrv,#xcsts,#0,#1 ; /62/ get status clr rt.v51 ; init version flag tst tsxcl ; CL? bne 50$ ; ya, skip this tst km.lock ; /62/ if it's KM do it here which bne 49$ ; /62/ keeps handler smaller.. cmpb xcsts+1 ,#$xlv51 ; does this ver of XL eat LF after CR? bgt 50$ ; ya 49$: inc rt.v51 ; no, flag it has to be done here 50$: mov clkflg ,r0 ; /62/ get number of ticks/second asr r0 ; /62/ number of ticks in 1/2 second mov r0 ,ststime+2 ; /62/ stuff into status check timer mov #tlist ,r0 ; init flags for each task 52$: tst (r0) ; end of the list? beq 57$ ; ya mov sp ,state(r0) ; no, run each task to init itself add #hdsize ,r0 ; bump to head of next task br 52$ ; and loop back for it 57$: clr crflag ; no CR received from TT yet clr done ; definitely not done mov #1 ,suspnd ; don't miss a .rsum in the init pass mov sp ,xk.con ; direct data read from handler here tstb @xkpoint ; anything unused in buffer? bne 70$ ; ya call readxk ; get data or set completion routine .sbttl CONNECT main_loop 70$: mov #tlist ,r5 ; get top of the task list 73$: tst (r5) ; end of the table now? beq 79$ ; ya, go away until something happens tst state(r5) ; runnable task? beq 77$ ; no jsr pc ,@(r5) ; ya, do it 77$: add #hdsize ,r5 ; next task control block please br 73$ ; loop back for it 79$: inc suspnd ; flag a .rsum is needed .spnd ; suspend ourself tst done ; time to go now? beq 70$ ; no, loop again .sbttl Shut_down and exit clr xk.con ; send completed reads data to binread .cmkt #cancel ,#0 ; kill all marktime requests call ttyrst ; reset some terminal parameters call ttyfin ; drop the handler clr linksts ; flag link is closed .newline ; ensure exit is to a clean line clr logini ; /62/ indicate cursor on a clean line return .dsabl lsb .sbttl Scheduler's mark time completion routines stsdone:mov r0 ,-(sp) ; don't alter r0 in completion routine mov #sthead ,r0 ; make the status test runnable br S1$ xkredo: mov r0 ,-(sp) mov #xkhead ,r0 ; retry terminal output, buff was full br S1$ ttdone: tst done ; finished? bne S10$ ; ya, skip all this.. mov r0 ,-(sp) ; no, mov #tthead ,r0 ; go poll TT for possible input S1$: mov sp ,state(r0) ; flag task is now ready to run mov (sp)+ ,r0 ; restore r0 rerun: tst suspnd ; need to resume? /62/ add rerun ept beq S10$ ; nope.. dec suspnd ; ya, make sure no one else does it .rsum ; get scheduler going S10$: return .sbttl Process TT input ttproc: tst done ; finished? bne 101$ ; ya, don't eat possible type ahead.. tst r4 ; previous input queued to send yet? bne 101$ ; no, loop until it has been 1$: .ttinr ; check for input waiting for term bcs 90$ ; nothing to do tst con8bit ; SET CON 8? bne 3$ ; ya bic #^c177 ,r0 ; no, strip any parity present 3$: cmpb r0 ,conesc ; escape sequence? bne 50$ ; no, dump character as is mov #5 ,r1 ; ya, wait up to five seconds mul clkflg ,r1 ; for the next char 10$: .ttinr ; try to get the next char bcc 30$ ; got something valid .twait #twait ,#short ; nothing, wait one tick sob r1 ,10$ ; and try again br 90$ ; exit as we did not get anything tst con8bit ; SET CON 8? bne 32$ ; ya 30$: bic #^c177 ,r0 ; strip junk from the character 32$: cmpb r0 ,conesc ; another escape character? beq 50$ ; yes, dump that character as is call concmd ; console command processor br 90$ ; if n.g. concmd will beep 50$: bit #2 ,xcsts ; /62/ remote asserted flow control? beq 51$ ; no save ; /62/ ya, save the input byte beep ; beep & continue, _OVERWRITING_ data unsave ; /62/ by restoring input byte and clr r4 ; /62/ ensuring it's bit settable here 51$: tst tsxsav ; running under TSX? bne 60$ ; ya, skip LF processing.. tst rt.v51 ; is this OLD XL/XC from RT-11 V5.1? beq 60$ ; no asr crflag ; ya, see if a CR precedes a LF bcc 55$ ; last char was not a CR cmpb r0 ,#lf ; ignore LINE FEEDs please, but only beq 1$ ; when they follow a CR, that is.. 55$: cmpb r0 ,#cr ; is this a CR? bne 60$ ; no inc crflag ; yes, flag for next pass 60$: tst duplex ; need local echoing? beq 70$ ; no tst tsxsav ; TSX? beq 65$ ; no cmpb r0 ,m.tsxr ; is it TSX lead-in char? beq 70$ ; ya, don't type this to TT 65$: .ttoutr ; echo the character 70$: setpar r0 ,r0 ; set parity if enabled tstb r4 ; is this byte free? bne 73$ ; no, use the hi byte for this char bisb r0 ,r4 ; ya, stuff the char in schedule #rmhead ; enable the send char via XL task br 1$ ; and try for one more input byte 73$: swab r4 ; swap bytes to bisb r0 ,r4 ; stuff second char into the hi one swab r4 ; bytes back into proper positions return ; waste no time, every inst counts.. 90$: clr state(r5) ; don't come back right away .mrkt #ttmark,#ttwait,#ttdone,#3 ; sched another try for TT input 101$: return .sbttl Send data from XL to TT xkproc: clr r0 ; avoid sign extension bisb @xkpoint,r0 ; get next char beq 240$ ; nothing left.. tst con8bit ; SET CON 7 or 8? bne 215$ ; 8 bicb #200 ,r0 ; 7, strip high bit 215$: tst tsxsav ; TSX? beq 217$ ; no cmpb r0 ,m.tsxr ; lead-in char? beq 218$ ; ya, don't type this to TT 217$: .ttoutr ; dump the char bcs 220$ ; buffer full, go wait a bit 218$: bit #log$co ,trace ; logging enabled? beq 219$ ; no mov #lun.lo ,r1 ; log file chan, char is still in r0 call putcr0 ; that's it folks tst r0 ; /62/ did it work? beq 219$ ; /62/ ya save ; /62/ no, save error code beep ; /62/ call attention to this! unsave ; /62/ recover error code call logerr ; /62/ handle the error 219$: inc xkpoint ; bump to next byte br xkproc ; loop for it 220$: .mrkt #xkmark,#xktime,#xkredo,#13 ; output ring buffer is FULL clr state(r5) ; wait for mark time to expire return 240$: clr state(r5) ; no longer runnable call readxk ; get more data from XL return .sbttl Write one word from TT input to XL rmproc: tst iopending ; we still waiting for XL? bne 90$ ; /62/ ya, don't wait too long.. mov r4 ,rmbuff ; copy the data beq 100$ ; nothing to do clr r4 ; make TT input buffer available again mov sp ,iopending ; flag I/O is not yet completed .writc #xkwork,#lun.xk,#rmbuff,#1,#200$,#1 ; queue the write 90$: jmp rerun ; /62/ check for more, rerun ttproc 100$: clr state(r5) ; done, no longer runnable return .sbttl XL write completion routine 200$: clr iopending ; I/O no longer pending return .sbttl Status_watcher .enabl lsb stproc: mov xcsts ,r2 ; /62/ save prior status .spfun #rtwork,#xc.control,#stsdrv,#xcsts,#0,#1 ; /62/ present status bcs 100$ ; failed mov xcsts ,r1 ; /62/ copy of current status tst tsxcl ; which handler is it? bne 1$ ; CL uses bit 2 asr r1 ; KM, XC and XL use bit 3 asr r2 ; make it 2 here 1$: bic #^c4 ,r2 ; recover the carrier bic #^c4 ,r1 ; detect bits cmp r1 ,r2 ; any change? beq 100$ ; no beep ; ya, make a small noise message <%KRTCON-W-Carrier > tst r1 ; did we loose it? bne 10$ ; no, must have just gotten it message call ttxon ; clear the driver just in case br 20$ 10$: message 20$: .newline 100$: clr state(r5) ; no longer runnable .mrkt #stsmark,#ststime,#stsdone,#7 ; reschedule us return .dsabl lsb .sbttl Internal command processor .enabl lsb concmd: call strip0 ; /62/ strip parity, upcase if alpha scan r0 ,#200$ ; look for a match asl r0 ; word offsets jmp @210$(r0) ; /62/ dispatch to the correct routine .save .psect $pdata ; /62/ pull lower case stuff.. 200$: .byte '? ,'B&137 ,'C&137 ,'H&137 ,'I&137 ,'Q&137 ,'R&137 .byte 'X&137 ,'Z&137 ,'^ ,177 .byte 0 .even 210$: .word con.$ .word con.hl ,con.br ,con.c ,con.hl ,con.i ,con.q ,con.r .word con.x ,con.z ,con.ctr,con.br .restore .dsabl lsb con.$: beep ; bad command, ring the bell return con.c: mov sp ,done ; set flag to exit the emulator return con.i: jmp ttyhang ; /62/ go toggle DTR con.q: bit #log$op ,trace ; /62/ file open? beq con.$ ; /62/ no, go make a beep bic #log$co ,trace ; turn off console logging return con.r: bit #log$op ,trace ; file open? beq con.$ ; /62/ no, go make a beep bis #log$co ,trace ; yes, resume console logging return con.z: call hose ; zap handler, then con.x: jmp ttxon ; /62/ reset XOFF and send an XON con.br: .spfun #rtwork,#xc.control,#brkdrv,#0,#1,#1 ; /62/ turn break on .mrkt #brkwrk,#break,#20$,#20 ; /62/ queue this to turn it off return 20$: save ; /62/ this is a completion routine .spfun #rtwork,#xc.control,#brkdrv,#0,#0,#1 ; /62/ turn break off unsave return con.hl: wrtall #hlptxt ; dump help text to terminal return .save .psect $pdata hlptxt: .ascii .ascii "B Send a break" .ascii "C Connect back to the local Kermit-11" .ascii "I Drop DTR for 0.5sec (hang up) then restore it" .ascii "Q Suspend CONSOLE logging" .ascii "R Resume CONSOLE logging" .ascii "X Flow control reset" .ascii "Z Zap (100% hose & try to unhang) the handler" .ascii '^x Send control char "x" using A..Z[\]~?' .ascii "RUBOUT Send a break" .byte ,0 .even .restore .sbttl Send a control char ala VTCOM's ^x command con.ctrl:mov #5 ,r1 ; wait five seconds mul clkflg ,r1 ; for the next char 10$: .ttinr ; get possible ctrl character bcc 21$ ; got something valid .twait #twait ,#short ; nothing, wait one tick sob r1 ,10$ ; next please br 100$ ; exit as we did not get any data 21$: call strip0 ; /62/ strip parity, upcase if alpha scan r0 ,#lis.ctrl ; a control char symbol? tst r0 bne 30$ ; ya beep ; no, beep for a n.g. char br 100$ 30$: setpar r0 ,r0 ; set parity if enabled tstb r4 ; is this byte free? bne 73$ ; no bisb r0 ,r4 ; ya, stuff the char in br 90$ ; and try for another one 73$: swab r4 ; swap bytes to bisb r0 ,r4 ; stuff second char into the hi one swab r4 ; bytes back into proper positions 90$: schedule #rmhead ; dump the data down the line 100$: return .save .psect $pdata lis.ct: .asciz "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]~?" .even .restore .sbttl Strip parity and upcase ; /62/ moved this here, now shared.. strip0: bic #^c177 ,r0 ; strip parity cmp r0 ,#'a!40 ; convert blo 23$ ; char cmp r0 ,#'z!40 ; to bhi 23$ ; upper bic #40 ,r0 ; case 23$: return .end