home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 04 / proto < prev    next >
Text File  |  1989-03-27  |  19KB  |  634 lines

  1. _C PROGRAMMING COLUMN_
  2. by Al Stevens
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* ------- the hook to the phone directory ---------- */
  8. extern void phdirectory(void);
  9. static void (*phone_directory)(void) = phdirectory;
  10. /* ------- the hook to script processors ---------- */
  11. void (*script_processor)(void);
  12. /* ------- hooks to file transfer protocols --------- */
  13. extern int select_protocol(void);
  14. static int (*select_transfer_protocol)(void) = select_protocol;
  15. /* ----- up to five upload function pointers ----- */
  16. void upload_xmodem(FILE *);
  17. void upload_kermit(FILE *);
  18. static void (*up_protocol[5])(FILE *file_pointer) = {
  19.     upload_ASCII, upload_xmodem, upload_kermit,NULL,NULL
  20. };
  21. /* ----- up to five download function pointers ----- */
  22. void download_xmodem(FILE *);
  23. void download_kermit(FILE *);
  24. static void (*down_protocol[5])(FILE *file_pointer) = {
  25.     download_ASCII, download_xmodem, download_kermit,NULL,NULL
  26. };
  27.  
  28.  
  29. [LISTING TWO]
  30.  
  31. /* --------- phonedir.c ---------- */
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <conio.h>
  35. #include <string.h>
  36. #include <mem.h>
  37. #include <ctype.h>
  38. #include "window.h"
  39. #include "entry.h"
  40. #include "help.h"
  41. #include "modem.h"
  42.  
  43. #define DIRECTORY "phone.dir"
  44. #define MAX_ENTRIES 50
  45. #define WRITEDIR F2
  46. #define MODIFYDIR F3
  47.  
  48. void phdirectory(void);
  49. char scriptfile[13];
  50. static void get_directory(void);
  51. static void put_directory(void);
  52. static int dirproc(int, int);
  53. static void bld_default(int);
  54. static void build_dir(int);
  55. static int enter_directory(int);
  56. static void select_directory(int);
  57. char *prompt_line(char *, int, char *);
  58. void reset_prompt(char *, int);
  59. static int edit_directory(void);
  60. static int direrror(int);
  61. static void field_terminate(FIELD *fld, int termchar);
  62.  
  63. extern int PARITY,STOPBITS,WORDLEN,BAUD;
  64. extern char PHONENO[];
  65. extern char spaces[];
  66. extern struct wn wkw;   /* the directory window structure */
  67. extern void (*phone_directory)() = phdirectory;
  68. /* -------- phone directory file record ------------ */
  69. struct {
  70.     char ol_name[21];    /* callee's name             */
  71.     char ol_phone[24];   /* phone number              */
  72.     char ol_parity[8];   /* none/odd/even             */
  73.     char ol_stopbits[4]; /* 1 or 2                    */
  74.     char ol_wordlen[3];  /* 7 or 8                    */
  75.     char ol_baud[6];     /* 110,150,300,600,1200,2400 */
  76.     char ol_script[9];   /* name of script file       */
  77. } pd;
  78. static char hdr[] =
  79.     " Name                 "
  80.     "Phone Number           "
  81.     "Parity Stop Len Baud  Script";
  82. static char select_prompt[] =
  83.     "\030\031\021\304\331:Select Esc:Return "
  84.     "F2:Write Directory F3:Modify "
  85.     "Ins:Insert Del:Delete";
  86. static char enter_prompt[] =
  87.     " F2:Write Changes to Directory    "
  88.     " Esc:Ignore Entry   F1:Help";
  89. static char *pds[MAX_ENTRIES+1];
  90. static int pct;
  91. static FILE *fp;
  92. static char nmmask[] = "____________________";
  93. static char phmask[] = "____________________";
  94. static char prmask[] = "____";
  95. static char sbmask[] = "_";
  96. static char wlmask[] = "_";
  97. static char bdmask[] = "____";
  98. static char scmask[] = "________";
  99. /* ------- data entry template for the directory ------- */
  100. FIELD directory_template[] = {
  101.     {3, 16, 1, pd.ol_name,     nmmask, "name"},
  102.     {4, 16, 1, pd.ol_phone,    phmask, "phone"},
  103.     {5, 16, 1, pd.ol_parity,   prmask, "parity"},
  104.     {6, 16, 1, pd.ol_stopbits, sbmask, "stopbits"},
  105.     {7, 16, 1, pd.ol_wordlen,  wlmask, "wordlen"},
  106.     {8, 16, 1, pd.ol_baud,     bdmask, "baud"},
  107.     {9, 16, 1, pd.ol_script,   scmask, "script"},
  108.     {0}
  109. };
  110. /* -------- data entry error messages --------- */
  111. static char *ermsgs[] = {
  112.     "Parity must be None, Odd, or Even",
  113.     "Stop Bits must 1 or 2",
  114.     "Word Length must be 7 or 8",
  115.     "Baud Rate must be 110,150,300,600,1200,2400"
  116. };
  117. /* ------ manage the telephone directory ------ */
  118. void phdirectory(void)
  119. {
  120.     int s = 1;
  121.     char *ttl, *sel;
  122.     set_help("directry");
  123.     ttl = prompt_line(hdr, 1, NULL);
  124.     sel = prompt_line(select_prompt, 25, NULL);
  125.     establish_window(1,2,80,24,TEXTFG,TEXTBG,TRUE);
  126.     get_directory();
  127.     text_window(pds, 1);
  128.     while (pct &&
  129.           (s=select_window(s,SELECTFG,SELECTBG,dirproc))!=0)
  130.         if (pct && pds[s-1] != spaces+1)    {
  131.             select_directory(s-1);
  132.             break;
  133.         }
  134.     delete_window();
  135.     reset_prompt(sel, 25);
  136.     reset_prompt(ttl, 1);
  137. }
  138. /* -------- select the directory entry for the dialer ------- */
  139. static void select_directory(int n)
  140. {
  141.     char *cp = scriptfile;
  142.     movmem(pds[n], &pd, sizeof pd);
  143.     strncpy(PHONENO, pd.ol_phone, 20);
  144.     BAUD     = atoi(pd.ol_baud);
  145.     STOPBITS = *pd.ol_stopbits - '0';
  146.     WORDLEN  = *pd.ol_wordlen  - '0';
  147.     PARITY   = (*pd.ol_wordlen == 'N' ? 0 :
  148.                 *pd.ol_wordlen == 'O' ? 1 : 2);
  149.     establish_window(30,11,50,13,HELPFG,HELPBG,TRUE);
  150.     gotoxy(2,2);
  151.     cputs("Initializing Modem");
  152.     initmodem();
  153.     delete_window();
  154.     setmem(scriptfile, sizeof scriptfile, '\0');
  155.     strncpy(scriptfile, pd.ol_script, 8);
  156.     while (*cp && *cp != ' ')
  157.         cp++;
  158.     strcpy(cp, ".scr");
  159. }
  160. /* ------ read the phone directory ----------- */
  161. static void get_directory(void)
  162. {
  163.     if (pct == 0 && (fp = fopen(DIRECTORY, "r")) != NULL)   {
  164.         while (fread(&pd, sizeof pd, 1, fp) != 0)   {
  165.             build_dir(pct++);
  166.             if (pct == MAX_ENTRIES)
  167.                 break;
  168.         }
  169.         pds[pct++] = spaces+1;
  170.         pds[pct] = NULL;
  171.         fclose(fp);
  172.     }
  173.     if (pct == 0)
  174.         dirproc(INS, 1);
  175. }
  176. /* ------- build a default phone directory entry -------- */
  177. static void bld_default(int n)
  178. {
  179.     static char *prs[] = {"None", "Odd ", "Even"};
  180.     setmem(&pd, sizeof pd-1, ' ');
  181.     strncpy(pd.ol_parity, prs[PARITY], 4);
  182.     *pd.ol_stopbits = STOPBITS + '0';
  183.     *pd.ol_wordlen  = WORDLEN + '0';
  184.     sprintf(pd.ol_baud, "%4d", BAUD);
  185.     pd.ol_baud[4] = ' ';
  186.     build_dir(n);
  187. }
  188. /* --------- build a directory entry for display ----------- */
  189. static void build_dir(int n)
  190. {
  191.     if ((pds[n] = malloc(sizeof pd)) != NULL)
  192.         movmem(&pd, pds[n], sizeof pd);
  193. }
  194. /* ------- write the phone directory ---------- */
  195. static void put_directory(void)
  196. {
  197.     int i;
  198.     fp = fopen(DIRECTORY, "w");
  199.     for (i = 0; i < pct; i++)
  200.         if (pds[i] != spaces+1)
  201.             fwrite(pds[i], sizeof pd, 1, fp);
  202.     fclose(fp);
  203. }
  204. /* ---------- process a directory entry ------------- */
  205. static int dirproc(int c, int lineno)
  206. {
  207.     int i, j;
  208.     switch (c)  {
  209.         case DEL:
  210.             if (pds[lineno-1] != spaces+1)  {
  211.                 free(pds[lineno-1]);
  212.                 for (j = lineno-1; j < pct; j++)
  213.                     pds[j] = pds[j+1];
  214.                 if (--pct)  {
  215.                     text_window(pds, wkw.wtop);
  216.                     for (i = pct+2; i <= wkw.wtop+wkw.ht; i++)
  217.                         writeline(2, i, spaces+1);
  218.                     if (lineno-1 == pct)
  219.                         --lineno;
  220.                 }
  221.                 else
  222.                     clear_window();
  223.             }
  224.             break;
  225.         case INS:
  226.             if (pct == MAX_ENTRIES)
  227.                 break;
  228.             i = pct;
  229.             if (i)
  230.                 while (i >= lineno) {
  231.                     pds[i] = pds[i-1];
  232.                     --i;
  233.                 }
  234.             bld_default(i);
  235.             pct++;
  236.         case MODIFYDIR:
  237.             if (pds[lineno-1] != spaces+1)  {
  238.                 movmem(pds[lineno-1], &pd, sizeof pd);
  239.                 enter_directory(lineno-1);
  240.             }
  241.             break;
  242.         case WRITEDIR:
  243.             put_directory();
  244.             break;
  245.     }
  246.     wkw.wy = lineno - wkw.wtop + 1;
  247.     return (pct == 0);
  248. }
  249. /* ------- data entry for a directory record ---------- */
  250. static int enter_directory(int lineno)
  251. {
  252.     int s = 1;
  253.     char *p = prompt_line(enter_prompt, 25, NULL);
  254.     establish_window(20,5,56,15,ENTRYFG,ENTRYBG,TRUE);
  255.     window_title(" Telephone Directory Entry ");
  256.     gotoxy(3,3), cputs("Name:");
  257.     gotoxy(3,4), cputs("Phone:");
  258.     gotoxy(3,5), cputs("Parity:");
  259.     gotoxy(3,6), cputs("Stop Bits:");
  260.     gotoxy(3,7), cputs("Word Length:");
  261.     gotoxy(3,8), cputs("Baud Rate:");
  262.     gotoxy(3,9), cputs("Script:");
  263.     field_terminate(directory_template, '\0');
  264.     while (s != WRITEDIR && s != ESC)   {
  265.         s = data_entry(directory_template, FALSE, s);
  266.         if (s == WRITEDIR)
  267.             s = edit_directory();
  268.     }
  269.     field_terminate(directory_template, ' ');
  270.     *(((char *)(&pd)) + sizeof pd - 1) = '\0';
  271.     delete_window();
  272.     reset_prompt(p, 25);
  273.     if (s == WRITEDIR)  {
  274.         movmem(&pd, pds[lineno], sizeof pd);
  275.         put_directory();
  276.     }
  277.     text_window(pds,wkw.wtop ? wkw.wtop : 1);
  278.     return (s != ESC);
  279. }
  280. /* -------- validate the directory entry -------- */
  281. static int edit_directory(void)
  282. {
  283.     int i;
  284.     static int bds[] = {110,150,300,600,1200,2400};
  285.     *pd.ol_parity = toupper(*pd.ol_parity);
  286.     if (*pd.ol_parity != 'N' &&
  287.             *pd.ol_parity != 'O' &&
  288.             *pd.ol_parity != 'E')
  289.         return direrror(3);
  290.     if (*pd.ol_stopbits != '1' && *pd.ol_stopbits != '2')
  291.         return direrror(4);
  292.     if (*pd.ol_wordlen != '7' && *pd.ol_wordlen != '8')
  293.         return direrror(5);
  294.     for (i = 0; i < 6; i++)
  295.         if (atoi(pd.ol_baud) == bds[i])
  296.             break;
  297.     if (i == 6)
  298.         return direrror(6);
  299.     return WRITEDIR;
  300. }
  301. /* ------- post a directory entry error ---------- */
  302. static int direrror(int n)
  303. {
  304.     error_message(ermsgs[n-3]);
  305.     return n;
  306. }
  307. /* -------- set field terminators to null or space ------- */
  308. static void field_terminate(FIELD *fld, int termchar)
  309. {
  310.     for (;fld->frow;fld++)
  311.         *(fld->fbuff+strlen(fld->fmask)) = termchar;
  312. }
  313.  
  314.  
  315. [LISTING THREE]
  316.  
  317. /* ------------- protocol.c --------------- */
  318.  
  319. #include <stdio.h>
  320. #include <conio.h>
  321. #include <ctype.h>
  322. #include "window.h"
  323. #include "help.h"
  324. #include "menu.h"
  325.  
  326. static char *prots[] = {
  327.     " ASCII",
  328.     " Xmodem",
  329.     " Kermit",
  330.     NULL
  331. };
  332.  
  333. /* ----- translate A,X,K keystrokes for protocol menu ----- */
  334. static int protkey(int ky, int lnno)
  335. {
  336.     ky = tolower(ky);
  337.     return ky=='a' ? 1 : ky=='x' ? 2 : ky=='k' ? 3 : ERROR;
  338. }
  339.  
  340. /* --- file transfer protocol for uploads and downloads --- */
  341. int select_protocol(void)
  342. {
  343.     extern MENU *mn;
  344.     MENU *holdmn;
  345.     static int rtn = 0;
  346.     holdmn = mn;
  347.     mn = NULL;
  348.     set_help("protocol");
  349.     establish_window(25,7,55,11,MENUFG,MENUBG,TRUE);
  350.     window_title(" Select Transfer Protocol ");
  351.     text_window(prots, 1);
  352.     rtn = select_window(rtn?rtn:1,SELECTFG,SELECTBG,protkey);
  353.     delete_window();
  354.     mn = holdmn;
  355.     return rtn ? rtn-1 : 0;
  356. }
  357.  
  358. /* ---- These are stubs, to be replaced later ---- */
  359. void upload_kermit(FILE *fd)
  360. {
  361.     error_message("Upload KERMIT not implemented");
  362. }
  363.  
  364. void download_kermit(FILE *fd)
  365. {
  366.     error_message("Download KERMIT not implemented");
  367. }
  368.  
  369.  
  370. [LISTING FOUR]
  371.  
  372. /* -------------- xmodem.c --------------- */
  373. #include <stdio.h>
  374. #include <conio.h>
  375. #include <stdlib.h>
  376. #include <mem.h>
  377. #include "window.h"
  378. #include "serial.h"
  379.  
  380. #define RETRIES  12
  381. #define CRCTRIES 2
  382. #define PADCHAR  0x1a
  383. #define SOH      1
  384. #define EOT      4
  385. #define ACK      6
  386. #define NAK      0x15
  387. #define CAN      0x18
  388. #define CRC      'C'
  389. /* -------- external data ---------- */
  390. extern int TIMEOUT;
  391. extern int WORDLEN;
  392. extern int xonxoff_enabled;
  393. /* --------- local data ------------ */
  394. static int tries;   /* retry counter */
  395. static char bf [130]; /* i/o buffer  */
  396. /* -------- prototypes ------------- */
  397. extern int keyhit(void);
  398. static void receive_error(int, int);
  399. static void xmodem_msg(char *);
  400. static void test_wordlen(void);
  401. unsigned compute_crc(char *, int);
  402. /* --------- error messages ----------- */
  403. static char *errs[] = {
  404.     "Timed Out         ",
  405.     "Invalid SOH       ",
  406.     "Invalid block #   ",
  407.     "Invalid chksum/crc"
  408. };
  409. /* ---------- upload with xmodem protocol ------------- */
  410. void upload_xmodem(FILE *fd)
  411. {
  412.     int i, chksum, eof = FALSE, ans = 0, ln, crcout = 0;
  413.     unsigned crc;
  414.     char bno = 1;
  415.     xonxoff_enabled = FALSE;
  416.     establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
  417.     window_title("XMODEM Upload (CHKSUM)");
  418.     tries = 0;
  419.     test_wordlen();
  420.     /* ----- wait for the go-ahead from the receiver ------ */
  421.     TIMEOUT = 6;
  422.     while (tries++ < RETRIES && crcout != NAK && crcout != CRC)
  423.         crcout = readcomm();
  424.     if (crcout == CRC)
  425.         window_title(" XMODEM Upload (CRC)  ");
  426.     TIMEOUT = 10;
  427.     /* -------- send the file to the receiver ----------- */
  428.     while (tries < RETRIES &&
  429.             !eof && ans != CAN && !timed_out())     {
  430.         /* ---- read the next data block ----- */
  431.         setmem(bf, 128, PADCHAR);
  432.         if ((ln = fread(bf, 1, 128, fd)) < 128)
  433.             eof = TRUE;
  434.         if (ln == 0)
  435.             break;
  436.         gotoxy(2, 2);
  437.         cprintf("Block %d  ",bno);
  438.         chksum = 0;
  439.         if (keyhit())
  440.             if (getch() == ESC) {
  441.                 writecomm(CAN);
  442.                 break;
  443.             }
  444.         writecomm(SOH);      /* SOH           */
  445.         writecomm(bno);      /* block number  */
  446.         writecomm(~bno);     /* 1s complement */
  447.         /* ------- send the data block ------ */
  448.         for (i = 0; i < 128; i++)   {
  449.             writecomm(bf[i]);
  450.             chksum += bf[i];        /* checksum calculation */
  451.         }
  452.         /* -- send error-correcting value (chksum or crc) -- */
  453.         if (crcout == NAK)
  454.             writecomm(chksum & 255);
  455.         else    {
  456.             crc = compute_crc(bf, 130);
  457.             writecomm((crc >> 8) & 255);
  458.             writecomm(crc & 255);
  459.         }
  460.         /* ----- read ACK, NAK, or CAN from receiver ----- */
  461.         ans = readcomm();
  462.         if (ans == ACK) {
  463.             bno++;
  464.             tries = 0;
  465.             gotoxy(2, 4);
  466.             cprintf("        ");
  467.         }
  468.         if (ans == NAK) {
  469.             eof = FALSE;
  470.             gotoxy(2, 4);
  471.             cprintf("%2d tries", ++tries);
  472.             /* ---- position to previous block ----- */
  473.             if (fseek(fd, -128L, 1) == -1)
  474.                 fseek(fd, 0L, 0);
  475.         }
  476.     }
  477.     if (eof)    {
  478.         writecomm(EOT);                 /* send the EOT    */
  479.         readcomm();                     /* wait for an ACK */
  480.         xmodem_msg("Transfer Completed");
  481.     }
  482.     else
  483.         xmodem_msg("Transfer Aborted");
  484.     xonxoff_enabled = TRUE;
  485. }
  486. /* ---------- download with xmodem protocol ------------- */
  487. void download_xmodem(FILE *fd)
  488. {
  489.     int blk=0, soh= 0, bn, nbn, i, crcin = TRUE, fst = TRUE;
  490.     unsigned chksum, cs, cs1;
  491.     xonxoff_enabled = FALSE;
  492.     establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
  493.     window_title("XMODEM Download (CHKSUM)");
  494.     /* - send Cs then NAKs until the sender starts sending - */
  495.     tries = 0;
  496.     test_wordlen();
  497.     TIMEOUT = 6;
  498.     while (soh != SOH && tries < RETRIES)   {
  499.         crcin = (tries++ < CRCTRIES);
  500.         writecomm(crcin ? CRC : NAK);
  501.         soh = readcomm();
  502.         if (!timed_out() && soh != SOH)
  503.             sleep(6);
  504.     }
  505.     if (crcin)
  506.         window_title(" XMODEM Download (CRC)  ");
  507.     while (tries < RETRIES) {
  508.         if (timed_out())
  509.             receive_error(0, NAK);
  510.         /* -- Receive the data and build the file -- */
  511.         gotoxy(2,2);
  512.         cprintf("Block %d   ", blk + 1);
  513.         if (!fst)   {
  514.             TIMEOUT = 10;
  515.             soh = readcomm();
  516.             if (timed_out())
  517.                 continue;
  518.             if (soh == CAN)
  519.                 break;
  520.             if (soh == EOT) {
  521.                 writecomm(ACK);
  522.                 break;
  523.             }
  524.         }
  525.         fst = FALSE;
  526.         TIMEOUT = 1;
  527.         bn  = readcomm();       /* block number */
  528.         nbn = readcomm();       /* 1's complement */
  529.         chksum = 0;
  530.         /* ---- data block ----- */
  531.         for (i = 0; i < 128; i++)   {
  532.             *(bf + i) = readcomm();
  533.             if (timed_out())
  534.                 break;
  535.             chksum = (chksum + (*(bf + i)) & 255) & 255;
  536.         }
  537.         if (timed_out())
  538.             continue;
  539.         /* ---- checksum or crc from sender ---- */
  540.         cs = readcomm() & 255;
  541.         if (crcin)  {
  542.             cs1 = readcomm() & 255;
  543.             cs = (cs << 8) + cs1;
  544.         }
  545.         if (timed_out())
  546.             continue;
  547.         if (soh != SOH) {       /* check the SOH */
  548.             receive_error(1, NAK);
  549.             continue;
  550.         }
  551.         /* --- same as previous block number? --- */
  552.         if (bn == blk)
  553.             fseek(fd, -128L, 1);
  554.         /* --- no, next sequential block number? --- */
  555.         else if (bn != blk + 1) {
  556.             receive_error(2, CAN);
  557.             break;
  558.         }
  559.         blk = bn;
  560.         /* --- test the block # 1s complement --- */
  561.         if ((nbn & 255) != (~blk & 255))    {
  562.             receive_error(2, NAK);
  563.             continue;
  564.         }
  565.         if (crcin)
  566.             chksum = compute_crc(bf, 130);
  567.         /* --- test chksum or crc vs one sent --- */
  568.         if (cs != chksum)   {
  569.             receive_error(6, NAK);
  570.             continue;
  571.         }
  572.         soh = bn = nbn = cs = 0;
  573.         tries = 0;
  574.         /* --- write the block to disk --- */
  575.         fwrite(bf, 128, 1, fd);
  576.         if (keyhit())
  577.             if (getch() == ESC) {
  578.                 writecomm(CAN);
  579.                 break;
  580.             }
  581.         writecomm(ACK);
  582.     }
  583.     if (soh == EOT)
  584.         xmodem_msg("Transfer Complete");
  585.     else
  586.         xmodem_msg("Transfer Aborted");
  587.     TIMEOUT = 10;
  588.     xonxoff_enabled = TRUE;
  589. }
  590. /* ------------- send a nak ------------ */
  591. static void receive_error(erno, rtn)
  592. {
  593.     ++tries;
  594.     if (TIMEOUT == 1)   {
  595.         gotoxy(2,4);
  596.         cprintf("%s (%d tries)", errs[erno], tries);
  597.     }
  598.     writecomm(rtn);
  599. }
  600. /* ------ test for valid word length -------- */
  601. static void test_wordlen(void)
  602. {
  603.     if (WORDLEN != 8)   {
  604.         gotoxy(2,4);
  605.         cprintf("Must be 8 Data Bits");
  606.         tries = RETRIES;
  607.     }
  608. }
  609. /* --------- final message about xmodem transfer -------- */
  610. static void xmodem_msg(char *s)
  611. {
  612.     gotoxy(2,3);
  613.     cprintf(s);
  614.     putch(BELL);
  615.     sleep(3);
  616.     delete_window();
  617. }
  618. /* --------- compute the crc ------------ */
  619. unsigned compute_crc(char *bf, int len)
  620. {
  621.     int i;
  622.     long crc = 0;
  623.     while (len--)   {
  624.         crc |= (*bf++) & 255;
  625.         for (i = 0; i < 8; i++) {
  626.             crc <<= 1;
  627.             if (crc & 0x1000000L)
  628.                 crc ^= 0x102100L;
  629.         }
  630.     }
  631.     return (unsigned) (crc >> 8);
  632. }
  633.  
  634.