; ; PCPUT - This CP/M program sends a file from the CP/M machine to a PC using ; a serial port. The file transfer uses the XMODEM protocol. ; ; Note this program is gutted from the Ward Christenson Modem program. ; ; Hacked together by Mike Douglas for the Sol-20 Computer. ; Ver Date Desc ; 1.0 5/12/14 Initial version ; ; 1.1 11/21/14 Look for ctrl-c abort on Sol-20 keyboard in addition ; to the incoming data line. ; ; 1.2 12/21/14 Support CRC as well as checksum ; ; 1.3 10/16/15 Set initial CRC flag state in software. Was ; previously random from load. ; ; 1.4 02/23/16 Use the SOLOS/CUTER AINP/AOUT entry points for ; serial I/O instead of accessing the hardware ; directly. This allows PCGET to function with ; the subsystem-b card set as well as a Sol-20. ; Delete erroneous INIT$ACIA call. ; SOLOS/CUTER Equates SOLOS EQU 0C000H ;BASE ADDRESS OF SOLOS/CUTER AINP EQU SOLOS+22H ;PORT INOUT AOUT EQU SOLOS+1CH ;PORT OUTPUT ERROR$LIMIT EQU 5 ;MAX ALLOWABLE ERRORS ;DEFINE ASCII CHARACTERS USED SOH EQU 1 EOT EQU 4 ACK EQU 6 NAK EQU 15H CTRLC EQU 3 ;Control-C LF EQU 10 CR EQU 13 org 100h ; Verify that a file name to send has been specified on the command line lda fcb+1 ;A=1st character of command line parameter cpi ' ' ;make sure something entered jnz havName ;have a file name lxi d,helpMsg ;otherwise, display help message mvi c,print call bdos ret ;return to CPM ; Have a filename on the command line. Switch to local stack. havName LXI H,0 ;HL=0 DAD SP ;HL=STACK FROM CP/M SHLD STACK ;..SAVE IT LXI SP,STACK ;SP=MY STACK xra a sta SECTNO ;initialize sector number to zero CALL OPEN$FILE ;OPEN THE FILE LXI d,rcvMsg ;print "Start file receive now" message MVI C,PRINT CALL BDOS ;PRINT ID MESSAGE ; GOBBLE UP GARBAGE CHARS FROM THE LINE purge MVI B,1 ;times out after 1 second if no data CALL RECV jc lineClr ;line is clear, go wait for initial NAK cpi ctrlc ;exit if abort requested jz abort jmp purge ; WAIT FOR INITIAL NAK, THEN SEND THE FILE lineClr xra a ;clear crc flag = checksum mode sta crcFlag WAITNAK MVI B,1 ;TIMEOUT DELAY CALL RECV JC WAITNAK cpi ctrlc ;abort requested? jz abort CPI NAK ;NAK RECEIVED? jz SENDB ;yes, send file in checksum mode cpi 'C' ;'C' for CRC mode received? JNZ WAITNAK ;no, keep waiting sta crcFlag ;set CRC flag non-zero = true ;fall through to start the send operation ; ;*****************SEND A FILE*************** ; ;READ SECTOR, SEND IT SENDB CALL READ$SECTOR LDA SECTNO ;INCR SECT NO. INR A STA SECTNO ;SEND OR REPEAT SECTOR REPTB MVI A,SOH CALL SEND LDA SECTNO CALL SEND LDA SECTNO CMA CALL SEND lxi h,0 ;init crc to zero shld crc16 mov c,h ;init checksum in c to zero LXI H,80H SENDC MOV A,M CALL SEND call calCrc ;update CRC INX H MOV A,H CPI 1 ;DONE WITH SECTOR? JNZ SENDC ; Send checksum or CRC based on crcFlag lda crcFlag ;crc or checksum? ora a jz sndCsum ;flag clear = checksum lda crc16+1 ;a=high byte of CRC call SEND ;send it lda crc16 ;a=low byte of crc jmp sndSkip ;skip next instruction sndCsum mov a,c ;send the checksum byte sndSkip call SEND ;GET ACK ON SECTOR MVI B,4 ;WAIT 4 SECONDS MAX CALL RECV JC REPTB ;TIMEOUT, SEND AGAIN ;NO TIMEOUT SENDING SECTOR CPI ACK ;ACK RECIEVED? JZ SENDB ;..YES, SEND NEXT SECT cpi ctrlc ;control-c to abort? jz abort JMP REPTB ;PROBABLY NAK - TRY AGAIN ; ; ; S U B R O U T I N E S ; ;OPEN FILE OPEN$FILE LXI D,FCB MVI C,OPEN CALL BDOS INR A ;OPEN OK? RNZ ;GOOD OPEN CALL ERXIT DB CR,LF,'Can''t Open File',CR,LF,'$' ; - - - - - - - - - - - - - - - ;EXIT PRINTING MESSAGE FOLLOWING 'CALL ERXIT' ERXIT POP D ;GET MESSAGE MVI C,PRINT CALL BDOS ;PRINT MESSAGE EXIT LHLD STACK ;GET ORIGINAL STACK SPHL ;RESTORE IT RET ;--EXIT-- TO CP/M ; - - - - - - - - - - - - - - - ;MODEM RECV ;------------------------------------- RECV PUSH D ;SAVE D,E MSEC lxi d,6289 ;1 sec = 6289 * 318 cycles MWTI mvi a,1 ;(7) read from serial port call AINP ;(136) call SOLOS/CUTER to read port jnz MCHAR ;(10) have character ; Look for CTRL-C on Sol-20 keyboard xra a ;(4) read from keyboard call AINP ;(136) call SOLOS/CUTER to read keyboard jz NOKEY ;(10) nothing pressed cpi CTRLC ;CTRL-C typed? jnz NOKEY ;no pop d ;restore D,E ret ;return the CTRL-C NOKEY DCR E ;(5) COUNT DOWN JNZ MWTI ;(10) FOR TIMEOUT DCR D JNZ MWTI DCR B ;DCR # OF SECONDS JNZ MSEC ;MODEM TIMED OUT RECEIVING POP D ;RESTORE D,E STC ;CARRY SHOWS TIMEOUT RET ;GOT MODEM CHAR (already in A) MCHAR POP D ;RESTORE DE mov b,a ;save character read in B ADD C ;CALC CKSUM MOV C,A mov a,b ;restore character read into A ORA A ;TURN OFF CARRY TO SHOW NO TIMEOUT RET ; - - - - - - - - - - - - - - - ;MODEM SEND CHAR ROUTINE ;---------------------------------- ; SEND mov b,a ;put character to send in B ADD C ;CALC CKSUM MOV C,A mvi a,1 ;output to serial port call AOUT ;send character using SOLOS/CUTER RET ; ;FILE READ ROUTINE ; READ$SECTOR: LXI D,FCB MVI C,READ CALL BDOS ORA A RZ DCR A ;EOF? JNZ RDERR ;EOF XRA A STA ERRCT SEOT MVI A,EOT CALL SEND MVI B,3 ;WAIT 3 SEC FOR TIMEOUT CALL RECV JC EOTTOT ;EOT TIMEOUT CPI ACK JZ XFER$CPLT ;ACK NOT RECIEVED EOTERR LDA ERRCT INR A STA ERRCT CPI ERROR$LIMIT JC SEOT CALL ERXIT db CR,LF,LF db 'No ACK received on EOT, but transfer is complete.',CR,LF,'$' ; ;TIMEOUT ON EOT ; EOTTOT JMP EOTERR ; ;READ ERROR ; RDERR CALL ERXIT DB CR,LF,'File Read Error',CR,LF,'$' ;DONE - CLOSE UP SHOP XFER$CPLT: CALL ERXIT DB CR,LF,LF,'Transfer Complete',CR,LF,'$' abort call erxit DB CR,LF,LF,'Transfer Aborted',CR,LF,'$' ;----------------------------------------------------------------------------- ; calCrc - update the 16-bit CRC with one more byte. ; (Copied from M. Eberhard) ; On Entry: ; a has the new byte ; crc16 is current except this byte ; On Exit: ; crc16 has been updated ; Trashes a,de ;----------------------------------------------------------------------------- calCrc push b ;save bc, hl push h lhld crc16 ;get CRC so far xra h ;XOR into CRC top byte mov h,a lxi b,1021h ;bc=CRC16 polynomial mvi d,8 ;prepare to rotate 8 bits ; do 8 bit shift/divide by CRC polynomial cRotLp dad h ;16-bit shift jnc cClr ;skip if bit 15 was 0 mov a,h ;CRC=CRC xor 1021H xra b mov h,a mov a,l xra c mov l,a cClr dcr d jnz cRotLp ;rotate 8 times ; save the updated CRC and exit shld crc16 ;save updated CRC pop h ;restore hl, bc pop b ret ; Messages rcvMsg db 'Start XMODEM file receive now...$' helpMsg db CR,LF,'PCPUT Ver 1.4 for the Sol-20',CR,LF,LF db 'Transmits a file to a PC through the',CR,LF db 'serial port using the XMODEM protocol.',CR,LF,LF db 'Usage: PCPUT file.ext',CR,LF,'$' ; Data Area DS 40 ;STACK AREA STACK DS 2 ;STACK POINTER SECTNO DS 1 ;CURRENT SECTOR NUMBER ERRCT DS 1 ;ERROR COUNT crcFlag ds 1 ;non-zero if using CRC crc16 ds 2 ;computed crc ; ; BDOS EQUATES (VERSION 2) ; RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 CONST EQU 11 ;CONSOLE STAT OPEN EQU 15 ;0FFH=NOT FOUND CLOSE EQU 16 ; " " SRCHF EQU 17 ; " " SRCHN EQU 18 ; " " ERASE EQU 19 ;NO RET CODE READ EQU 20 ;0=OK, 1=EOF WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC MAKE EQU 22 ;0FFH=BAD REN EQU 23 ;0FFH=BAD STDMA EQU 26 BDOS EQU 5 REIPL EQU 0 FCB EQU 5CH ;SYSTEM FCB end