]> cloudbase.mooo.com Git - kermit-80.git/blame - cpspk2.asm
Bugfix in outmdm (output buffer flush)
[kermit-80.git] / cpspk2.asm
CommitLineData
e58a7a25
L
1; CPSPK2.ASM\r
2; KERMIT - (Celtic for "FREE")\r
3;\r
4; This is the CP/M-80 implementation of the Columbia University\r
5; KERMIT file transfer protocol.\r
6;\r
7; Version 4.0\r
8;\r
9; Copyright June 1981,1982,1983,1984\r
10; Columbia University\r
11;\r
12; Originally written by Bill Catchings of the Columbia University Center for\r
13; Computing Activities, 612 W. 115th St., New York, NY 10025.\r
14;\r
15; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,\r
16; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many\r
17; others. \r
18;\r
19; This file contains the (system-independent) routines that implement\r
20; the KERMIT protocol, and the commands that use them:\r
21; RECEIVE, SEND, FINISH, and LOGOUT.\r
22;\r
23; revision history:\r
24;\r
25;edit 11, 21-Mar-1991 by MF. After "inchr7", close TAKE-file (if any) so\r
26; ^C will halt all processing (including commands from TAKE-files)\r
27; and put the user back at Kermit command-level.\r
28;edit 10, 3-Jan-1991 by MF. Modify routine "inchr" after label "inchr5" to\r
29; not take retry (nonskip) return if ^X/^Z seen on the Console. This\r
30; will prevent multiple copies of packets being sent if user aborts\r
31; some files in a stream being sent via ^X and is a better fix to this\r
32; problem than flushing comm input before sending the "Z" packet\r
33; requesting the remote Kermit to discard the current file being\r
34; received (as implemented in CPSPK1.ASM edit of 2-jan-1991).\r
35;edit 9, 14-Dec-1990 by MF. Modified "gofil" routine to allow for\r
36; specification of a drive in the local filespec for GET and\r
37; RECEIVE commands. Thus commands such as\r
38; GET HELLO.TXT B:GOODBYE.TXT\r
39; and\r
40; RECEIVE B:GOODBYE.TXT\r
41; now work as expected.\r
42;edit 8, 22-Oct-1990 by MF. Fixed bug in completion-message routine\r
43; "finmes" wherein the completion message was not printed if the\r
44; terminal was set to QUIET because the message pointer was clobbered\r
45; by prcrlf.\r
46;edit 7, 14-Sep-1990 by MF. Add hooks for SET COLLISION command.\r
47; Eliminate commented-out old file warning rename routine.\r
48; Clear communication input buffers (call flsmdm) before\r
49; BYE, FINISH and LOGOUT commands.\r
50;edit 6, 9-Sep-1990 by MF. Implemented fixes in CPKERM.BWR for\r
51; garbage printout during quiet transfers and for file existence/\r
52; rename algorithm.\r
53; Also implemented hooks for Remote commands.\r
54; edit 5, 18 June 1990 by Russell Lang [rjl@monu1.cc.monash.edu.au]\r
55; When trying to generate a unique file name on receive, zero\r
56; the attribute bits between file opening attempts. This is\r
57; to fix a bug which caused the unique file name to have the\r
58; attributes of the already existing file. If the attribute\r
59; was R/O, a bdos error occured later when an attempt was made\r
60; to write to the file.\r
61;\r
62; edit 4, 27 October, 1987 By OBSchou. Changed the rename routine to \r
63; be more like the MSDOS issue.\r
64;\r
65; edit 3, 28 July, by OBSchou. Added traps to NOT print to screen during\r
66; file transfers if quietd is non zero (ie we SET TERMINAL QUIET)\r
67; This hopefully speeds up transfers in systems spending an age\r
68; updating the screen.\r
69;\r
70; edit 2, 8 April, 1987 by OBSchou. Minor edit to put drive and user number\r
71; in the "filename" field on the transfer screen. This means that the\r
72; offset on the line foe the file name proper has moved along 4 space. \r
73; Also, it writes 15 spaces AFER the xxd: string to clear the field \r
74; of any prevous file. Needed for thos terminals that cannot\r
75; clear to end of line...\r
76;\r
77; edit 1, 28 January, 1987 by OBSchou.\r
78; Hived off about 1/2 of CPSPKT.ASM to form two (smaller => easier\r
79; to handle) files. \r
80;\r
81;\r
82\r
83pk2ver: db 'CPSPK2.ASM (11) 21-Mar-1991$' ; name, edit number, date\r
84\r
85\r
86;\r
87; Get the file name (including host to micro translation)\r
88; called by: rfile\r
89\r
90gofil: xra a\r
91 sta fcb ;Set the drive to default to current.\r
92 lxi h,data ;Get the address of the file name.\r
93; allow use of local name if one was given [gnn]\r
94 lda remlen ;[gnn] \r
95 ora a ;[gnn] anything there?\r
96 jz gofil0 ;[gnn] no, use the one in the data packet\r
97 lxi h,remnam ;[gnn] yes, use this instead\r
98 lda remnam+1 ;[MF]Get 2nd char of local filename\r
99 cpi ':' ;[MF]Was a drive specified?\r
100 jnz gofil0 ;[MF]No, proceed as of old\r
101 mov a,m ;[MF]Yes, get drive\r
102 ani 5fh ;[MF]Force uppercase\r
103 sui 'A'-1 ;[MF]Make valid drive for fcb\r
104 sta fcb ;[MF]and store in fcb\r
105 inx h ;[MF]Skip drive and delimiter\r
106 inx h ;[MF]...\r
107gofil0: ;[gnn] continue to set up the file [gnn]\r
108;\r
109 shld datptr ;Store the address.\r
110 lxi h,fcb+1 ;Address of the FCB.\r
111 shld fcbptr ;Save it.\r
112 xra a\r
113 sta temp1 ;Initialize the char count.\r
114 sta temp2\r
115 mvi b,' '\r
116gofil1: mov m,b ;Blank the FCB.\r
117 inx h\r
118 inr a\r
119; cpi 0CH ;Twelve?[5a]\r
120 cpi 0BH ; Eleven? [5a]\r
121 jm gofil1\r
122 mvi m,0 ; [5a] Specify extent 0\r
123gofil2: lhld datptr ;Get the NAME field.\r
124 mov a,m\r
125 cpi 'a' ;Force upper case\r
126 jm gofl2a ;\r
127 ani 5FH ;\r
128gofl2a: inx h\r
129 cpi '.' ;Seperator?\r
130 jnz gofil3\r
131 shld datptr ;[jd] update ptr (moved from above)\r
132 lxi h,fcb+9H\r
133 shld fcbptr\r
134 lda temp1\r
135 sta temp2\r
136 mvi a,9H\r
137 sta temp1\r
138 jmp gofil6\r
139\r
140gofil3: ora a ;Trailing null?\r
141 jz gofil7 ;Then we're done.\r
142 shld datptr ;[jd] no, can update ptr now.\r
143 lhld fcbptr\r
144 mov m,a\r
145 inx h\r
146 shld fcbptr\r
147 lda temp1 ;Get the char count.\r
148 inr a\r
149 sta temp1\r
150 cpi 8H ;Are we finished with this field?\r
151 jm gofil2\r
152gofil4: sta temp2\r
153 lhld datptr\r
154 mov a,m\r
155 inx h\r
156 shld datptr\r
157 ora a\r
158 jz gofil7\r
159 cpi '.' ;Is this the terminator?\r
160 jnz gofil4 ;Go until we find it.\r
161gofil6: lhld datptr ;Get the TYPE field.\r
162 mov a,m\r
163 cpi 'a' ;Force upper case\r
164 jm gofl6a ;\r
165 ani 5FH ;\r
166gofl6a: ora a ;Trailing null?\r
167 jz gofil7 ;Then we're done.\r
168;[jd] move above two lines so we don't increment pointer if char is null\r
169 inx h\r
170 shld datptr\r
171 lhld fcbptr\r
172 mov m,a\r
173 inx h\r
174 shld fcbptr\r
175 lda temp1 ;Get the char count.\r
176 inr a\r
177 sta temp1\r
178 cpi 0CH ;Are we finished with this field?\r
179 jm gofil6\r
180gofil7: lhld datptr\r
181 mvi m,'$' ;Put in a dollar sign for printing.\r
182 lda quietd ; quiet display?\r
183 ana a\r
184 jnz gofi70 ; yes, so skip it.\r
185 call scrfln ;Position cursor\r
186gofi70: lxi d,data ;Print the file name\r
187 lda getrxflg ;[obs 8] are we doing a get or receive?\r
188 ana a ;[obs 8]\r
189 jz gofi7a ;[obs 8] if zero, receive\r
190 lxi d,remnam ;[obs 8]\r
191gofi7a: ;[obs 8]\r
192\r
193 call prtstr\r
194gofi7b: xra a ;[MF]Zero "discard" flag\r
195 sta dscflg ;[MF]...\r
196 lda flwflg ;Is file warning on?\r
197 ora a\r
198 jz gofil9 ;If not, just proceed.\r
199 mvi c,openf ;See if the file exists.\r
200 lxi d,fcb\r
201 call bdos\r
202 cpi 0FFH ;Does it exist?\r
203 jz gofil9 ;If not create it.\r
204;\r
205 lda flwflg ;[MF]Get flag again\r
206 cpi 3 ;[MF]SET COLLISION DISCARD?\r
207 jnz gofi7h ;[MF]No\r
208 mvi a,0ffh ;[MF]Yes, order rejection of the file\r
209 sta dscflg ;[MF]...\r
210 jmp rskp ;[MF]and pretend successful open\r
211gofi7h: push psw ;[MF]Save Collision status\r
212 lxi d,infms5\r
213 call error3\r
214 pop psw ;[MF]Restore Collision status\r
215 cpi 1 ;[MF]SET COLLISION RENAME?\r
216 jz gofi7i ;[MF]Yes, same as SET WARNING ON\r
217 ;[MF]If we come here, SET COLLISION BACKUP\r
218 lxi h,fcb ;[MF]Copy original fcb to a safe place\r
219 lxi d,colfcb ;[MF]...\r
220 lxi b,33 ;[MF]...\r
221 call mover ;[MF]...\r
222 ;[MF]and fall into rename code\r
223gofi7i: ;[MF]\r
224;\r
225; Replacement file name renamer routine. Incomming\r
226; files are renamed in this manner:\r
227; original file name: filex.ext\r
228; first rename: filex001.ext\r
229; ... ...\r
230; ninth rename filex009.ext\r
231; 10th rename fail - would we really want 10\r
232; files of the same name??\r
233;\r
234;\r
235; 1)\r
236; Assume that we need to "rename" the file, so lets make sure\r
237; that there is a full. 8 character filename. (We make it if \r
238; it does not already exist)\r
239; 1a) If full file name, last character is to be replaced\r
240; by a zero. This gives us up to no#ine renames.\r
241; 2)open file\r
242; 2a)If exists, increment last character by one\r
243; 2b)if = '9' then abort\r
244; 2c)If does not exist, got 2)\r
245; 3)we have a valid 'renamed' file\r
246;\r
247;Part 1) - fill out filename part \r
248\r
249 mvi c,8 ; max 8 characters to test for\r
250 mvi a,'0' ; spaces to be replaced by a zero.\r
251 lxi h,fcb+8 ; start at the end\r
252gofi7c: mov m,a ; put a zero in here\r
253 dcr c ; come to the end?\r
254 jz gofi7d ; should not have, but just in case...\r
255 dcx h ; previous chararcter\r
256 mov a,m ; get it\r
257 cpi ' ' ; if this character a space as well, zero it\r
258 mvi a,'0' ; set it to ascii zero just in case...\r
259 jz gofi7c ;\r
260;\r
261; Part 2) open the file (if success, then it exists)\r
262\r
263gofi7d:\r
264;zero the attribute bits. [rjl@monu1.cc.monash.edu.au]\r
265 lxi h,fcb+1 ;[rjl]\r
266 mvi c,11 ;[rjl]\r
267gofi7z: mov a,m ;[rjl]\r
268 ani 07fh ;[rjl]\r
269 mov m,a ;[rjl]\r
270 inx h ;[rjl]\r
271 dcr c ;[rjl]\r
272 jnz gofi7z ;[rjl]\r
273 lxi d,fcb\r
274 mvi c,openf\r
275 call BDOS\r
276 inr a ; if 0ffh returned, error (ie does not exist)\r
277 jz gofi7e\r
278 lda fcb+8 ; get last character\r
279 inr a\r
280 sta fcb+8\r
281 cpi '9'+1 ; more than '9' => too far, lets give up.\r
282 jnz gofi7d ; else try again\r
283;Giving up, so lets exit\r
284 lxi d,erms16 ;\r
285 call prtstr\r
286 ret ; return to error routine\r
287\r
288gofi7e: lxi d,fnbuf ; make the file name into a character string\r
289 lxi h,fcb+1 ; point to source file name, less drive name\r
290 mvi c,8 ; 11 characters (8+3) + dot to copy across\r
291;\r
292gofi7f: mov a,m ; get character\r
293 stax d\r
294 inx h\r
295 inx d\r
296 dcr c\r
297 jnz gofi7f ; loop until all done\r
298\r
299 mvi a,'.' ; then the dot\r
300 stax d\r
301 inx d\r
302\r
303 mvi c,3 ; then the file extention\r
304\r
305gofi7g: mov a,m\r
306 stax d\r
307 inx h\r
308 inx d\r
309 dcr c\r
310 jnz gofi7g ; loop until extention copied across\r
311\r
312 mvi a,'$' ; dollar terminate string\r
313 stax d\r
314 lxi d,fnbuf ;[MF]Point to string\r
315 call prtstr ; write string to console\r
316\r
317 lda flwflg ;[MF]Get warning (SET COLLISION) flag\r
318 cpi 2 ;[MF]SET COLLISION BACKUP?\r
319 jnz gofil9 ;[MF]No\r
320 lxi h,fcb ;[MF]Yes, get new filename fcb\r
321 lxi d,colfcb+16 ;[MF]Where to copy to for rename\r
322 lxi b,16 ;[MF]Copy 16 bytes\r
323 call mover ;[MF]...\r
324 lxi d,colfcb ;[MF]Point to rename fcb\r
325 mvi c,renam ;[MF]Rename function\r
326 call bdos ;[MF]Try to rename original file\r
327 cpi 0ffh ;[MF]Did we win?\r
328 jnz gofl82 ;[MF]Yes\r
329 lxi d,erms16 ;[MF]No, complain and bomb\r
330 jmp error3 ;[MF]...\r
331gofl82: lxi h,colfcb ;[MF]Now recopy original filename into fcb\r
332 lxi d,fcb ;[MF]to create new file with original name\r
333 lxi b,16 ;[MF]...\r
334 call mover ;[MF]...\r
335;\r
336;\r
337;Now lets make the file (create it)\r
338\r
339gofil9: call makfil ; Create the file.\r
340 jmp gofl91 ; Disk was full.\r
341 jmp rskp ; Success.\r
342 \r
343gofl91: lxi d,erms11\r
344 call error3\r
345 ret\r
346;\f\r
347; This is the FINISH command. It tells the remote KERSRV to exit.\r
348; here from kermit\r
349\r
350finish: call cfmcmd\r
351 call selmdm ;[MF]Select modem\r
352 call flsmdm ;[MF]Flush buffers\r
353 call selcon ;[MF]Select keyboard again\r
354 xra a\r
355 sta numtry ;Inititialize count.\r
356 mvi a,'1' ;Reset block check type to single character\r
357 sta curchk ; . . .\r
358\r
359finsh1: lda numtry ;How many times have we tried?\r
360 cpi maxtry ;Too many times?\r
361 jm finsh3 ;No, try it.\r
362finsh2: lxi d,erms18 ;Say we couldn't do it.\r
363 call prtstr\r
364 jmp kermit ;Go home.\r
365\r
366finsh3: inr a ;Increment the number of tries.\r
367 sta numtry\r
368 xra a\r
369 sta argblk ;Make it packet number zero.\r
370 mvi a,1\r
371 sta argblk+1 ;One piece of data.\r
372 lxi h,data\r
373 mvi m,'F' ;Finish running Kermit.\r
374 mvi a,'G' ;Generic command packet.\r
375 call spack\r
376 jmp finsh2 ; Tell the user and die.\r
377 call rpack ;Get an acknowledgement.\r
378 jmp finsh1 ; Go try again.\r
379 cpi 'Y' ;ACK?\r
380 jz kermit ;Yes, we are done.\r
381 cpi 'E' ;Is it an error packet?\r
382 jnz finsh1 ;Try sending the packet again.\r
383 call error1 ;Print the error message.\r
384 jmp kermit\r
385;\f\r
386; This is the LOGOUT command. It tells the remote KERSRV to logout.\r
387; here from: kermit\r
388\r
389logout: call cfmcmd\r
390 call logo ;Send the logout packet.\r
391 jmp kermit ;Go get another command\r
392 jmp kermit ; whether we succeed or not.\r
393\r
394; do logout processing.\r
395; called by: bye, logout\r
396\r
397logo: call selmdm ;[MF]Select modem\r
398 call flsmdm ;[MF]Flush buffers\r
399 call selcon ;[MF]Select keyboard again\r
400 xra a\r
401 sta numtry ;Inititialize count.\r
402 mvi a,'1' ;Reset block check type to single character\r
403 sta curchk ; . . .\r
404\r
405logo1: lda numtry ;How many times have we tried?\r
406 cpi maxtry ;Too many times?\r
407 jm logo3 ;No, try it.\r
408logo2: lxi d,erms19 ;Say we couldn't do it.\r
409 call prtstr\r
410 ret ;Finished.\r
411\r
412logo3: inr a ;Increment the number of tries.\r
413 sta numtry\r
414 xra a\r
415 sta argblk ;Make it packet number zero.\r
416 mvi a,1\r
417 sta argblk+1 ;One piece of data.\r
418 lxi h,data\r
419 mvi m,'L' ;Logout the remote host.\r
420 mvi a,'G' ;Generic command packet.\r
421 call spack\r
422 jmp logo2 ; Tell the user and die.\r
423 call rpack ;Get an acknowledgement\r
424 jmp logo1 ; Go try again.\r
425 cpi 'Y' ;ACK?\r
426 jz rskp ;Yes, we are done.\r
427 cpi 'E' ;Is it an error packet?\r
428 jnz logo1 ;Try sending the packet again.\r
429 call error1 ;Print the error message.\r
430 ret ;All done.\r
431;\f\r
432; Packet routines\r
433\r
434; Send_Packet\r
435; This routine assembles a packet from the arguments given and sends it\r
436; to the host.\r
437;\r
438; Expects the following:\r
439; A - Type of packet (D,Y,N,S,R,E,F,Z,T)\r
440; ARGBLK - Packet sequence number\r
441; ARGBLK+1 - Number of data characters\r
442; Returns: nonskip if failure\r
443; skip if success\r
444; called by: read, rinit, rfile, rdata, sinit, sfile, sdata, seof, seot,\r
445; finish, logout, nak, ackp\r
446\r
447spack: sta argblk+2\r
448 lxi h,packet ;Get address of the send packet.\r
449 lda sndsop ;[gnn] send start-of-pkt char.\r
450 mov m,a ;Put in the packet.\r
451 inx h ;Point to next char.\r
452 lda curchk ;Get current checksum type\r
453 sui '1' ;Determine extra length of checksum\r
454 mov b,a ;Copy length\r
455 lda argblk+1 ;Get the number of data chars.\r
456 adi ' '+3 ;Real packet character count made printable.\r
457 add b ;Determine overall length\r
458 mov m,a ;Put in the packet.\r
459 inx h ;Point to next char.\r
460 lxi b,0 ;Zero the checksum AC.\r
461 mov c,a ;Start the checksum.\r
462 lda argblk ;Get the packet number.\r
463 adi ' ' ;Add a space so the number is printable.\r
464 mov m,a ;Put in the packet.\r
465 inx h ;Point to next char.\r
466 add c\r
467 mov c,a ;Add the packet number to the checksum.\r
468 mvi a,0 ;Clear A (Cannot be XRA A, since we can't\r
469 ; touch carry flag)\r
470 adc b ;Get high order portion of checksum\r
471 mov b,a ;Copy back to B\r
472 lda argblk+2 ;Get the packet type.\r
473 mov m,a ;Put in the packet.\r
474 inx h ;Point to next char.\r
475 add c\r
476 mov c,a ;Add the packet number to the checksum.\r
477 mvi a,0 ;Clear A\r
478 adc b ;Get high order portion of checksum\r
479 mov b,a ;Copy back to B\r
480spack2: lda argblk+1 ;Get the packet size.\r
481 ora a ;Are there any chars of data?\r
482 jz spack3 ; No, finish up.\r
483 dcr a ;Decrement the char count.\r
484 sta argblk+1 ;Put it back.\r
485 mov a,m ;Get the next char.\r
486 inx h ;Point to next char.\r
487 add c\r
488 mov c,a ;Add the packet number to the checksum.\r
489 mvi a,0 ;Clear A\r
490 adc b ;Get high order portion of checksum\r
491 mov b,a ;Copy back to B\r
492 jmp spack2 ;Go try again.\r
493\r
494spack3: lda curchk ;Get the current checksum type\r
495 cpi '2' ;Two character?\r
496 jz spack4 ;Yes, go handle it\r
497 jnc spack5 ;No, go handle CRC if '3'\r
498 mov a,c ;Get the character total.\r
499 ani 0C0H ;Turn off all but the two high order bits.\r
500 ;Shift them into the low order position.\r
501 rlc ;Two left rotates same as 6 rights\r
502 rlc ; . . .\r
503 add c ;Add it to the old bits.\r
504 ani 3FH ;Turn off the two high order bits. (MOD 64)\r
505 adi ' ' ;Add a space so the number is printable.\r
506 mov m,a ;Put in the packet.\r
507 inx h ;Point to next char.\r
508 jmp spack7 ;Go store eol character\r
509\r
510;Here for 3 character CRC-CCITT\r
511\r
512spack5: mvi m,0 ;Store a null for current end\r
513 push h ;Save H\r
514 lxi h,packet+1 ;Point to first checksumed character\r
515 call crcclc ;Calculate the CRC\r
516 pop h ;Restore the pointer\r
517 mov c,e ;Get low order half for later\r
518 mov b,d ;Copy the high order\r
519 mov a,d ;Get the high order portion\r
520 rlc ;Shift off low 4 bits\r
521 rlc ; . . .\r
522 rlc ; . . .\r
523 rlc ; . . .\r
524 ani 0FH ;Keep only low 4 bits\r
525 adi ' ' ;Put into printing range\r
526 mov m,a ;Store the character\r
527 inx h ;Point to next position\r
528\r
529;Here for two character checksum\r
530\r
531spack4: mov a,b ;Get high order portion\r
532 ani 0FH ;Only keep last four bits\r
533 rlc ;Shift up two bits\r
534 rlc ; . . .\r
535 mov b,a ;Copy back into safe place\r
536 mov a,c ;Get low order half\r
537 rlc ;Shift high two bits\r
538 rlc ;to low two bits\r
539 ani 03H ;Keep only two low bits\r
540 ora b ;Get high order portion in\r
541 adi ' ' ;Convert to printing character range\r
542 mov m,a ;Store the character\r
543 inx h ;Point to next character\r
544 mov a,c ;get low order portion\r
545 ani 3FH ;Keep only six bits\r
546 adi ' ' ;Convert to printing range\r
547 mov m,a ;Store it\r
548 inx h ;Bump the pointer\r
549\r
550spack7: lda dbgflg\r
551 ora a ; is debugging enabled?\r
552 jz spack8\r
553 push h ; yes. save address of end of packet\r
554 mvi m,0 ; null-terminate the packet for display\r
555 lda quietd ; a quiet display?\r
556 ana a\r
557 jnz spac7a ; so dont say a thing\r
558 call sppos ; position cursor\r
559 lxi h,packet+1 ; print the packet\r
560 call dmptxt\r
561 lda prnflg ; is the printer on too?\r
562 ana a\r
563 jz spac7a\r
564 lxi h,sstatm ; print state\r
565 call printm ; dumptext but to printer\r
566 lda state\r
567 mov e,a\r
568 call outprn\r
569 lxi h,princr ; cr lf to printer\r
570 call printm\r
571 lxi h,spackm\r
572 call printm\r
573 lxi h,packet+1\r
574 call printm\r
575 lxi h,princr\r
576 call printm\r
577 lxi h,princr\r
578 call printm\r
579\r
580spac7a: pop h ; restore address of end of packet\r
581spack8: lda seol ;Get the EOL the other host wants.\r
582 mov m,a ;Put in the packet.\r
583 inx h ;Point to next char.\r
584 xra a ;Get a null.\r
585 mov m,a ;Put in the packet.\r
586; Write out the packet.\r
587outpkt: call selmdm ; Set up for output to comm port if iobyt\r
588 lda spad ;Get the number of padding chars.\r
589 sta temp1\r
590outpk2: lda temp1 ;Get the count.\r
591 dcr a\r
592 ora a\r
593 jm outpk6 ;If none left proceed.\r
594 sta temp1\r
595 lda spadch ;Get the padding char.\r
596 call setpar ;Set parity appropriately\r
597 mov e,a ;Put the char in right AC.\r
598 call outmdm ;Output it.\r
599 jmp outpk2\r
600\r
601outpk6: lxi h,packet ; Point to the packet.\r
602outlup: mov a,m ; Get the next character.\r
603 ora a ; Is it a null?\r
604 jz outlud ; If so return success.\r
605 call setpar ; Set parity for the character\r
606 mov e,a ; Put it in right AC\r
607 call outmdm ; and output it.\r
608; TAC trap: If this character is the TAC intercept character, and the TAC\r
609; trap is enabled, we have to output it twice. If the TAC trap is enabled,\r
610; tacflg contains the intercept character. (The current character cannot\r
611; be NUL, so we don't have to worry about doubling nulls in the message)\r
612 lda tacflg ; get current intercept character, or zero.\r
613 cmp m ; compare against current data character.\r
614 jnz outpk8 ; if different, do nothing.\r
615 call setpar ; match. set appropriate parity,\r
616 mov e,a ; put it in the right register,\r
617 call outmdm ; and output it a second time.\r
618outpk8:\r
619 inx h ; Increment the char pointer.\r
620 jmp outlup\r
621\r
622outlud: call selcon ; select console\r
623 jmp rskp ; and return success\r
624;\f\r
625; Receive_Packet\r
626; This routine waits for a packet to arrive from the host. It reads\r
627; characters until it finds a SOH. It then reads the packet into packet.\r
628;\r
629; Returns: nonskip if failure (checksum wrong or packet trashed)\r
630; skip if success, with\r
631; A - message type\r
632; ARGBLK - message number\r
633; ARGBLK+1 - length of data\r
634; called by: rinit, rfile, rdata,\r
635; sinit, sfile, sdata, seof, seot, finish, logout\r
636\r
637rpack: call inpkt ;Read up to the end-of-line character\r
638 jmp r ; Return bad.\r
639rpack0: call getchr ;Get a character.\r
640 jmp rpack ; Hit eol;null line;just start over.\r
641 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
642 cmp m ;[gnn]\r
643 jnz rpack0 ; No, go until it is.\r
644rpack1: call getchr ;Get a character.\r
645 jmp r ; Hit end of line, return bad.\r
646 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
647 cmp m ;[gnn]\r
648 jz rpack1 ; Yes, then go start over.\r
649 sta packet+1 ;Store in packet also\r
650 mov c,a ;Start the checksum.\r
651 lda curchk ;Get block check type\r
652 sui '1' ;Determine extra length of block check\r
653 mov b,a ;Get a copy\r
654 mov a,c ;Get back length character\r
655 sui ' '+3 ;Get the real data count.\r
656 sub b ;Get total length\r
657 sta argblk+1\r
658 mvi b,0 ;Clear high order half of checksum\r
659 call getchr ;Get a character.\r
660 jmp r ; Hit end of line, return bad.\r
661 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
662 cmp m ;[gnn]\r
663 jz rpack1 ; Yes, then go start over.\r
664 sta argblk\r
665 sta packet+2 ;Save also in packet\r
666 add c\r
667 mov c,a ;Add the character to the checksum.\r
668 mvi a,0 ;Clear A\r
669 adc b ;Get high order portion of checksum\r
670 mov b,a ;Copy back to B\r
671 lda argblk\r
672 sui ' ' ;Get the real packet number.\r
673 sta argblk\r
674 call getchr ;Get a character.\r
675 jmp r ; Hit end of line, return bad.\r
676 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
677 cmp m ;[gnn]\r
678 jz rpack1 ; Yes, then go start over.\r
679 sta temp1 ;Save the message type.\r
680 sta packet+3 ;Save in packet\r
681 add c\r
682 mov c,a ;Add the character to the checksum.\r
683 mvi a,0 ;Clear A\r
684 adc b ;Get high order portion of checksum\r
685 mov b,a ;Copy back to B\r
686 lda argblk+1 ;Get the number of data characters.\r
687 sta temp2\r
688 lxi h,data ;Point to the data buffer.\r
689 shld datptr\r
690rpack2: lda temp2\r
691 sui 1 ;Any data characters?\r
692 jm rpack3 ; If not go get the checksum.\r
693 sta temp2\r
694 call getchr ;Get a character.\r
695 jmp r ; Hit end of line, return bad.\r
696 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
697 cmp m ;[gnn]\r
698 jz rpack1 ; Yes, then go start over.\r
699 lhld datptr\r
700 mov m,a ;Put the char into the packet.\r
701 inx h ;Point to the next character.\r
702 shld datptr\r
703 add c\r
704 mov c,a ;Add the character to the checksum.\r
705 mvi a,0 ;Clear A\r
706 adc b ;Get high order portion of checksum\r
707 mov b,a ;Copy back to B\r
708 jmp rpack2 ;Go get another.\r
709\r
710rpack3: call getchr ;Get a character.\r
711 jmp r ; Hit end of line, return bad.\r
712 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
713 cmp m ;[gnn]\r
714 jz rpack1 ; Yes, then go start over.\r
715 sui ' ' ;Turn the char back into a number.\r
716 sta temp3\r
717;Determine type of checksum\r
718\r
719 lda curchk ;Get the current checksum type\r
720 cpi '2' ;1, 2 or 3 character?\r
721 jz rpack4 ;If zero, 2 character\r
722 jnc rpack5 ;Go handle 3 character\r
723 mov a,c ;Get the character total.\r
724 ani 0C0H ;Turn off all but the two high order bits.\r
725 ;Shift them into the low order position.\r
726 rlc ;Two left rotates same as six rights\r
727 rlc ; . . .\r
728 add c ;Add it to the old bits.\r
729 ani 3FH ;Turn off the two high order bits. (MOD 64)\r
730 mov b,a\r
731 lda temp3 ;Get the real received checksum.\r
732 cmp b ;Are they equal?\r
733 jz rpack7 ;If so, proceed.\r
734rpack9: call updrtr ;If not, update the number of retries.\r
735 ret ;Return error.\r
736\r
737;Here for three character CRC-CCITT\r
738\r
739rpack5: lhld datptr ;Get the address of the data\r
740 mvi m,0 ;Store a zero in the buffer to terminate packet\r
741 lxi h,packet+1 ;Point at start of checksummed region\r
742 call crcclc ;Calculate the CRC\r
743 mov c,e ;Save low order half for later\r
744 mov b,d ;Also copy high order\r
745 mov a,d ;Get high byte\r
746 rlc ;Want high four bits\r
747 rlc ; . . .\r
748 rlc ;And shift two more\r
749 rlc ; . . .\r
750 ani 0FH ;Keep only 4 bits\r
751 mov d,a ;Back into D\r
752 lda temp3 ;Get first value back\r
753 cmp d ;Correct?\r
754 jnz rpack9 ;No, punt\r
755 call getchr ;Get a character.\r
756 jmp r ; Hit end of line, return bad.\r
757 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
758 cmp m ;[gnn]\r
759 jz rpack1 ; Yes, then go start over.\r
760 sui ' ' ;Remove space offset\r
761 sta temp3 ;Store for later check\r
762 ;...\r
763\r
764;Here for a two character checksum and last two characters of CRC\r
765\r
766rpack4: mov a,b ;Get high order portion\r
767 ani 0FH ;Only four bits\r
768 rlc ;Shift up two bits\r
769 rlc ; . . .\r
770 mov b,a ;Save back in B\r
771 mov a,c ;Get low order\r
772 rlc ;move two high bits to low bits\r
773 rlc ; . . .\r
774 ani 03H ;Save only low two bits\r
775 ora b ;Get other 4 bits\r
776 mov b,a ;Save back in B\r
777 lda temp3 ;Get this portion of checksum\r
778 cmp b ;Check first half\r
779 jnz rpack9 ;If bad, go give up\r
780 call getchr ;Get a character.\r
781 jmp r ; Hit end of line, return bad.\r
782 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
783 cmp m ;[gnn]\r
784 jz rpack1 ; Yes, then go start over.\r
785 sui ' ' ;Remove space offset\r
786 mov b,a ;Save in safe place\r
787 mov a,c ;Get low 8 bits of checksum\r
788 ani 3FH ;Keep only 6 bits\r
789 cmp b ;Correct value\r
790 jnz rpack9 ;Bad, give up\r
791rpack7: lhld datptr\r
792 mvi m,0 ;Put a null at the end of the data.\r
793 lda temp1 ;Get the type.\r
794 jmp rskp\r
795;\f\r
796; inpkt - receive and buffer packet\r
797; returns: nonskip if error (timeout)\r
798; skip if success; packet starts at recpkt (which holds the SOH)\r
799; and is terminated by a null.\r
800; console is selected in either case.\r
801; called by: rpack\r
802\r
803inpkt: lxi h,recpkt ;Point to the beginning of the packet.\r
804 shld pktptr\r
805inpkt1: call inchr ;Get first character\r
806 jmp r ;Return failure\r
807 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
808 cmp m ;[gnn]\r
809 jnz inpkt1 ;if not, ignore leading junk\r
810 jmp inpkt3 ;else go put it in packet\r
811\r
812inpkt2: call inchr ;Get a character.\r
813 jmp r ; Return failure.\r
814 lxi h,rcvsop ;[gnn] Is it receive start-of-pkt char.\r
815 cmp m ;[gnn]\r
816 jnz inpkt3 ;if not continue\r
817 lxi h,recpkt ;else throw away what we've got so far\r
818 shld pktptr ;\r
819inpkt3: lhld pktptr ;\r
820 mov m,a ;Put the char in the packet.\r
821 inx h\r
822 shld pktptr\r
823 mov b,a\r
824 lxi d,-recpkx ;Start over if packet buffer overflow\r
825 dad d ;\r
826 jc inpkt ;buffer overflow\r
827 lda reol ;Get the EOL char.\r
828 cmp b\r
829 jnz inpkt2 ;If not loop for another.\r
830;[gnn] *** added by Godfrey Nix Nottingham University ***\r
831;[gnn] to allow Kermit server to echo our packets back\r
832 lxi h,recpkt+3 ;[gnn] point to packet type\r
833 lda packet+3 ;[gnn] get the one we sent\r
834 cmp m ;[gnn] are they the same?\r
835 jz inpkt ;[gnn] yes, get another packet\r
836;[gnn] *** end of patch *****\r
837 ;...\r
838 ;...\r
839\r
840;Begin IBM change/fdc\r
841;This moved from OUTPK7 -- it appears that waiting until we're\r
842;ready to send a packet before looking for turnaround character\r
843;is long enough for it to get lost. Better to look now.\r
844\r
845 lda ibmflg ;Is this the IBM?\r
846 ora a\r
847 jz inpkt6 ;If not then proceed.\r
848 lda state ;Check if this is the Send-Init packet.\r
849 cpi 'S'\r
850 jz inpkt6 ;If so don't wait for the XON.\r
851inpkt5: call inchr ;Wait for the turn around char.\r
852 jmp inpkt6\r
853 cpi xon ;Is it the IBM turn around character?\r
854 jnz inpkt5 ;If not, go until it is.\r
855inpkt6: lhld pktptr ;Reload packet pointer\r
856;End IBM change/fdc.\r
857 dcx h ;Back up to end of line character\r
858 mvi m,0 ;Replace it with a null to stop rpack:\r
859 call selcon ;We've got the packet. Return to console.\r
860\r
861 lda dbgflg ; Is debugging enabled?\r
862 ora a\r
863 jz inpkt7\r
864 inx h ; Point to next char.\r
865 lda quietd ; a quiet display?\r
866 ana a\r
867 jnz inpkt7 ; so dont say a thing\r
868 call rppos ; position cursor\r
869 lxi h,recpkt+1 ; print the packet\r
870 call dmptxt\r
871\r
872 lda prnflg ; is the printer on too?\r
873 ana a\r
874 jz inpkt7\r
875 lxi h,rstatm ; print state\r
876 call printm ; dumptext but to printer\r
877 lda state\r
878 mov e,a\r
879 call outprn\r
880 lxi h,princr ; cr lf to printer\r
881 call printm\r
882 lxi h,rpackm\r
883 call printm\r
884 lxi h,recpkt+1\r
885 call printm\r
886 lxi h,princr\r
887 call printm\r
888 lxi h,princr\r
889 call printm\r
890\r
891\r
892inpkt7: lxi h,recpkt\r
893 shld pktptr ;Save the packet pointer.\r
894 jmp rskp ;If so we are done.\r
895\r
896; getchr - get next character from buffered packet.\r
897; returns nonskip at end of packet.\r
898; called by: rpack\r
899\r
900getchr: lhld pktptr ;Get the packet pointer.\r
901 mov a,m ;Get the char.\r
902 inx h\r
903 shld pktptr\r
904 ora a ;Is it the null we put at the end of the packet?\r
905 jnz rskp ;If not return retskp.\r
906 ret ;If so return failure.\r
907;\f\r
908;\r
909; inchr - character input loop for file transfer\r
910; returns: nonskip if timeout or character typed on console\r
911; (console selected)\r
912; skip with character from modem in A (parity stripped\r
913; if necessary; modem selected)\r
914; preserves bc, de, hl in either case.\r
915; called by: inpkt\r
916\r
917inchr: push h ; save hl and bc\r
918 push b\r
919 lhld timout ;Get initial value for timeout\r
920 shld timval ;[jd] \r
921inchr0: call selmdm ;select modem\r
922 call inpmdm ;Try to get a character from the modem\r
923 ora a\r
924 jz inchr2 ;if zero, nothing there.\r
925 mov b,a\r
926 lda parity ;Is the parity none?\r
927 cpi parnon\r
928 mov a,b\r
929 jz inchr1 ;If so just return.\r
930 ani 7FH ;Turn off the parity bit.\r
931inchr1: pop b ;restore registers\r
932 pop h\r
933 jmp rskp ;take skip return, character in A\r
934\r
935inchr2: call selcon ;select console\r
936 call inpcon ; Try to get a character from the console\r
937 ora a\r
938 jz inchr6 ;If not go do timer thing\r
939 cpi cr ;Is it a carriage return?\r
940 jz inchr4 ;If so return\r
941 cpi ('Z'-100O) ;Control-Z?\r
942 jz inchr5 ;Yes, go flag it\r
943 cpi ('C'-100O) ;Control-C?\r
944 jz inchr7 ;re-enter, he wants to get out\r
945 cpi ('X'-100O) ;Control-X?\r
946 jnz inchr6 ;No, ignore it. do timer thing.\r
947inchr5: adi 100O ;Convert to printing range\r
948 sta czseen ;Flag we saw a control-Z\r
949 jmp inchr6 ;[MF] and do timer thing\r
950inchr4: pop b ; restore registers\r
951 pop h\r
952 ret ;And return\r
953\r
954inchr6: lda timflg ;[jd] pick up timer flag\r
955 ora a ;[jd] are we allowed to use timer?\r
956 jz inchr0 ;[jd] no, don't time out\r
957 lhld timval ; decrement fuzzy time-out\r
958 dcx h ;\r
959 shld timval ;((timout-1) * loop time)\r
960 mov a,h ;(Retry if not time-out)\r
961 ora l ;\r
962 jnz inchr0 ;\r
963 call updrtr ;Count as retry (?)\r
964 pop b ;restore registers\r
965 pop h\r
966 ret ;and return to do retry\r
967\r
968inchr7: call clrtop ;[hh] clear screen and home cursor\r
969 lda takflg ;[MF]Take-file in progress?\r
970 ani 1 ;[MF]...\r
971 cnz closet ;[MF]Yes, close it and reset TAKE-flag\r
972 ;[MF]so all processing is halted\r
973 jmp kermit ;[hh] then re-enter kermit\r
974\r
975;\f\r
976; CRCCLC - Routine to calculate a CRC-CCITT for a string.\r
977;\r
978; This routine will calculate a CRC using the CCITT polynomial for\r
979; a string.\r
980;\r
981; call with: HL/ Address of null-terminated string\r
982; 16-bit CRC value is returned in DE.\r
983; Registers BC and HL are preserved.\r
984;\r
985; called by: spack, rpack\r
986\r
987crcclc: push h ;Save HL\r
988 push b ;And BC\r
989 lxi d,0 ;Initial CRC value is 0\r
990\r
991crccl0: mov a,m ;Get a character\r
992 ora a ;Check if zero\r
993 jz crccl1 ;If so, all done\r
994 push h ;Save the pointer\r
995 xra e ;Add in with previous value\r
996 mov e,a ;Get a copy\r
997 ani 0FH ;Get last 4 bits of combined value\r
998 mov c,a ;Get into C\r
999 mvi b,0 ;And make high order zero\r
1000 lxi h,crctb2 ;Point at low order table\r
1001 dad b ;Point to correct entry\r
1002 dad b ; . . .\r
1003 push h ;Save the address\r
1004 mov a,e ;Get combined value back again\r
1005 rrc ;Shift over to make index\r
1006 rrc ; . . .\r
1007 rrc ; . . .\r
1008 ani 1EH ;Keep only 4 bits\r
1009 mov c,a ;Set up to offset table\r
1010 lxi h,crctab ;Point at high order table\r
1011 dad b ;Correct entry\r
1012 mov a,m ;Get low order portion of entry\r
1013 xra d ;XOR with previous high order half\r
1014 inx h ;Point to high order byte\r
1015 mov d,m ;Get into D\r
1016 pop h ;Get back pointer to other table entry\r
1017 xra m ;Include with new high order half\r
1018 mov e,a ;Copy new low order portion\r
1019 inx h ;Point to other portion\r
1020 mov a,m ;Get the other portion of the table entry\r
1021 xra d ;Include with other high order portion\r
1022 mov d,a ;Move back into D\r
1023\r
1024 pop h ;And H\r
1025 inx h ;Point to next character\r
1026 jmp crccl0 ;Go get next character\r
1027\r
1028crccl1: pop b ;Restore B\r
1029 pop h ;And HL\r
1030\r
1031 ret ;And return, DE=CRC-CCITT\r
1032\r
1033CRCTAB: DW 00000H\r
1034 DW 01081H\r
1035 DW 02102H\r
1036 DW 03183H\r
1037 DW 04204H\r
1038 DW 05285H\r
1039 DW 06306H\r
1040 DW 07387H\r
1041 DW 08408H\r
1042 DW 09489H\r
1043 DW 0A50AH\r
1044 DW 0B58BH\r
1045 DW 0C60CH\r
1046 DW 0D68DH\r
1047 DW 0E70EH\r
1048 DW 0F78FH\r
1049\r
1050CRCTB2: DW 00000H\r
1051 DW 01189H\r
1052 DW 02312H\r
1053 DW 0329BH\r
1054 DW 04624H\r
1055 DW 057ADH\r
1056 DW 06536H\r
1057 DW 074BFH\r
1058 DW 08C48H\r
1059 DW 09DC1H\r
1060 DW 0AF5AH\r
1061 DW 0BED3H\r
1062 DW 0CA6CH\r
1063 DW 0DBE5H\r
1064 DW 0E97EH\r
1065 DW 0F8F7H\r
1066;\f\r
1067; This is where we go if we get an error during a protocol communication.\r
1068; error prints the error packet on line 6 or so, and aborts the\r
1069; transfer.\r
1070; called by: rinit, rfile, rdata, sinit, sfile, sdata, seof, seot\r
1071; error1 print CRLF followed by the error packet.\r
1072; called by: finish, logout\r
1073; error2 just prints the error packet.\r
1074; error3 positions cursor and prints error message specified in DE.\r
1075; called by: rinit, rfile, rdata, sinit, sfile, sdata, seof,\r
1076; seot, parwrn, gofil, outbuf\r
1077\r
1078error: lda quietd ; a quiet display?\r
1079 ana a\r
1080 jnz error0 ; so dont say a thing\r
1081 lda remtxt ;[MF]Doing a remote command?\r
1082 ora a ;[MF]...\r
1083 jnz error0 ;[MF]Yes, don't position cursor\r
1084 call screrr ;Position the cursor.\r
1085error0: mvi a,'A' ;Set the state to abort.\r
1086 sta state\r
1087 jmp error2\r
1088\r
1089error1: lxi d,crlf ;Print a CRLF.\r
1090 lda quietd ; a quiet display?\r
1091 ana a\r
1092 jnz error2 ; so dont say a thing\r
1093 call prtstr\r
1094error2: lda argblk+1 ;Get the length of the data.\r
1095 mov c,a\r
1096 mvi b,0 ;Put it into BC\r
1097 lxi h,data ;Get the address of the data.\r
1098 dad b ;Get to the end of the string.\r
1099 mvi m,'$' ;Put a dollar sign at the end.\r
1100 lxi d,data ;Print error message\r
1101 lda remtxt ;[MF]Doing a remote command?\r
1102 ora a ;[MF]...\r
1103 jnz errr2a ;[MF]Yes, print message, quiet or not!\r
1104 lda quietd ; a quiet display?\r
1105 ana a\r
1106 rnz ; so dont say a thing\r
1107errr2a: call prtstr\r
1108 ret\r
1109\r
1110error3: lda quietd ; a quiet display?\r
1111 ana a\r
1112 rnz ; so dont say a thing\r
1113 lda remtxt ;[MF]Doing a remote command?\r
1114 ora a ;[MF]...\r
1115 jnz err3a ;[MF]Yes, don't position cursor\r
1116 push d ;Save the pointer to the message.\r
1117 call screrr ;Position the cursor.\r
1118 pop d ;Get the pointer back.\r
1119err3a: call prtstr ;Print error message\r
1120 ret\r
1121;\f\r
1122; Set up for file transfer.\r
1123; called by read, send.\r
1124\r
1125init: lxi d,version ; point at Kermit's version string\r
1126 lda quietd ; a quiet display?\r
1127 ana a\r
1128 jnz init1 ; so dont say a thing\r
1129 call sysscr ; fix up screen\r
1130init1: call selmdm ; select modem\r
1131 call flsmdm ; purge any pending data\r
1132 call selcon ; select console again.\r
1133 ret\r
1134\r
1135; Set state to ABORT\r
1136; called by: rinit, rfile, rdata, sinit, sfile, sdata, seof, seot,\r
1137; nak, ackp\r
1138\r
1139abort: mvi a,'A' ;Otherwise abort.\r
1140 sta state\r
1141 ret\r
1142\r
1143; nak - send NAK packet\r
1144; here from: rinit, rfile, rdata\r
1145; nak0 - update retry count and send NAK packet\r
1146; here from: rinit, rfile, rdata, tryagn\r
1147\r
1148nak0: call updrtr ;Update number of retries.\r
1149nak: lda pktnum ;Get the packet number we're waiting for.\r
1150 sta argblk\r
1151 xra a ;No data.\r
1152 sta argblk+1\r
1153 mvi a,'N' ;NAK that packet.\r
1154 call spack\r
1155 jmp abort ; Give up.\r
1156 ret ;Go around again.\r
1157\r
1158; increment and display retry count\r
1159; called by: rfile, sinit, sfile, sdata, seof, seot,\r
1160; nak, rpack, inchr, tryagn\r
1161\r
1162updrtr: lhld numrtr\r
1163 inx h ;Increment the number of retries\r
1164 shld numrtr\r
1165 lda remtxt ;[MF]Doing a remote server command?\r
1166 ora a ;[MF]...\r
1167 rnz ;[MF]Yes, keep mum\r
1168 lda quietd ; a quiet display?\r
1169 ana a\r
1170 rnz ; so dont say a thing\r
1171 call scrnrt ;Position cursor\r
1172 lhld numrtr ;[MF]\r
1173call nout ;Write the number of retries.\r
1174 ret\r
1175\r
1176; [jd] this routine prints parity warnings. All registers are\r
1177; saved except for a.\r
1178; called by: sdata\r
1179\r
1180parwrn: push b\r
1181 push d\r
1182 push h\r
1183 lxi d,inms25\r
1184 call error3\r
1185 pop h\r
1186 pop d\r
1187 pop b\r
1188 ret\r
1189;[jd] end of addition\r
1190\r
1191; print message in status field. address of message is in DE.\r
1192; called by: read, send\r
1193\r
1194finmes: lda quietd ; a quiet display?\r
1195 ana a\r
1196 jz finme0 ; so do usual stuff\r
1197 push d ;[MF]Save pointer to completion message\r
1198 call prcrlf ; best do a new line\r
1199 pop d ;[MF]Restore completion message pointer\r
1200 call prtstr ; and send message\r
1201 mvi e,space ; send a space or two\r
1202 mvi c,dconio\r
1203 push b\r
1204 push d\r
1205 call bdos\r
1206 pop d\r
1207 pop b\r
1208 call bdos\r
1209 ret ; and exit back\r
1210;\r
1211;else for screaming screens...\r
1212\r
1213finme0: push d ;Save message.\r
1214 call scrst ;Position cursor\r
1215 pop d ;Print the termination message\r
1216 call prtstr\r
1217 ret ; may not want this **************\r
1218\r
1219 mvi c,4 ;[2] copy across user no and drive\r
1220 lxi h,kerm1 ;[2] as we have the text already\r
1221finme1: mov e,m\r
1222 push h ;[2] conout probably destroys these\r
1223 push b\r
1224 call conout\r
1225 pop b\r
1226 pop h\r
1227 inx h ;[2] next character\r
1228 dcr c ;[2] ah, but have we done?\r
1229 jnz finme1 ;[2] nope\r
1230 lxi d,spac15 ;[2] send 15 spaces (clears previous filename)\r
1231 call prtstr ;[2]\r
1232 call scrend ;Position cursor for prompt\r
1233 ret\r
1234\r
1235; Compare expected packet number against received packet number.\r
1236; return with flags set (Z = packet number valid)\r
1237; called by: rfile, rdata, sinit, sfile, sdata, seof, seot\r
1238\r
1239compp: lda pktnum ;Get the packet Nr.\r
1240 mov b,a\r
1241 lda argblk\r
1242 cmp b\r
1243 ret\r
1244\r
1245; Increment the packet number, modulo 64.\r
1246; called by: rinit, rfile, rdata, sinit, sfile, sdata, seof, seot\r
1247\r
1248countp: inr a ;Increment packet Nr.\r
1249 ani 3FH ;Turn off the two high order bits\r
1250 sta pktnum ;Save modulo 64 of number\r
1251 lhld numpkt\r
1252 inx h ;Increment Nr. of packets\r
1253 shld numpkt\r
1254 ret\r
1255\r
1256; Send an ACK-packet\r
1257; called by: rfile, rdata, tryagn\r
1258\r
1259ackp: xra a\r
1260 sta numtry ;Reset number of retries\r
1261 sta argblk+1 ;No data. (The packet number is in argblk)\r
1262 mvi a,'Y' ;Acknowledge packet\r
1263 call spack ;Send packet\r
1264 jmp abort\r
1265 ret\r
1266\r
1267; ?\r
1268; called with A/ current retry count\r
1269; called by: rfile, rdata\r
1270\r
1271tryagn: inr a ;Increment it.\r
1272 sta oldtry ;Save the updated number of tries.\r
1273 lda pktnum ;Get the present packet number.\r
1274 dcr a ;Decrement\r
1275 ani 3FH ; modulo 64\r
1276 mov b,a\r
1277 lda argblk ;Get the packet's number\r
1278 cmp b ;Is the packet's number one less than now?\r
1279 jnz nak0 ;No, NAK it and try again.\r
1280 call updrtr ;Update the number of retries.\r
1281 call ackp\r
1282 ret\r
1283\r
1284; Output a null-terminated string to the console. We assume that the\r
1285; console has been selected. Called with HL = address of string.\r
1286; called by: spack, inpkt\r
1287\r
1288dmptxt: mov a,m ; get character from string\r
1289 ora a\r
1290 rz ; done if null\r
1291 push h ; save string address\r
1292 mov e,a ; move character to E for outcon\r
1293 call outcon ; output character to console\r
1294 pop h ; restore string address\r
1295 inx h ; point past printed character\r
1296 jmp dmptxt ; go output rest of string\r
1297\r
1298\r
1299; Output a null-terminated string to the PRINTER We assume that the\r
1300; console has been selected. Called with HL = address of string.\r
1301; called by: spack, inpkt\r
1302\r
1303printm: mov a,m ; get character from string\r
1304 ora a\r
1305 rz ; done if null\r
1306 push h ; save string address\r
1307 mov e,a ; move character to E for outcon\r
1308 call outprn ; output character to printer\r
1309 pop h ; restore string address\r
1310 inx h ; point past printed character\r
1311 jmp printm ; go output rest of string\r
1312\r
1313\r
1314;\f\r
1315; test if character in A is the start of header character. We get\r
1316; the start of packet character from sohchr, which can be SET\r
1317tstsoh: push b ; save these registers for a bit\r
1318 mov c,a ; we have to test if this is the character\r
1319 lda sohchr\r
1320 cmp c ; if zero, then it is\r
1321 mov a,c ; restore accumulator but not flags\r
1322 pop b\r
1323 ret ; return with flags set\r
1324;\r
1325\r
1326\r
1327; Little code to allow some expansion of code without changing\r
1328; every futher address, only up to the end of this file.\r
1329; TO BE REMOVED FRO RELEASE!\r
1330\r
1331; org ($+100h) AND 0FF00H\r
1332\r
1333\r
1334IF lasm\r
1335 LINK CPSREM\r
1336ENDIF;lasm\r