/* * vivi/deriver/serialxmodem.c: * - an implementation of the xmodem protocol from the spec. * * Based on bootldr/xmodem.c (C) 2000 Compaq Computer Coporation. * * Copyright (C) 2001 MIZI Research, Inc. * * * 1999-01-xx: Edwin Foo * - Initial code * * 2001-10-04: Janghoon Lyu * - Modified a little bit. * * 2002-07-04: Janghoon Lyu */ #include "config.h" #include "machine.h" #include "serial.h" #include "priv_data.h" #include <types.h> /* XMODEM parameters */ #define BLOCK_SIZE 128 /* size of transmit blocks */ #define RETRIES 20 /* maximum number of RETRIES */ /* Line control codes */ #define SOH 0x01 /* start of header */ #define ACK 0x06 /* Acknowledge */ #define NAK 0x15 /* Negative acknowledge */ #define CAN 0x18 /* Cancel */ #define EOT 0x04 /* end of text */ #define GET_BYTE_TIMEOUT 10000000 /* global error variable */ char *xmodem_errtxt = NULL; int get_byte_err = 0; __u8 volatile rbuffer[BLOCK_SIZE]; /* prototypes of helper functions */ int get_record(void); __u8 get_byte(void); enum { SAC_SEND_NAK = 0, SAC_SENT_NAK = 1, SAC_PAST_START_NAK = 2 }; static volatile int seen_a_char = SAC_SEND_NAK; static int one_nak = 0; static unsigned long xmodem_timeout = GET_BYTE_TIMEOUT; char debugbuf[4096]; int db_idx = 0; void bufputs(char *s) { size_t len = strlen(s) + 1; if (len + db_idx > sizeof(debugbuf)) len = sizeof(debugbuf) - db_idx; if (len) { memcpy(&debugbuf[db_idx], s, len); db_idx += len; } } void reset_debugbuf(void) { memset(debugbuf, 0x2a, sizeof(debugbuf)); db_idx = 0; } __u32 xmodem_receive(char *dldaddr, size_t len) { char ochr; int r = 0, rx_block_num = 0, error_count = 0; __u32 foffset = 0; int i; int ret; xmodem_errtxt = NULL; seen_a_char = 0; one_nak = get_param_value("xmodem_one_nak", &ret); if (ret) one_nak = 0; xmodem_timeout = get_param_value("xmodem_initial_timeout", &ret); if (ret) xmodem_timeout = GET_BYTE_TIMEOUT; rx_block_num = 1; // 一共接收到了多少個包 error_count = RETRIES; // 重試次數(shù) 20次 do { // rx_block_num & 255 的意思是求出當(dāng)前的包的編號,因為每次最多 // 是 256個包而已0-255,并且 rx_block_num 應(yīng)該是指向下一個應(yīng)該 // 接收到的正確的包的編號,如果相等,表示今次接收的包是正確的 if ((r = get_record()) == (rx_block_num & 255)) { error_count = RETRIES; // 重置重試次數(shù) for (i = 0; i <BLOCK_SIZE; i++) // 將一個包復(fù)制到指定的地址 *(__u8 *)(dldaddr+foffset+i) = rbuffer[i]; xmodem_errtxt = "RX PACKET"; // 錯誤信息,沒有錯誤,接收一個包完畢 rx_block_num++; // 接收到的總包數(shù)加1 ochr = ACK; // 回應(yīng) ACK 信號 foffset += BLOCK_SIZE; // 寫入的目標地址的偏移,相應(yīng)加上一個block } else { switch (r) { // 否則,處理錯誤代碼 // NAK 信號的意思是請求發(fā)送方重新發(fā)一個包 // ACK 信號解釋為正確接收 // 下面可以看出,超時,錯誤的checksum case -1: /* TIMEOUT */ xmodem_errtxt = "TIMEOUT"; ochr = NAK; break; case -2: /* Bad block */ xmodem_errtxt = "BAD BLOCK#"; /* eat teh rest of the block */ get_byte_err = 0; while (get_byte_err != -1) get_byte(); ochr = NAK; break; case -3: /* Bad checksum */ xmodem_errtxt = "BAD CHKSUM"; ochr = NAK; break; case -4: /* End of file */ xmodem_errtxt = "DONE"; ochr = ACK; break; case -5: /* Cancel */ xmodem_errtxt = "ABORTED"; ochr = ACK; break; default: /* Block out of sequence */ xmodem_errtxt = "WRONG BLK"; ochr = NAK; } error_count--; // 錯誤加一 } putc(ochr); // 發(fā)送應(yīng)答信號,很簡單,putc就是接收-->發(fā)送端的信號了 } while ((r > -3) && error_count); // r>-3表示 DONE 和 ABORTED 之外的情況,也就是說,沒有完成或者沒有中途退出 // 的話就一直循環(huán),但是如果錯誤技術(shù)過多的話也停止傳輸。 if ((!error_count) || (r != -4)) { // 表示出錯了 foffset = 0; /* indicate failure to caller */ /*printk("x-modem error: %s\n", xmodem_errtxt); */ } return foffset; // 返回最后指向的指針,應(yīng)該是文件的結(jié)尾處表示正確,0表示錯誤 } /* * Read a record in the XMODEM protocol, return the block number * (0-255) if successful, or one of the following return codes: * -1 = Bad byte * -2 = Bad block number * -3 = Bad block checksum * -4 = End of file * -5 = Canceled by remote * * 讀取一個塊,每個塊的格式為(根據(jù) xmodem協(xié)議) * * | | | | | | * | SOH | 信息包序號 | 信息包序號的補碼 | 數(shù)據(jù)區(qū)段 | 算術(shù)校驗和 | * |_____|________ _ |________________ |________ |__________ | * * */ int get_record(void) { int c, block_num = 0; int i; __u32 check_sum; /* clear the buffer,接收緩沖,存128字節(jié)的數(shù)據(jù)區(qū)段 */ for (i = 0; i < BLOCK_SIZE; i++) rbuffer[i] = 0x00; check_sum = 0; i = -2; // 首先讀一個字節(jié),判斷是否有出錯 c = get_byte(); if (get_byte_err) return -1; switch (c) { case SOH: /* 如果接收的是頭信號的話 Receive packet */ for (;;) { // 一直循環(huán)到 128字節(jié)讀取完畢 c = get_byte(); // 讀一個字節(jié)判斷有沒有錯誤 if (get_byte_err) return -1; switch (i) { case -2: // 如果 i 為 -2 表示現(xiàn)在接收的是信息包的序號 block_num = c; // 保存起來以便返回 break; case -1: #if 0 #ifdef CHECK_NEGATED_SECTNUM if (c != (-block_num -1)) return -2; #endif #endif break; case BLOCK_SIZE: // 如果現(xiàn)在計數(shù)到達 128表示這是一個CHECKSUM // 因為包的編號是 0-127一共128個,那么128編號的包為校驗和 if ((check_sum & 0xff) != c) // 將接收到的校驗和和自己計算的比較 return -3; // 不對就返回錯誤 else return block_num; // 正確,返回包的編號 break; default: // 默認的話就是一個塊里面的每個字節(jié) rbuffer[i] = c; // 存放數(shù)據(jù) check_sum += c; // checksum只是很簡單的相加 } i++; } case EOT: /* end of file encountered */ return -4; case CAN: /* cancel protocol */ return -5; default: return -5; } } /* get_byte should use one of the timer's for a CPU clock independent timeout */ __u8 get_byte() { int c, ret; again: c = 0; get_byte_err = 0; /* reset errno */ c = awaitkey(xmodem_timeout, &get_byte_err); // 從UART讀取一個字節(jié),超時時間為 xmodem_timeout if (get_byte_err) { if (seen_a_char == SAC_SEND_NAK || !one_nak) { bufputs("timeout nak"); putc(NAK); /* make the sender go */ } if (seen_a_char < SAC_PAST_START_NAK) { bufputs("goto again"); seen_a_char = SAC_SENT_NAK; xmodem_timeout = get_param_value("xmodem_timeout", &ret); if (ret) xmodem_timeout = GET_BYTE_TIMEOUT; goto again; } } if (get_byte_err == 0) seen_a_char = SAC_PAST_START_NAK; return (c); } |
|