static int xmodem_send_pkt(struct xmodem_send * sx, int data_len) { unsigned char * pkt = sx->pkt.hdr; unsigned char * cp; int retry = 0; int pkt_len; int ret; int c; if (sx->state == XMODEM_SEND_IDLE) { for (;;) { // Wait for NAK or 'C' if ((ret = serial_recv(sx->dev, pkt, 1, XMODEM_SEND_TMOUT_MS)) <= 0) { if (ret == 0) { DBG(DBG_TRACE, "serial_recv() timed out!"); if (++retry < 20) continue; } DBG(DBG_WARNING, "serial_recv() failed 1!"); return ret; } c = *pkt; if (c == CAN) { DBG(DBG_WARNING, "<-- CAN"); return -1; } if (c == 'C') { DBG(DBG_TRACE, "<-- 'C' (CRC mode)"); sx->state = XMODEM_SEND_CRC; break; } if (c == NAK) { DBG(DBG_TRACE, "<-- NAK (Checksum mode)"); sx->state = XMODEM_SEND_CKS; break; } } } if (data_len) { unsigned char * fcs; if (data_len == 1024) pkt[0] = STX; else if (data_len == 128) pkt[0] = SOH; else return -1; pkt[1] = sx->seq; pkt[2] = ~sx->seq; cp = &pkt[3]; fcs = &pkt[3 + data_len]; if (sx->state == XMODEM_SEND_CRC) { unsigned short crc = 0; int i; for (i = 0; i < data_len; ++i) crc = CRC16CCITT(crc, cp[i]); fcs[0] = crc >> 8; fcs[1] = crc & 0xff; pkt_len = 3 + data_len + 2; } else {
int dmon_ymodem_rcv_pkt(struct dmon_comm * comm, struct ymodem_rcv * rx) { unsigned char * pkt = rx->pkt.hdr; unsigned char * cp; int ret = 0; int cnt = 0; int nseq; int seq; int rem; for (;;) { dbgmon_alarm(XMODEM_RCV_TMOUT_MS); DCC_LOG1(LOG_INFO, "SYN=%02x", rx->sync); dmon_comm_send(comm, &rx->sync, 1); for (;;) { int c; ret = dmon_comm_recv(comm, pkt, 1); if (ret < 0) goto timeout; c = pkt[0]; if (c == STX) { cnt = 1024; break; } if (c == SOH) { cnt = 128; break; } if (c == CAN) { return -1; } if (c == EOT) { DCC_LOG(LOG_INFO, "EOT!!"); /* end of transmission */ rx->sync = rx->crc_mode ? 'C' : NAK; rx->pktno = 0; pkt[0] = ACK; dmon_comm_send(comm, pkt, 1); return 0; } } rem = cnt + ((rx->crc_mode) ? 4 : 3); cp = pkt + 1; /* receive the packet */ while (rem) { dbgmon_alarm(500); ret = dmon_comm_recv(comm, cp, rem); if (ret < 0) goto timeout; rem -= ret; cp += ret; } /* sequence */ seq = pkt[1]; /* inverse sequence */ nseq = pkt[2]; if (seq != ((~nseq) & 0xff)) { goto error; } cp = &pkt[3]; if (rx->crc_mode) { unsigned short crc = 0; unsigned short cmp; int i; for (i = 0; i < cnt; ++i) crc = CRC16CCITT(crc, cp[i]); cmp = (unsigned short)cp[i] << 8 | cp[i + 1]; if (cmp != crc) { DCC_LOG(LOG_WARNING, "CRC error"); goto error; } } else { unsigned char cks = 0; int i; for (i = 0; i < cnt; ++i) cks += cp[i]; if (cp[i] != cks) { DCC_LOG(LOG_WARNING, "wrong sum"); goto error; } } if (seq == ((rx->pktno - 1) & 0xff)) { /* retransmission */ DCC_LOG(LOG_INFO, "rxmit ..."); continue; } if (seq != (rx->pktno & 0xff)) { if ((rx->pktno == 0) && (seq == 1)) { rx->pktno++; /* Fallback to XMODEM */ rx->xmodem = 1; DCC_LOG(LOG_INFO, "XMODEM..."); } else { DCC_LOG(LOG_WARNING, "wrong sequence"); goto error; } } /* YModem first packet ... */ if (rx->pktno == 0) { DCC_LOG(LOG_INFO, "ACK"); pkt[0] = ACK; dmon_comm_send(comm, pkt, 1); } else { rx->retry = 10; rx->sync = ACK; if ((rx->count + cnt) > rx->fsize) cnt = rx->fsize - rx->count; rx->count += cnt; } DCC_LOG2(LOG_INFO, "pktno=%d count=%d", rx->pktno, rx->count); rx->pktno++; dbgmon_alarm_stop(); return cnt; error: /* flush */ while (dmon_comm_recv(comm, pkt, 1024) > 0); ret = -1; break; timeout: DCC_LOG(LOG_WARNING, "timeout!!"); if ((--rx->retry) == 0) { /* too many errors */ ret = -1; break; } } pkt[0] = CAN; pkt[1] = CAN; dmon_comm_send(comm, pkt, 2); dbgmon_alarm_stop(); return ret; }
static int usb_ymodem_rcv_pkt(struct ymodem_rcv * rx) { unsigned char * pkt = rx->pkt.hdr; unsigned char * cp; int ret = 0; int cnt = 0; #if XMODEM_SEQUENCE_CHECK int nseq; int seq; #endif int rem; int pos; int i; for (;;) { if ((ret = usb_send(CDC_TX_EP, &rx->sync, 1)) < 0) { return ret; } rem = 0; pos = 0; for (;;) { int c; if (rem == 0) { ret = usb_recv(CDC_RX_EP, pkt, 128, 2000); DCC_LOG1(LOG_TRACE, "usb_recv() ret=%d)", ret); if (ret <= 0) goto timeout; pos = 0; rem = ret; } c = pkt[pos]; pos++; rem--; if (c == STX) { cnt = 1024; break; } if (c == SOH) { cnt = 128; break; } if (c == CAN) { return -1; } if (c == EOT) { /* end of transmission */ #if XMODEM_CHECKSUM rx->sync = rx->crc_mode ? 'C' : NAK; #else rx->sync = 'C'; #endif rx->pktno = 0; pkt[0] = ACK; usb_send(CDC_TX_EP, pkt, 1); return 0; } } cp = pkt + 1; for (i = 0; i < rem; ++i) cp[i] = pkt[pos + i]; cp += rem; rem = cnt + 4 - rem; /* receive the packet */ while (rem) { ret = usb_recv(CDC_RX_EP, cp, rem, 500); DCC_LOG1(LOG_TRACE, "usb_recv() ret=%d)", ret); if (ret < 0) goto timeout; rem -= ret; cp += ret; } #if XMODEM_SEQUENCE_CHECK /* sequence */ seq = pkt[1]; /* inverse sequence */ nseq = pkt[2]; if (seq != ((~nseq) & 0xff)) { goto error; } #endif cp = &pkt[3]; #if XMODEM_CHECKSUM if (rx->crc_mode) #endif #if XMODEM_CRC_CHECK { unsigned short crc = 0; unsigned short cmp; int i; for (i = 0; i < cnt; ++i) crc = CRC16CCITT(crc, cp[i]); cmp = (unsigned short)cp[i] << 8 | cp[i + 1]; if (cmp != crc) { goto error; } } #endif #if XMODEM_CHECKSUM else { unsigned char cks = 0; int i; for (i = 0; i < cnt; ++i) cks += cp[i]; if (cp[i] != cks) { goto error; } } #endif #if XMODEM_SEQUENCE_CHECK if (seq == ((rx->pktno - 1) & 0xff)) { /* retransmission */ continue; } if (seq != (rx->pktno & 0xff)) { #if XMODEM_FALLBACK if ((rx->pktno == 0) && (seq == 1)) { rx->pktno++; /* Fallback to XMODEM */ rx->xmodem = true; } else #endif { goto error; } } #endif /* YModem first packet ... */ if (rx->pktno == 0) { pkt[0] = ACK; usb_send(CDC_TX_EP, pkt, 1); } else { rx->retry = 10; rx->sync = ACK; if ((rx->count + cnt) > rx->fsize) cnt = rx->fsize - rx->count; rx->count += cnt; } rx->pktno++; return cnt; #if XMODEM_SEQUENCE_CHECK || XMODEM_CRC_CHECK error: /* flush */ while (usb_recv(CDC_RX_EP, pkt, 1024, 100) > 0); ret = -1; break; #endif timeout: if ((--rx->retry) == 0) { /* too many errors */ DCC_LOG(LOG_WARNING, "too many errors!"); ret = -1; break; } } return usb_ymodem_rcv_cancel(rx); }