; M4MIT/ASM ; ORG 6000H ; ; Model 4(p) KERMIT by Gregg Wonderly ; ; Version 5.2 ; ; Version 5.2 adds wild card send capabilities as well as fixes ; to bugs. M4CHGS/ASM contains a list of the changes made between ; version 5.0, and 5.2. ; ; This version is a radically modified and rewritten version ; of the original TRS-80 KERMIT done by Stan Barber. It has ; numerous features and capabilities beyond that version due ; to differences between the Model 3 and 4. ; ; Get the macro definitions first ; *GET M4EQU *GET M4MAC ; ; Entry point for execution ; START LD (OLDSP),SP ;Save the current stack pointer for later LD SP,STACK ;Set up the stack to our area CALL XFLAGS ;Get the flags address in IY LD (FLAGS),IY ;Save the flags for later LD HL,SWTBUF ;Clear initial connect screen buffer LD DE,SWTBUF+1 LD BC,1920 ;Byte counter LD (HL),' ' ;Clear the first character LDIR ;Copy it to the next LD B,1 ;Move low memory up above our code. LD HL,0 ;Select GET option of @HIGH$ CALL XHIGH ;Get the current LOW$ JP NZ,BADMEM ;Quit on an error LD (OLDLOW),HL ;Save for restore on exit LD HL,TOPMEM ;Get the last address used CALL XHIGH ;Store it as the new LOW$ JP NZ,BADMEM ;Quit on an error LD E,'C' ;Look for the *CL DCB LD D,'L' CALL XGTDCB ;The address comes back in HL LD (CLDCB),HL ;Save the address (May be wrong) JR NZ,NOCL ;Now check for error... LD E,'S' ;Look for the *SI DCB LD D,'I' CALL XGTDCB ;The address comes back in HL LD (TMIDCB),HL ;Store the result JR NZ,NOSI ;Skip if NOT found or other error LD E,'S' ;Look for the *SO DCB LD D,'O' CALL XGTDCB ;The address comes back in HL LD (TMODCB),HL ;Save the address JR NZ,NOSO ;Jump if NOT found or other error CALL SETINT ;Set up interupt receiver etc XOR A ;ZERO A LD (FCB),A ;SET FILE CLOSED FLAG CALL CMBLNK ;CLEAR THE SCREEN STROUT INTRO ;Print the intro message CALL CHKTAK ;Check if there is a KERMIT/INI file CALL KERMIT ;Start accepting commands. JP EXIT1 ;If control returns, then exit ; ; Error messages printed when devices can not be found or allocated ; NOCL LD DE,CFCL ;Error message (Can't find *CL DCB) PRTOOPS CALL PRTSTR ;Print an OOPS message, and quit JP EXIT2 ;Finish cleaning up ; ; No DCB for the SI device was found ; NOSI LD DE,CFSI ;Get the message JR PRTOOPS ;Go print it ; ; No DCB for the SO device was found ; NOSO LD DE,CFSO ;Get the message JR PRTOOPS ;Go print it ; ; Bad return code from @HIGH$ call ; BADMEM CALL XERROR0 ;Print a system error message STROUT NOMEM ;Print the message JP XEXIT ;Exit to TRSDOS ; ; CLEAR THE SCREEN, SAVING DE ; CMBLNK PUSH DE ;Save DE STROUT CLRTOP ;Clear the screen POP DE ;Restore DE QUIT RET ;Just a simple return for QUIT ; ; KERMIT command processor ; This is where each command originates. ; KERMIT LD SP,STACK ;Set the stack back LD DE,FCB ;Always close an open file LD A,(DE) ;Get the flags byte BIT 7,A ;Is the file still open? CALL NZ,XCLOSE ;Close it if it is LD DE,KERM ;Get the prompt CALL PROMPT ;Display it, and set up the parser LD DE,COMTAB ;Get the primary command table LD A,CMKEY ;Parse a keyword CALL COMND ;Get a command or ERROR JP KERMT2 ;Abort on ERROR LD HL,KERMIT ;Put on a return address for the PUSH HL ;FINISH, LOGOUT, and BYE commands. PUSH HL LD HL,KERMTB ;Get the JUMP table for these commands LD C,A ;Make BC = A extended to 16 bits LD B,0 ;high byte is zero, (unsigned) ADD HL,BC ;Calculate the effective address JP (HL) ;Jump into the jump table ; ; Jump table for primary commands ; KERMTB JP REMOTE ;REMOTE JP EXIT ;EXIT JP CONNECT ;CONNECT JP LOG ;LOG JP READ ;RECEIVE JP SEND ;SEND JP SETCOM ;SET JP SHOW ;SHOW JP STATUS ;STATUS JP FINISH ;FINISH JP LOGOUT ;LOGOUT JP BYE ;BYE JP DIR ;DIRECTORY JP ERA ;KILL JP LOCCOM ;LOCAL JP SETCL ;SETCOM JP TAKE ;TAKE JP INPUT ;INPUT JP OUTPUT ;OUTPUT JP PAUSE ;PAUSE JP PULSE ;PULSE JP CLEARC ;CLEAR JP CLSFLS ;CLOSE JP ECHO ;Type text to screen ; ; Echo text to screen ; ECHO EQU $ LD A,CMTXT ;Get some text LD DE,DATA ;Where to put it PUSH DE ;Save for printing CALL COMND ;Parse it JP KERMT3 ;Jump on error POP HL ;Get the start LD C,A ;Make BC the length that is in A LD B,0 ADD HL,BC ;Move to EOS position LD (HL),EOS ;Put it in place CALL NEWLIN ;Get a new line STROUT DATA ;Print the string JP KERMIT ;Get a new command ; ; CLEAR command. Services CLEAR INPUT-PORT, and CLEAR SCREEN ; CLEARC LD A,CMKEY ;GET A KEYWORD LD DE,CLRTAB ;FROM THIS TABLE CALL COMND JP KERMT2 ;SAY UNRECOGNIZED COMMAND ON AN ERROR LD (TEMP1),A ;SAVE THE RETURNED VALUE LD A,CMCFM CALL COMND JP KERMT3 LD A,(TEMP1) LD C,A IFNZ CLR010 CALL CLRPRT ;DO "CLEAR INPUT-PORT" JP KERMIT ;GET A NEW COMMAND CLR010 CP 3 ;IS IT CLEAR SCREEN? JP NZ,KERMT2 ;SAY UNRECOGNIZED COMMAND IT NOT CALL CMBLNK ;CLEAR THE SCREEN JP KERMIT ;GET A NEW COMMAND ; ; TAKE commands from a file. This is basically a HACK that ; initializes some values so that GETSTR reads from the file, ; instead of the keyboard, until EOF is found. ; TAKE LD DE,TFCB ;WHERE TO PUT THE FILENAME LD A,CMIFI ;GET A FILE NAME CALL COMND ;GET USER INPUT JP KERMT3 ;ABORT ON AN ERROR OR A JP Z,KERMT3 ;Abort if no name given LD IY,(FLAGS) ;GET THE SYSTEM FLAGS SET 0,(IY+18) ;SET UP FOR NO FILE OPEN BIT LD HL,TBUF ;THIS IS THE DATA BUFFER LD DE,TFCB ;GET THE FILE FCB LD B,0 ;256 BYTE LRL CALL XOPEN ;TRY TO OPEN THE FILE JR NZ,TERROR ;GO REPORT AN ERROR LD A,1 LD (TAKFLG),A ;SET THE FLAG JP KERMIT TERROR CALL XERROR0 ;PRINT THE MESSAGE XOR A ;RESET THE TAKE FLAG LD (TAKFLG),A JP KERMIT ;GET A NEW COMMAND ; ; SETCOM command. We use the TRSDOS SETCOM command here, as it ; saves lots of time and trouble. ; SETCL LD A,CMTXT ;GET ARBITRARY TEXT LD DE,CLBUF ;BUFFER TO PUT DATA INTO CALL COMND ;GET THE INPUT JP KERMT3 ;ABORT ON ERROR CALL NEWLIN ;NEED A NEW LINE TO PRINT ON LD A,CR ;Get the EOL character LD (DE),A ;Put in the terminator LD HL,CLBUF-7 ;Get the 'SETCOM ' prefix CALL XCMNDR ;Let TRSDOS do it for us JP KERMIT ;Get a new command, ignoring any errors ; ; LOCAL command. Use @CMNDR to execute a TRSDOS command ; LOCCOM LD HL,(CMDPTR) ;GET THE ADDRESS OF THE START SYST1 LD A,(HL) ;GET A CHARACTER INC HL ;POINT TO THE NEXT IFA ' ',SYST1 ;Loop if just a blank IFA CR,SYST2 ;Do a LIB command if no text given IFANOT '?',SYST4 ;Go if user not asking for HELP SYST2 PUSH HL ;SAVE THE ADDRESS TO PASS POP IY ;GET A THE ADDRESS IN AN INDEX LD (IY-1),'L' ;HL GO INCREMENTED UP THERE LD (IY),'I' ;SPELLING OUT LIB LD (IY+1),'B' LD (IY+2),CR ;ADD THE TERMINATOR SYST4 DEC HL ;POINT TO THE ACTUAL ADDRESS CALL NEWLIN ;NEED A NEW LINE ; ; Remove the comments below to force LOCAL to process only library ; commands ; ; LD IY,(FLAGS) ;Get the Flags pointer ; SET 4,(IY+2) ;Only library commands are allowed CALL XCMNDR ;Do a system command SYST5 JP KERMIT ;IGNORE ANY ERRORS ; ; Print UNRECOGNIZED COMMAND message ; KERMT2 STROUT ERMES1 ;Issue the message JP KERMIT ; ; Print NOT CONFIRMED message ; KERMT3 STROUT ERMES3 ;Issue the message JP KERMIT ; ; Exit to TRSDOS ; EXIT LD A,CMCFM ;Get a confirmation of the EXIT CALL COMND JP KERMT3 EXIT1 LD DE,FCB ;Check the file FCB, and close if needed LD A,(DE) ;Get the info byte BIT 7,A ;Check the file open BIT CALL NZ,XCLOSE ;Close it if needed ; ; Check the log files to make sure they are closed ; LD DE,LFCB ;Get the file FCB LD A,(LOGFLG) ;Check if logging active OR A ;Check the flags CALL NZ,XCLOSE ;Close the file if open LD DE,DFCB ;Check debugging LD A,(DEBLOG) ;Get the flag OR A CALL NZ,XCLOSE ;Close it if open LD DE,TFCB ;Get the FCB LD A,(TRANLOG) ;Get the flag OR A CALL NZ,XCLOSE ;Close it if open ; ; Now reset the interrupt vector for *CL. ; LD C,4 ;Interrupts option of the @CTL SVC LD IY,0 ;Reset the INTERRUPT vector of *CL LD DE,(CLDCB) ;Get the *CL DCB address CALL XCTL ;Use @CTL to do it CALL CMBLNK ;Clear the screen EXIT2 LD HL,(OLDLOW) ;Get the old low memory pointer LD B,1 ;Set B to indicate LOW$ CALL XHIGH ;Move the value back ; ; Now fill the *FO, and *FI devices DCB's with zeros. This ; will make the devices no longer available. ; LD HL,(FINDCB) ;Get the *FI DCB address CALL ZERO8 ;Fill it with zeroes LD HL,(FOTDCB) ;Do the same for *FO CALL ZERO8 ;Fill DCB with zeroes CALL STOPTIMER ;Stop the timer if still running LD SP,(OLDSP) ;Restore the old STACK pointer LD HL,0 ;Set OK exit LD IY,(FLAGS) ;If JCL active, then just return BIT 5,(IY+18) ;Check the BIT RET NZ ;Return if BIT is set JP XEXIT ;Exit via @EXIT ; ; Zero 8 bytes pointed to by HL ; ZERO8 LD B,8 ;Get the byte count ZERO8_1 LD (HL),0 ;Zap one byte INC HL ;Point to next DJNZ ZERO8_1 ;Loop until done RET ; ; CALL ERROR Prints the DATA area on a new line, and sets ; the state to ABORT. ; CALL ERROR1 Prints the DATA area on a new line. ; CALL ERROR2 Prints the DATA area on the same line ; CALL ERROR3 Prints the string pointed to by DE on a new line ; CALL ERRORD Prints a system error message corresponding to ; A, providing A is none zero. ; ERROR NSTATE 'A' ;Set the state to abort ; ERROR1 CALL NEWLIN ;Get a new line ; ERROR2 LD A,(ARGBLK+1) ;Get the length of the data LD C,A ;Put the length into BC LD B,0 LD HL,DATA ;Get the start of the DATA area PUSH HL ;Save it LD A,EOS ;Add EOS for printing CALL PUTTRN POP DE ;Get start back JP PRTSTR ;Print the string, and return ; ERROR3 PUSH DE ;Save the message CALL NEWLIN ;Get a new line POP DE ;Restore the message JP PRTSTR ;Print error message ; ERRORD OR A ;Display system error message RET Z ;IFF an error has occured JP XERROR0 ;Do system error ; ; Print the string in DE, followed by a new line ; FINMES CALL PRTSTR ;Print the message JP NEWLIN ;Get a newline and return ; ; The FINISH, BYE, and LOGOUT commands all need a return address ; on the stack. This is because the CHKTRYS routine will use it ; to abort the packet operations when MAXTRY retries are reached. ; ; This is the FINISH command. ; FINISH LD A,CMCFM CALL COMND ;GET A CONFIRM. JP KERMT3 CALL NEWLIN CALL CLRPRT ;CLEAR ANY STACKED NAKS XOR A ;DIDN'T GET A CONFIRM. LD (NUMTRY),A ;INITITIALIZE COUNT. LD A,'1' ;Set block check to single char LD (CURCHK),A ;. . . FINSH1 CALL CHKTRYS ;Check the retry threshold XOR A LD (ARGBLK),A ;MAKE IT PACKET NUMBER ZERO. LD A,1 LD (ARGBLK+1),A ;ONE PIECE OF DATA. LD HL,DATA LD (HL),'F' ;FINISH RUNNING KERMIT. LD A,'G' ;GENERIC COMMAND PACKET. CALL SPACK ;Send the packet JP FINSH1 ;On fail, try again CALL RPACK ;GET AN ACKNOWLEDGEMENT. JP FINSH1 ;On fail, try again CP 'Y' ;ACK? JP Z,KERMIT ;YES, WE ARE DONE. IFANOT 'E',FINSH2 ;Jump if not error packet CALL ERROR1 ;PRINT THE ERROR MESSAGE. JP KERMIT FINSH2 CP 'N' ;Is this a NAK? CALL NZ,CONOUT ;Output the packet type to term JR FINSH1 ;Resend the packet ; ; This is the LOGOUT command. ; LOGOUT LD A,CMCFM CALL COMND ;GET A CONFIRM. JP KERMT3 CALL NEWLIN CALL LOGO ;SEND THE LOGOUT PACKET. JP LOG111 ;GO GET ANOTHER COMMAND JP KERMIT ;WHETHER WE SUCCEED OR NOT. LOGO XOR A LD (NUMTRY),A ;INITITIALIZE COUNT. CALL CLRPRT ;CLEAR ANY STACKED NAKS LD A,'1' ;Block check type to single LD (CURCHK),A ;. . . LOGO1 CALL CHKTRYS ;Check retry threshold XOR A LD (ARGBLK),A ;MAKE IT PACKET NUMBER ZERO. LD A,1 LD (ARGBLK+1),A ;ONE PIECE OF DATA. LD HL,DATA LD (HL),'L' ;LOGOUT THE REMOTE HOST. LD A,'G' ;GENERIC COMMAND PACKET. CALL SPACK JP LOGO3 CALL RPACK ;GET AN ACKNOWLEDGEMENT JP LOGO1 CP 'Y' ;ACK? JP Z,RSKP ;YES, WE ARE DONE. CP 'E' ;IS IT AN ERROR PACKET? JP Z,ERROR1 ;Print the error message LOGO2 CP 'N' CALL NZ,CONOUT JR LOGO1 ; LOGO3 LD DE,ERMS19 ;Get the message JP PRTSTR ;Print it ; ; This is the BYE command ; BYE EQU $ LD A,CMCFM CALL COMND ;GET A CONFIRM. JP KERMT3 CALL NEWLIN CALL LOGO ;TELL THE MAIN FRAME TO LOGOUT. JP LOG111 ;IF IT FAILS, DON'T EXIT. JP EXIT1 ;EXIT KERMIT. LOG111 CALL NEWLIN ;GET A NEW LINE JP KERMIT ; ; Get the rest of the modules ; *GET M4FILE/ASM ;Log file code *GET M4CMD/ASM ;Command parser *GET M4SET/ASM ;Set command processing *GET M4TERM/ASM ;Terminal emulation *GET M4SHOW/ASM ;Show command processing *GET M4PKT/ASM ;Additional packet stuff *GET M4GET/ASM ;Receive protocol *GET M4SEND/ASM ;Send protocol *GET M4XFER/ASM ;Protocol common code *GET M4ADD/ASM ;TRSDOS SVC's and other system dependent stuff *GET M4RMT/ASM ;Remote commands *GET M4KEY/ASM ;Set key code *GET M4LOG/ASM ;Input, Output, Pause, Pulse commands *GET M4WILD/ASM ;Wild carding *GET M4STR/ASM ;Strings and storage TOPMEM EQU $+10 ;A little padding END START ;end of file