WXMODEM.MOD 15 KB

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