]>
Commit | Line | Data |
---|---|---|
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 | |
83 | pk2ver: 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 | |
90 | gofil: 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 | |
107 | gofil0: ;[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 | |
116 | gofil1: 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 | |
123 | gofil2: 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 | |
128 | gofl2a: 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 | |
140 | gofil3: 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 | |
152 | gofil4: 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 | |
161 | gofil6: 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 | |
166 | gofl6a: 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 | |
180 | gofil7: 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 | |
186 | gofi70: 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 | |
191 | gofi7a: ;[obs 8]\r | |
192 | \r | |
193 | call prtstr\r | |
194 | gofi7b: 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 | |
211 | gofi7h: 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 | |
223 | gofi7i: ;[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 | |
252 | gofi7c: 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 | |
263 | gofi7d:\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 | |
267 | gofi7z: 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 | |
288 | gofi7e: 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 | |
292 | gofi7f: 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 | |
305 | gofi7g: 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 | |
331 | gofl82: 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 | |
339 | gofil9: call makfil ; Create the file.\r | |
340 | jmp gofl91 ; Disk was full.\r | |
341 | jmp rskp ; Success.\r | |
342 | \r | |
343 | gofl91: 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 | |
350 | finish: 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 | |
359 | finsh1: lda numtry ;How many times have we tried?\r | |
360 | cpi maxtry ;Too many times?\r | |
361 | jm finsh3 ;No, try it.\r | |
362 | finsh2: lxi d,erms18 ;Say we couldn't do it.\r | |
363 | call prtstr\r | |
364 | jmp kermit ;Go home.\r | |
365 | \r | |
366 | finsh3: 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 | |
389 | logout: 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 | |
397 | logo: 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 | |
405 | logo1: lda numtry ;How many times have we tried?\r | |
406 | cpi maxtry ;Too many times?\r | |
407 | jm logo3 ;No, try it.\r | |
408 | logo2: lxi d,erms19 ;Say we couldn't do it.\r | |
409 | call prtstr\r | |
410 | ret ;Finished.\r | |
411 | \r | |
412 | logo3: 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 | |
447 | spack: 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 | |
480 | spack2: 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 | |
494 | spack3: 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 | |
512 | spack5: 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 | |
531 | spack4: 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 | |
550 | spack7: 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 | |
580 | spac7a: pop h ; restore address of end of packet\r | |
581 | spack8: 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 | |
587 | outpkt: 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 | |
590 | outpk2: 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 | |
601 | outpk6: lxi h,packet ; Point to the packet.\r | |
602 | outlup: 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 | |
618 | outpk8:\r | |
619 | inx h ; Increment the char pointer.\r | |
620 | jmp outlup\r | |
621 | \r | |
622 | outlud: 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 | |
637 | rpack: call inpkt ;Read up to the end-of-line character\r | |
638 | jmp r ; Return bad.\r | |
639 | rpack0: 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 | |
644 | rpack1: 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 | |
690 | rpack2: 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 | |
710 | rpack3: 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 | |
734 | rpack9: 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 | |
739 | rpack5: 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 | |
766 | rpack4: 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 | |
791 | rpack7: 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 | |
803 | inpkt: lxi h,recpkt ;Point to the beginning of the packet.\r | |
804 | shld pktptr\r | |
805 | inpkt1: 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 | |
812 | inpkt2: 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 | |
819 | inpkt3: 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 | |
851 | inpkt5: 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 | |
855 | inpkt6: 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 | |
892 | inpkt7: 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 | |
900 | getchr: 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 | |
917 | inchr: 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 | |
921 | inchr0: 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 | |
931 | inchr1: pop b ;restore registers\r | |
932 | pop h\r | |
933 | jmp rskp ;take skip return, character in A\r | |
934 | \r | |
935 | inchr2: 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 | |
947 | inchr5: 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 | |
950 | inchr4: pop b ; restore registers\r | |
951 | pop h\r | |
952 | ret ;And return\r | |
953 | \r | |
954 | inchr6: 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 | |
968 | inchr7: 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 | |
987 | crcclc: push h ;Save HL\r | |
988 | push b ;And BC\r | |
989 | lxi d,0 ;Initial CRC value is 0\r | |
990 | \r | |
991 | crccl0: 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 | |
1028 | crccl1: pop b ;Restore B\r | |
1029 | pop h ;And HL\r | |
1030 | \r | |
1031 | ret ;And return, DE=CRC-CCITT\r | |
1032 | \r | |
1033 | CRCTAB: 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 | |
1050 | CRCTB2: 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 | |
1078 | error: 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 | |
1085 | error0: mvi a,'A' ;Set the state to abort.\r | |
1086 | sta state\r | |
1087 | jmp error2\r | |
1088 | \r | |
1089 | error1: 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 | |
1094 | error2: 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 | |
1107 | errr2a: call prtstr\r | |
1108 | ret\r | |
1109 | \r | |
1110 | error3: 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 | |
1119 | err3a: 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 | |
1125 | init: 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 | |
1130 | init1: 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 | |
1139 | abort: 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 | |
1148 | nak0: call updrtr ;Update number of retries.\r | |
1149 | nak: 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 | |
1162 | updrtr: 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 | |
1173 | call 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 | |
1180 | parwrn: 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 | |
1194 | finmes: 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 | |
1213 | finme0: 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 | |
1221 | finme1: 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 | |
1239 | compp: 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 | |
1248 | countp: 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 | |
1259 | ackp: 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 | |
1271 | tryagn: 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 | |
1288 | dmptxt: 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 | |
1303 | printm: 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 | |
1317 | tstsoh: 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 | |
1334 | IF lasm\r | |
1335 | LINK CPSREM\r | |
1336 | ENDIF;lasm\r |