⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xyzmodem.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
        if (cksum != ((xyz.crc1 << 8) | xyz.crc2)) {
            ZM_DEBUG(zm_dprintf("CRC error - recvd: %02x%02x, computed: %x\n", 
                                xyz.crc1, xyz.crc2, cksum & 0xFFFF));
            return xyzModem_cksum;
        }
    } else {
        cksum = 0;
        for (i = 0;  i < xyz.len;  i++) {
            cksum += xyz.pkt[i];
        }
        if (xyz.crc1 != (cksum & 0xFF)) {
            ZM_DEBUG(zm_dprintf("Checksum error - recvd: %x, computed: %x\n", xyz.crc1, cksum & 0xFF));
            return xyzModem_cksum;
        }
    }
    // If we get here, the message passes [structural] muster
    return 0;
}

int 
xyzModem_stream_open(connection_info_t *info, int *err)
{
    int console_chan, stat;
    int retries = xyzModem_MAX_RETRIES;
    int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;

//    ZM_DEBUG(zm_out = zm_out_start);
#ifdef xyzModem_zmodem
    if (info->mode == xyzModem_zmodem) {
        *err = xyzModem_noZmodem;
        return -1;
    }
#endif

    // Set up the I/O channel.  Note: this allows for using a different port in the future
    console_chan = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
    if (info->chan >= 0) {
        CYGACC_CALL_IF_SET_CONSOLE_COMM(info->chan);
    } else {
        CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
    }
    xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
    CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
    CYGACC_COMM_IF_CONTROL(*xyz.__chan, __COMMCTL_SET_TIMEOUT, xyzModem_CHAR_TIMEOUT);
    xyz.len = 0;
    xyz.crc_mode = true;
    xyz.at_eof = false;
    xyz.tx_ack = false;
    xyz.mode = info->mode;
    xyz.total_retries = 0;
    xyz.total_SOH = 0;
    xyz.total_STX = 0;
    xyz.total_CAN = 0;
#ifdef USE_YMODEM_LENGTH
    xyz.read_length = 0;
    xyz.file_length = 0;
#endif
    
    CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));

    if (xyz.mode == xyzModem_xmodem) {
	    // X-modem doesn't have an information header - exit here
            xyz.next_blk = 1;
            return 0;
    }

    while (retries-- > 0) {
        stat = xyzModem_get_hdr();
        if (stat == 0) {
            // Y-modem file information header
            if (xyz.blk == 0) {
#ifdef USE_YMODEM_LENGTH
                // skip filename
                while (*xyz.bufp++);
                // get the length
                parse_num(xyz.bufp, &xyz.file_length, NULL, " ");
#endif
                // The rest of the file name data block quietly discarded
                xyz.tx_ack = true;
            }
            xyz.next_blk = 1;
            xyz.len = 0;
            return 0;
        } else 
        if (stat == xyzModem_timeout) {
            if (--crc_retries <= 0) xyz.crc_mode = false;
            CYGACC_CALL_IF_DELAY_US(5*100000);   // Extra delay for startup
            CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
            xyz.total_retries++;
            ZM_DEBUG(zm_dprintf("NAK (%d)\n", __LINE__));
        }
        if (stat == xyzModem_cancel) {
            break;
        }
    }
    *err = stat;
    ZM_DEBUG(zm_flush());
    return -1;
}

