10 REM > BBCHost
   20 
   30 ESC%=&9B
   40 TxStatus=&FEED:TxRdy=&10:TxData=&FEE0:TxSetup=&FEE2:TxInit=&FF:RxStop=&00
   50 RxStatus=&FEED:RxRdy=&02:RxData=&FEE1:RxSetup=&FEEC:RxInit=&AA:RxCont=&00
   60 :
   70 CLS:DIM ctrl% 31, string% 255
   80 REPEAT A%=?RxData:UNTIL (?RxStatus AND RxRdy)=0 OR ?RxStatus>&7F
   90 ?TxSetup=TxInit:?RxSetup=RxInit :REM Reset I/O system and client
  100 ON ERROR PROC_ERROR:IF ERR=17:IF INKEY-1:PRINT'"Stopped":END
  110 X%=ctrl%:Y%=X% DIV 256
  120 REPEAT A%=FNRdByte:IF A%:VDU A% :REM Display startup banner
  130 UNTIL A%=0:PROCWrByte(&7F)      :REM Ack=NoExec
  140 REPEAT:VDU FNRdByte:UNTIL FALSE :REM Main VDU loop
  150 END
  160 :
  170 DEFPROCWrCmd(A%)
  180 REPEAT UNTIL (?TxStatus AND TxRdy):?TxData=ESC%
  190 REPEAT UNTIL (?TxStatus AND TxRdy):?TxData=A%:ENDPROC
  200 DEFPROCWrBlock(N%):IF N%=0:ENDPROC
  210 FOR D%=N%-1 TO 0 STEP -1:PROCWrByte(ctrl%?D%):NEXT:ENDPROC
  220 DEFPROCRdBlock(N%):IF N%=0:ENDPROC
  230 FOR D%=N%-1 TO 0 STEP -1:ctrl%?D%=FNRdByte:NEXT:ENDPROC
  240 DEFPROCWrString:D%=0:REPEAT:B%=string%?D%:PROCWrByte(B%):D%=D%+1:UNTILB%=13:ENDPROC
  250 DEFPROCRdString:D%=0:REPEAT:B%=FNRdByte:string%?D%=B%:D%=D%+1:UNTILB%=13:ENDPROC
  260 DEFPROCWrByte(A%)
  270 REPEAT UNTIL (?TxStatus AND TxRdy):?TxData=A%:IF A%<>ESC%:ENDPROC
  280 REPEAT UNTIL (?TxStatus AND TxRdy):?TxData=A%:ENDPROC
  290 DEFFNRdByte
  300 REPEAT:REPEAT UNTIL (?RxStatus AND RxRdy):A%=?RxData
  310   IF A%=ESC%:REPEAT UNTIL (?RxStatus AND RxRdy):A%=?RxData:IF A%<>ESC%:A%=EVAL("FN_"+STR$~(A%AND&1E)):A%=-1
  320 UNTIL A%>=0:=A%
  330 :
  340 DEFFN_0:PROCEscOff:A%=GET:PROCEscOn:PROCWrByte((A%=27)AND&80):PROCWrByte(A%):=-1
  350 DEFFN_2:PROCRdString:OSCLI$string%:IFFNuc(LEFT$($string%,4))="HELP":IFstring%?4<64:PRINT'"Serial TUBE"
  360 PROCWrByte(&7F):=-1
  370 DEFFN_4:X%=FNRdByte:A%=FNRdByte:A%=((USR&FFF4)AND&FF00)DIV256:X%=ctrl%:PROCWrByte(A%):=-1
  380 DEFFN_6:X%=FNRdByte:Y%=FNRdByte:A%=FNRdByte:A%=((USR&FFF4)AND&1FFFF00)DIV256
  390 X%=ctrl%:Y%=X%DIV256:PROCWrByte((A%AND&10000)DIV512):PROCWrByte((A%AND&FF00)DIV256):PROCWrByte(A%):=-1
  400 DEFFN_8:A%=FNRdByte:inlen%=FNRdByte:PROCRdBlock(inlen%):outlen%=FNRdByte:CALL &FFF1:PROCWrBlock(outlen%):=-1
  410 DEFFN_A:PROCRdBlock(5):INPUTLINE""$string%:PROCWrByte(&7F):PROCWrString:=-1
  420 DEFFN_C:Y%=FNRdByte:PROCRdBlock(4):A%=FNRdByte
  430 X%=&70:!X%=!ctrl%:A%=USR&FFDA:!ctrl%=!X%:X%=ctrl%:PROCWrByte(A%):PROCWrBlock(4):=-1
  440 DEFFN_E:Y%=FNRdByte:A%=USR&FFD7:Y%=X%DIV256:PROCWrByte((A%AND&1000000)DIV&20000):PROCWrByte(A%):=-1
  450 DEFFN_10:BPUT#FNRdByte,FNRdByte:PROCWrByte(&7F):=-1
  460 DEFFN_12:A%=FNRdByte:IFA%=0:CLOSE#FNRdByte:=-1
  470 PROCRdString:X%=string%:Y%=X%DIV256:A%=USR&FFCE:X%=ctrl%:Y%=X%DIV256:PROCWrByte(A%):=-1
  480 DEFFN_14:PROCRdBlock(16):PROCRdString:A%=FNRdByte
  490 REM Manually do OSFILE call
  500 PROCWrByte(A%):PROCWrBlock(16):=-1
  510 DEFFN_16:PROCRdBlock(13):A%=FNRdByte
  520 REM Manually do OSGBPB call
  530 PROCWrBlock(13):PROCWrByte((A%AND&100)DIV2):PROCWrByte(A%):=-1
  540 DEFFN_18:X%=FNRdByte:H%=FNRdByte:L%=FNRdByte
  550 IF A%>127 OR A%<2 OR A%=6 OR A%=7 OR A%=8:PROCWrByte(&FF):PROCWrByte(H%):PROCWrByte(L%):=-1
  560 PROCWrByte(&7F):PROCRdString
  570 REM Manually do OSFSC call
  580 IF A%>=0:PROCWrByte(A%)
  590 =-1
  600 DEFFN_1A:=-1
  610 DEFFN_1C:=-1
  620 DEFFN_1E:PROCWrByte(0):=-1
  630 :
  640 DEFPROC_ERROR
  650 A%=-1:REPEAT:A%=A%+1:string%?A%=?(A%+!&FD+1):UNTILstring%?A%=0:A%=ERR:IFA%=28:A%=253:$string%="Bad address"+CHR$0
  660 PROCWrCmd(&00):PROCWrByte(A%):A%=-1:REPEAT:A%=A%+1:PROCWrByte(string%?A%):UNTILstring%?A%=0:ENDPROC
  670 :
  680 DEFPROCEscOff:OSCLI"FX229":ENDPROC
  690 DEFPROCEscOn:OSCLI"FX229,1":ENDPROC
  700 :
  710 DEFFNs(A$):IFLEFT$(A$,1)=" ":REPEATA$=MID$(A$,2):UNTILLEFT$(A$,1)<>" "
  720 IFRIGHT$(A$,1)=" ":REPEATA$=LEFT$(A$,LENA$-1):UNTILRIGHT$(A$,1)<>" "
  730 =A$
  740 DEFFNuc(A$):LOCAL B$:IFA$="":=""
  750 REPEATB$=B$+CHR$(ASCA$AND((A$<"@")OR&DF)):A$=MID$(A$,2):UNTILA$="":=B$