XMODEM.MOD 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. (* Release 3.10 *)
  2. (*-------------------------------------------------------------------------*
  3. * *
  4. * XMODEM.MOD - COMMS Toolkit XMODEM protocol *
  5. * *
  6. * COPYRIGHT (C) 1988..1992 Clarion Software Corporation. *
  7. * All Rights Reserved *
  8. * *
  9. *--------------------------------------------------------------------------*)
  10. IMPLEMENTATION MODULE XModem;
  11. IMPORT Lib,FTSupport,CommUtil,FIO,Str,RS232;
  12. FROM FTSupport IMPORT ACK,CAN,CRCREQ,EOT,NAK,SOH,STX;
  13. VAR
  14. f : FIO.File;
  15. Response : CHAR;
  16. CRCCheck,
  17. ResponseWaiting : BOOLEAN;
  18. LastBlockNo,BlockNo,
  19. BlockSize : CARDINAL;
  20. (*..................................................*)
  21. PROCEDURE InitVars(VAR Filename:ARRAY OF CHAR);
  22. BEGIN
  23. FTSupport.Errors:=0;
  24. FTSupport.LastMessage:='';
  25. FTSupport.XferMode := 'CRC';
  26. FTSupport.Transferred:=0;
  27. FTSupport.Aborted := FALSE;
  28. FTSupport.SizeInBytes:=0;
  29. Str.Copy(FTSupport.FileSpec,Filename);
  30. BlockNo:=1;
  31. LastBlockNo:=0FFFFH;
  32. BlockSize:=128;
  33. CRCCheck:=TRUE;
  34. END InitVars;
  35. (*...............................................*)
  36. PROCEDURE ReceiveData():CARDINAL;
  37. VAR
  38. c : CHAR;
  39. RxBlk,CRC,RxCRC,
  40. CheckSum,Result,
  41. Cnt,CRCIndex : CARDINAL;
  42. RxState : (Blk,Compl,Data,Chk,CRCH,CRCL,Flushing);
  43. BEGIN
  44. (* Already had the first character SOH or STX *)
  45. RxState:=Blk;
  46. CRC:=0;
  47. CheckSum:=0;
  48. Cnt:=0;
  49. Result:=0;
  50. LOOP
  51. IF FTSupport.Aborted THEN
  52. RETURN(128+6);
  53. END;
  54. IF NOT RS232.SerialRead(c,50) THEN
  55. IF RxState=Flushing THEN
  56. RETURN(Result);
  57. ELSE
  58. FTSupport.LastMessage := 'Timeout';
  59. RETURN(3);
  60. END;
  61. END;
  62. CASE RxState OF
  63. Blk : RxBlk := ORD(c);
  64. RxState := Compl; |
  65. Compl : IF 255-ORD(c)<>RxBlk THEN
  66. Result:=11;
  67. FTSupport.LastMessage:='Bad Block No';
  68. RxState:=Flushing;
  69. ELSIF RxBlk=LastBlockNo THEN
  70. Result := 15;
  71. RxState := Data;
  72. ELSIF RxBlk<>BlockNo THEN
  73. Result := 128+10;
  74. FTSupport.LastMessage := 'Sequence Error';
  75. RxState := Flushing;
  76. ELSE
  77. RxState := Data;
  78. END; |
  79. Data : FTSupport.FBuff[Cnt] := c;
  80. IF CRCCheck THEN
  81. CRCIndex := CARDINAL(BITSET(CRC>>8)/BITSET(ORD(c)));
  82. CRC := CARDINAL(BITSET(FTSupport.CRCTable[CRCIndex])/BITSET(CRC<<8))
  83. ELSE
  84. CheckSum := (CheckSum+ORD(c)) MOD 100H;
  85. END;
  86. INC(Cnt);
  87. IF Cnt=BlockSize THEN
  88. IF CRCCheck THEN
  89. RxState:=CRCH;
  90. ELSE
  91. RxState:=Chk;
  92. END;
  93. END; |
  94. Chk : IF ORD(c)=CheckSum THEN
  95. RETURN Result
  96. ELSE
  97. Result := 8;
  98. FTSupport.LastMessage := 'Bad Checksum';
  99. RxState := Flushing;
  100. END; |
  101. CRCH : RxCRC := ORD(c)<<8;
  102. RxState := CRCL; |
  103. CRCL : RxCRC := RxCRC+ORD(c);
  104. IF CRC=RxCRC THEN
  105. RETURN Result
  106. ELSE
  107. Result := 9;
  108. FTSupport.LastMessage := 'Bad CRC';
  109. RxState := Flushing;
  110. END; |
  111. Flushing : (* do nothing *) |
  112. END; (* case *)
  113. END; (* loop *)
  114. END ReceiveData;
  115. (*...............................................*)
  116. PROCEDURE XMReceive():CARDINAL;
  117. VAR
  118. c : CHAR;
  119. EOTCount,Result : CARDINAL;
  120. IncomingData,
  121. Negotiating,
  122. EndOfFile,
  123. Skippit : BOOLEAN;
  124. BEGIN
  125. Negotiating:=TRUE;
  126. EOTCount:=0;
  127. Skippit:=FALSE;
  128. EndOfFile:=FALSE;
  129. REPEAT
  130. IncomingData := FALSE;
  131. REPEAT
  132. FTSupport.UpdateStatus;
  133. IF FTSupport.Aborted THEN
  134. RETURN(6);
  135. END;
  136. IF NOT Skippit THEN
  137. RS232.SerialWrite(Response,1);
  138. END;
  139. Skippit := FALSE;
  140. LOOP
  141. IF RS232.SerialRead(c,100) THEN
  142. IF (c=SOH) OR (c=EOT) OR (c=STX) THEN
  143. FTSupport.LastMessage:='';
  144. Negotiating:=FALSE;
  145. IncomingData := TRUE;
  146. EXIT;
  147. END;
  148. ELSE
  149. Response := NAK;
  150. RS232.SerialWrite(Response,1);
  151. FTSupport.LastMessage := 'Timeout';
  152. INC(FTSupport.Errors);
  153. IF FTSupport.Errors>1 THEN
  154. IF Negotiating THEN
  155. RETURN(1);
  156. ELSE
  157. RETURN(2);
  158. END;
  159. END;
  160. EXIT;
  161. END;
  162. END;
  163. UNTIL IncomingData;
  164. IF c=EOT THEN
  165. FTSupport.LastMessage := 'End of File';
  166. INC(EOTCount);
  167. IF EOTCount=2 THEN
  168. EndOfFile := TRUE;
  169. Response:=ACK;
  170. RS232.SerialWrite(Response,1)
  171. ELSE
  172. Response:=NAK; (* NAK first EOT in case it was spurious *)
  173. END
  174. ELSE
  175. EOTCount:=0;
  176. IF (c=SOH) THEN
  177. BlockSize:=128;
  178. ELSE
  179. BlockSize:=1024;
  180. END;
  181. Result := ReceiveData();
  182. IF Result=0 THEN
  183. (* ACK a good block immediately so that the background *)
  184. (* receiver can be getting the next block while we write *)
  185. (* this one to disk. *)
  186. Response := ACK;
  187. RS232.SerialWrite(Response,1);
  188. Skippit := TRUE;
  189. LastBlockNo := BlockNo;
  190. BlockNo := (BlockNo+1) MOD 100H;
  191. IF FTSupport.SizeInBytes>0 THEN
  192. IF FTSupport.Transferred+LONGCARD(BlockSize)>FTSupport.SizeInBytes THEN
  193. BlockSize := CARDINAL(FTSupport.SizeInBytes-FTSupport.Transferred);
  194. END;
  195. END;
  196. FIO.WrBin(f,FTSupport.FBuff,BlockSize);
  197. IF FIO.IOresult()<>0 THEN
  198. FTSupport.LastMessage := 'Disk Write Error';
  199. FTSupport.UpdateStatus;
  200. RETURN(4);
  201. END;
  202. FTSupport.Transferred := FTSupport.Transferred+LONGCARD(BlockSize);
  203. FTSupport.Errors:=0;
  204. FTSupport.LastMessage:='';
  205. FTSupport.UpdateStatus;
  206. ELSIF Result=15 THEN
  207. (* Sender resent previous block - ACK and ignore *)
  208. Response := ACK;
  209. FTSupport.Errors := 0;
  210. FTSupport.LastMessage := '';
  211. FTSupport.UpdateStatus;
  212. ELSE
  213. INC(FTSupport.Errors);
  214. FTSupport.UpdateStatus;
  215. IF Result>127 (*fatal*) THEN
  216. FTSupport.Aborted := TRUE;
  217. RETURN(Result MOD 100H)
  218. END;
  219. Response := NAK;
  220. IF FTSupport.Errors>5 (* too many *) THEN
  221. RETURN(Result);
  222. END;
  223. END;
  224. END;
  225. UNTIL EndOfFile OR FTSupport.Aborted;
  226. IF FTSupport.Aborted THEN
  227. RETURN(6);
  228. ELSE
  229. RETURN(0);
  230. END;
  231. END XMReceive;
  232. (*...............................................*)
  233. PROCEDURE XModemReceive(VAR Filename:ARRAY OF CHAR):CARDINAL;
  234. VAR
  235. Result : CARDINAL;
  236. HookSave : BOOLEAN;
  237. BEGIN
  238. InitVars(Filename);
  239. FTSupport.CompleteFilename;
  240. f := FIO.Create(FTSupport.FileSpec);
  241. IF FIO.IOresult()=0 THEN
  242. HookSave := RS232.Hooked;
  243. RS232.Hooked := FTSupport.HookOnFT;
  244. FTSupport.OpenStatusWindow('XModem Download');
  245. FTSupport.NewFilename;
  246. Response := CRCREQ;
  247. Result := XMReceive();
  248. IF Result=1 THEN
  249. CRCCheck:=FALSE;
  250. FTSupport.XferMode:='CHK';
  251. Response := NAK;
  252. Result := XMReceive();
  253. END;
  254. RS232.Hooked := HookSave;
  255. FIO.Close(f);
  256. IF FTSupport.Aborted THEN
  257. FTSupport.Cancel;
  258. END;
  259. FTSupport.CloseStatusWindow;
  260. RETURN Result;
  261. ELSE
  262. CommUtil.ErrorMessage('Could not open file!');
  263. RETURN 12;
  264. END;
  265. END XModemReceive;
  266. (*..................................................*)
  267. PROCEDURE GetResponse(VAR c:CHAR):CARDINAL;
  268. VAR
  269. CANCount : CARDINAL;
  270. GotResponse : BOOLEAN;
  271. BEGIN
  272. CANCount := 0;
  273. REPEAT
  274. IF FTSupport.AbortRequested() THEN
  275. RETURN(6);
  276. END;
  277. IF ResponseWaiting THEN
  278. c:=Response;
  279. GotResponse:=TRUE;
  280. ResponseWaiting:=FALSE
  281. ELSE
  282. GotResponse := RS232.SerialRead(c,100);
  283. END;
  284. IF GotResponse THEN
  285. IF c=CAN THEN
  286. INC(CANCount);
  287. IF CANCount=3 THEN
  288. RETURN(13);
  289. END;
  290. END;
  291. ELSE
  292. FTSupport.LastMessage := 'Timeout';
  293. INC(FTSupport.Errors);
  294. FTSupport.UpdateStatus;
  295. IF FTSupport.Errors=5 THEN
  296. RETURN(2);
  297. END;
  298. END;
  299. UNTIL GotResponse AND ((c=NAK) OR (c=ACK) OR (c=CRCREQ));
  300. FTSupport.LastMessage := '';
  301. FTSupport.UpdateStatus;
  302. RETURN 0;
  303. END GetResponse;
  304. (*..................................................*)
  305. PROCEDURE SendBlock(VAR c:CHAR):CARDINAL;
  306. VAR
  307. Result,i,Lnth,CRC,
  308. CheckSum,CRCIndex : CARDINAL;
  309. Header : ARRAY[0..2] OF CHAR;
  310. BEGIN
  311. CRC:=0;
  312. CheckSum:=0;
  313. Lnth:=BlockSize;
  314. IF Lnth=128 THEN
  315. Header[0]:=SOH;
  316. ELSE
  317. Header[0]:=STX;
  318. END;
  319. Header[1]:=CHR(BlockNo);
  320. Header[2]:=CHR(255-BlockNo);
  321. RS232.SerialWrite(Header,3);
  322. IF CRCCheck THEN
  323. FOR i:=0 TO Lnth-1 DO
  324. RS232.SerialWrite(FTSupport.FBuff[i],1);
  325. CRCIndex := CARDINAL(BITSET(CRC>>8)/BITSET(ORD(FTSupport.FBuff[i])));
  326. CRC := CARDINAL(BITSET(FTSupport.CRCTable[CRCIndex])/BITSET(CRC<<8))
  327. END;
  328. FTSupport.FBuff[Lnth] := CHR(CRC DIV 100H);
  329. FTSupport.FBuff[Lnth+1] := CHR(CRC MOD 100H);
  330. RS232.SerialWrite(FTSupport.FBuff[Lnth],2);
  331. INC(Lnth,2);
  332. ELSE
  333. FOR i:=0 TO Lnth-1 DO
  334. RS232.SerialWrite(FTSupport.FBuff[i],1);
  335. CheckSum := (CheckSum + ORD(FTSupport.FBuff[i])) MOD 100H;
  336. END;
  337. FTSupport.FBuff[Lnth] := CHR(CheckSum);
  338. RS232.SerialWrite(CHR(CheckSum),1);
  339. INC(Lnth);
  340. END;
  341. REPEAT
  342. Result := GetResponse(c);
  343. IF Result<>0 THEN
  344. RETURN(Result);
  345. END;
  346. IF c#ACK THEN
  347. FTSupport.LastMessage := 'Received NAK';
  348. INC(FTSupport.Errors);
  349. FTSupport.UpdateStatus;
  350. IF FTSupport.Errors=5 THEN
  351. RETURN(14);
  352. END;
  353. RS232.SerialWrite(Header,3);
  354. RS232.SerialWrite(FTSupport.FBuff,Lnth);
  355. END;
  356. UNTIL c=ACK;
  357. RETURN 0;
  358. END SendBlock;
  359. (*..................................................*)
  360. PROCEDURE GetStartChar(VAR c:CHAR):CARDINAL;
  361. VAR
  362. Result : CARDINAL;
  363. BEGIN
  364. REPEAT
  365. Result := GetResponse(c);
  366. IF Result<>0 THEN
  367. RETURN(Result);
  368. END;
  369. UNTIL (c=NAK) OR (c=CRCREQ);
  370. IF c=NAK THEN
  371. CRCCheck:=FALSE;
  372. FTSupport.XferMode:='CHK'
  373. END;
  374. RS232.FlushInBuf;
  375. RETURN 0;
  376. END GetStartChar;
  377. (*..................................................*)
  378. PROCEDURE XMSend():CARDINAL;
  379. VAR
  380. c : CHAR;
  381. Result,BytesRead,
  382. CANCount : CARDINAL;
  383. BEGIN
  384. Result := GetStartChar(c);
  385. IF Result<>0 THEN
  386. RETURN(Result);
  387. END;
  388. FTSupport.UpdateStatus;
  389. WHILE NOT FIO.EOF DO
  390. BytesRead := FIO.RdBin(f,FTSupport.FBuff,BlockSize);
  391. IF FIO.IOresult()<>0 THEN
  392. RETURN(5);
  393. END;
  394. IF BytesRead<BlockSize THEN
  395. Lib.Fill(ADR(FTSupport.FBuff[BytesRead]),BlockSize-BytesRead,CHR(26));
  396. END;
  397. FTSupport.Errors := 0;
  398. Result := SendBlock(c);
  399. IF Result<>0 THEN
  400. RETURN(Result);
  401. END;
  402. FTSupport.LastMessage := '';
  403. FTSupport.Transferred := FTSupport.Transferred+LONGCARD(BlockSize);
  404. BlockNo := (BlockNo+1) MOD 100H;
  405. FTSupport.Errors := 0;
  406. FTSupport.UpdateStatus;
  407. END;
  408. FTSupport.LastMessage := 'End of File';
  409. FTSupport.UpdateStatus;
  410. REPEAT
  411. REPEAT
  412. RS232.SerialWrite(EOT,1);
  413. Result := GetResponse(c);
  414. IF Result<>0 THEN
  415. RETURN(Result);
  416. END;
  417. UNTIL (c=NAK) OR (c=ACK);
  418. UNTIL c=ACK;
  419. RETURN 0;
  420. END XMSend;
  421. (*..................................................*)
  422. PROCEDURE XModemSend(VAR Filename:ARRAY OF CHAR):CARDINAL;
  423. VAR
  424. Result : CARDINAL;
  425. HookSave : BOOLEAN;
  426. BEGIN
  427. IF FIO.Exists(Filename) THEN
  428. HookSave := RS232.Hooked;
  429. RS232.Hooked := FTSupport.HookOnFT;
  430. InitVars(Filename);
  431. f := FIO.Open(Filename);
  432. FIO.EOF := FALSE;
  433. FTSupport.SizeInBytes := FIO.Size(f);
  434. FTSupport.OpenStatusWindow('XModem Upload');
  435. FTSupport.NewFilename;
  436. Result := XMSend();
  437. RS232.Hooked := HookSave;
  438. FTSupport.CloseStatusWindow;
  439. FIO.Close(f);
  440. RETURN Result;
  441. ELSE
  442. CommUtil.ErrorMessage('Could not open file!');
  443. RETURN 7
  444. END;
  445. END XModemSend;
  446. (*..................................................*)
  447. END XModem.
  448.