int 
xyzModem_stream_read(char *buf, int size, int *err)
{
    int stat, total, len;
    int retries;

    total = 0;
    stat = xyzModem_cancel;
    // Try and get 'size' bytes into the buffer
    while (!xyz.at_eof && (size > 0)) {
        if (xyz.len == 0) {
            retries = xyzModem_MAX_RETRIES;
            while (retries-- > 0) {
                stat = xyzModem_get_hdr();
                if (stat == 0) {
                    if (xyz.blk == xyz.next_blk) {
                        xyz.tx_ack = true;
                        ZM_DEBUG(zm_dprintf("ACK block %d (%d)\n", xyz.blk, __LINE__));
                        xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
                        // Data blocks can be padded with ^Z (EOF) characters
                        // This code tries to detect and remove them
#ifdef xyzModem_zmodem
                        if (xyz.mode != xyzModem_zmodem) {
#else
                        if (1) {
#endif
                            if ((xyz.bufp[xyz.len-1] == EOF) &&
                                (xyz.bufp[xyz.len-2] == EOF) &&
                                (xyz.bufp[xyz.len-3] == EOF)) {
                                while (xyz.len && (xyz.bufp[xyz.len-1] == EOF)) {
                                    xyz.len--;
                                }
                            }
                        }

#ifdef USE_YMODEM_LENGTH
                        // See if accumulated length exceeds that of the file.
                        // If so, reduce size (i.e., cut out pad bytes)
                        // Only do this for Y-modem (and Z-modem should it ever
                        // be supported since it can fall back to Y-modem mode).
                        if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length) {
                            xyz.read_length += xyz.len;
                            if (xyz.read_length > xyz.file_length) {
                                xyz.len -= (xyz.read_length - xyz.file_length);
                            }
                        }
#endif
                        break;
                    } else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF)) {
                        // Just re-ACK this so sender will get on with it
                        CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
                        continue;  // Need new header
                    } else {
                        stat = xyzModem_sequence;
                    }
                }
                if (stat == xyzModem_cancel) {
                    break;
                }
                if (stat == xyzModem_eof) {
                    CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
                    ZM_DEBUG(zm_dprintf("ACK (%d)\n", __LINE__));
                    if (xyz.mode == xyzModem_ymodem) {
                        CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
                        xyz.total_retries++;
                        ZM_DEBUG(zm_dprintf("Reading Final Header\n"));
                        stat = xyzModem_get_hdr();                        
                        CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
                        ZM_DEBUG(zm_dprintf("FINAL ACK (%d)\n", __LINE__));
                    }
                    xyz.at_eof = true;
                    break;
                }
                CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
                xyz.total_retries++;
                ZM_DEBUG(zm_dprintf("NAK (%d)\n", __LINE__));
            }
            if (stat < 0) {
                *err = stat;
                xyz.len = -1;
                return total;
            }
        }
        // Don't "read" data from the EOF protocol package
        if (!xyz.at_eof) {
            len = xyz.len;
            if (size < len) len = size;
            memcpy(buf, xyz.bufp, len);
            size -= len;
            buf += len;
            total += len;
            xyz.len -= len;
            xyz.bufp += len;
        }
    }
    return total;
}

void
xyzModem_stream_close(int *err)
{
    diag_printf("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n", 
                xyz.crc_mode ? "CRC" : "Cksum",
                xyz.total_SOH, xyz.total_STX, xyz.total_CAN,
                xyz.total_retries);
//    ZM_DEBUG(zm_flush());
}

// Need to be able to clean out the input buffer, so have to take the
// getc
void xyzModem_stream_terminate(bool abort, int (*getc)(void))
{
  int c;

  if (abort) {
      ZM_DEBUG(zm_dprintf("!!!! TRANSFER ABORT !!!!\n"));
      switch (xyz.mode) {
	case xyzModem_xmodem:
	case xyzModem_ymodem:
	  // The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal
	  // number of Backspaces is a friendly way to get the other end to abort.
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
	  CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
	  // Now consume the rest of what's waiting on the line.
	  ZM_DEBUG(zm_dprintf("Flushing serial line.\n"));
	  xyzModem_flush();
          xyz.at_eof = true;
	break;
#ifdef xyzModem_zmodem
	case xyzModem_zmodem:
	  // Might support it some day I suppose.
#endif
	break;
      }
  } else {
      ZM_DEBUG(zm_dprintf("Engaging cleanup mode...\n"));
      // Consume any trailing crap left in the inbuffer from
      // previous recieved blocks. Since very few files are an exact multiple
      // of the transfer block size, there will almost always be some gunk here.
      // If we don't eat it now, RedBoot will think the user typed it.
      ZM_DEBUG(zm_dprintf("Trailing gunk:\n"));
      while ((c = (*getc)()) > -1) ;
      ZM_DEBUG(zm_dprintf("\n"));
      // Make a small delay to give terminal programs like minicom
      // time to get control again after their file transfer program
      // exits.
      CYGACC_CALL_IF_DELAY_US((cyg_int32)250000);
  }
}

char *
xyzModem_error(int err)
{
    switch (err) {
    case xyzModem_access:
        return "Can't access file";
        break;
    case xyzModem_noZmodem:
        return "Sorry, zModem not available yet";
        break;
    case xyzModem_timeout:
        return "Timed out";
        break;
    case xyzModem_eof:
        return "End of file";
        break;
    case xyzModem_cancel:
        return "Cancelled";
        break;
    case xyzModem_frame:
        return "Invalid framing";
        break;
    case xyzModem_cksum:
        return "CRC/checksum error";
        break;
    case xyzModem_sequence:
        return "Block sequence error";
        break;
    default:
        return "Unknown error";
        break;
    }
}

//
// RedBoot interface
//
GETC_IO_FUNCS(xyzModem_io, xyzModem_stream_open, xyzModem_stream_close,
              xyzModem_stream_terminate, xyzModem_stream_read, xyzModem_error);
RedBoot_load(xmodem, xyzModem_io, false, false, xyzModem_xmodem);
RedBoot_load(ymodem, xyzModem_io, false, false, xyzModem_ymodem);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -