diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index b946848a3..d8157c127 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -81,6 +81,13 @@ char ZigbeeUploadFlashRead(void) { ZbUpload.byte_counter++; if (ZbUpload.byte_counter > ZbUpload.ota_size) { + +// static bool padding = true; +// if (padding) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Start padding from %d"), ZbUpload.byte_counter); +// padding = false; +// } + // When the source device reaches the last XModem data block, it should be padded to 128 bytes // of data using SUB (ASCII 0x1A) characters. data = XM_SUB; @@ -107,8 +114,8 @@ struct XMODEM { uint32_t delay = 0; uint32_t flush_delay = 0xFFFFFFFF; uint32_t filepos = 0; + uint32_t packet_no = 1; int crcBuf = 0; - uint8_t packetNo = 1; uint8_t checksumBuf = 0; bool oldChecksum; } XModem; @@ -142,6 +149,11 @@ char XModemWaitACK(void) if (i > 200) { return -1; } } in_char = ZigbeeSerial->read(); + +// if (in_char != XM_ACK) { +// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("XMD: Rcvd3 0x%02X"), in_char); +// } + if (XM_CAN == in_char) { return XM_CAN; } } while ((in_char != XM_NAK) && (in_char != XM_ACK) && (in_char != 'C')); return in_char; @@ -162,10 +174,12 @@ bool XModemSendPacket(uint32_t packet_no) { XModem.checksumBuf = 0x00; XModem.crcBuf = 0x00; + uint8_t packet_num = packet_no; + // Try to send packet, so header first ZigbeeSerial->write(XM_SOH); - ZigbeeSerial->write(packet_no); - ZigbeeSerial->write(~packet_no); + ZigbeeSerial->write(packet_num); + ZigbeeSerial->write(~packet_num); for (uint32_t i = 0; i < XMODEM_PACKET_SIZE; i++) { in_char = ZigbeeUploadFlashRead(); XModemOutputByte(in_char); @@ -220,6 +234,13 @@ bool ZigbeeUploadBootloaderPrompt(void) { yield(); char bootloader_byte = ZigbeeSerial->read(); + // [cr][lf] + // Gecko Bootloader v1.A.3 or Gecko Bootloader v1.9.1.04[cr][lf] + // 1. upload gbl[cr][lf] + // 2. run[cr][lf] + // 3. ebl info[cr][lf] + // BL > + if (((uint8_t)bootloader_byte >=0) && (buf_len < sizeof(serial_buffer) -2)) { serial_buffer[buf_len++] = bootloader_byte; } @@ -332,17 +353,18 @@ bool ZigbeeUploadXmodem(void) { } } else { // After the bootloader receives a carriage return from the target device, it displays a menu - // Gecko Bootloader v1.A.3 - // 1. upload gbl - // 2. run - // 3. ebl info + // [cr][lf] + // Gecko Bootloader v1.A.3 or Gecko Bootloader v1.9.1.04[cr][lf] + // 1. upload gbl[cr][lf] + // 2. run[cr][lf] + // 3. ebl info[cr][lf] // BL > if (ZigbeeUploadBootloaderPrompt()) { AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Init sync")); ZigbeeSerial->flush(); ZigbeeSerial->write('1'); // upload ebl if (TasmotaGlobal.sleep > 0) { - TasmotaGlobal.sleep = 1; // Speed up loop used for xmodem upload + TasmotaGlobal.sleep = 1; // Speed up loop used for xmodem upload } XModem.timeout = millis() + (XMODEM_SYNC_TIMEOUT * 1000); ZbUpload.ota_step = ZBU_SYNC; @@ -358,11 +380,17 @@ bool ZigbeeUploadXmodem(void) { } // Wait for either C or NACK as a sync packet. Determines protocol details, checksum algorithm. if (ZigbeeSerial->available()) { + // [cr][lf] + // begin upload[cr][lf] + // C char xmodem_sync = ZigbeeSerial->read(); + +// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("XMD: Rcvd2 0x%02X"), xmodem_sync); + if (('C' == xmodem_sync) || (XM_NAK == xmodem_sync)) { // Determine which checksum algorithm to use XModem.oldChecksum = (xmodem_sync == XM_NAK); - XModem.packetNo = 1; + XModem.packet_no = 1; ZbUpload.byte_counter = 0; ZbUpload.ota_step = ZBU_UPLOAD; AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Init packet send")); @@ -372,12 +400,15 @@ bool ZigbeeUploadXmodem(void) { } case ZBU_UPLOAD: { // *** Handle file upload using XModem - upload if (ZigbeeUploadAvailable()) { - if (!XModemSendPacket(XModem.packetNo)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Packet send failed")); + if (ZbUpload.byte_counter && !(ZbUpload.byte_counter % 10240)) { // Show progress every 10kB + AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Progress %d kB"), ZbUpload.byte_counter / 1024); + } + if (!XModemSendPacket(XModem.packet_no)) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Packet %d send failed"), XModem.packet_no); ZbUpload.ota_step = ZBU_ERROR; return true; } - XModem.packetNo++; + XModem.packet_no++; } else { // Once the last block is ACKed by the target, the transfer should be finalized by an // EOT (ASCII 0x04) packet from the source. Once this packet is confirmed via XModem ACK @@ -385,6 +416,7 @@ bool ZigbeeUploadXmodem(void) { ZigbeeSerial->write(XM_EOT); XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EOT ACK ZbUpload.ota_step = ZBU_EOT; + AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Transferred %d bytes"), ZbUpload.ota_size); } break; } @@ -401,7 +433,12 @@ bool ZigbeeUploadXmodem(void) { } if (ZigbeeSerial->available()) { char xmodem_ack = XModemWaitACK(); - if (XM_ACK == xmodem_ack) { + if (XM_CAN == xmodem_ack) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: Transfer invalid")); + ZbUpload.ota_step = ZBU_ERROR; + return true; + } + else if (XM_ACK == xmodem_ack) { AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: " D_SUCCESSFUL)); XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EBL prompt ZbUpload.byte_counter = 0; @@ -418,28 +455,33 @@ bool ZigbeeUploadXmodem(void) { } else { // After an image successfully uploads, the XModem transaction completes and the bootloader displays // ‘Serial upload complete’ before redisplaying the menu - // Serial upload complete - // Gecko Bootloader v1.A.3 - // 1. upload gbl - // 2. run - // 3. ebl info + // + // [cr][lf] + // Serial upload complete[cr][lf] + // [cr][lf] + // Gecko Bootloader v1.A.3 or Gecko Bootloader v1.9.1.04[cr][lf] + // 1. upload gbl[cr][lf] + // 2. run[cr][lf] + // 3. ebl info[cr][lf] // BL > if (ZigbeeUploadBootloaderPrompt()) { ZbUpload.state = ZBU_COMPLETE; ZbUpload.ota_step = ZBU_DONE; + AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: " D_RESTARTING)); } } break; } case ZBU_ERROR: ZbUpload.state = ZBU_ERROR; + AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: " D_FAILED)); case ZBU_DONE: { // *** Clean up and restart to disable bootloader and use new firmware - AddLog_P(LOG_LEVEL_DEBUG, PSTR("XMD: " D_RESTARTING)); ZigbeeUploadSetBootloader(1); // Disable bootloader and reset MCU - should happen at restart if (1 == TasmotaGlobal.sleep) { TasmotaGlobal.sleep = Settings.sleep; // Restore loop sleep } // TasmotaGlobal.restart_flag = 2; // Restart to disable bootloader and use new firmware + if (ZbUpload.buffer) { free(ZbUpload.buffer); } ZbUpload.ota_step = ZBU_FINISH; // Never return to zero without a restart to get a sane Zigbee environment break; } @@ -472,10 +514,6 @@ void ZigbeeUploadStep1Done(uint32_t data, size_t size) { ZbUpload.state = ZBU_UPLOAD; // Signal upload done and ready for delayed upload to MCU EFR32 } -bool ZigbeeUploadFinish(void) { - return (ZBU_FINISH == ZbUpload.ota_step); -} - #define WEB_HANDLE_ZIGBEE_XFER "zx" const char HTTP_SCRIPT_XFER_STATE[] PROGMEM = @@ -500,12 +538,12 @@ void HandleZigbeeXfer(void) { if (!HttpCheckPriviledgedAccess()) { return; } if (Webserver->hasArg("z")) { // Status refresh requested - WSContentBegin(200, CT_PLAIN); - WSContentSend_P(PSTR("%d"), ZbUpload.state); - WSContentEnd(); if (ZBU_ERROR == ZbUpload.state) { Web.upload_error = 7; // Upload aborted (xmodem transfer failed) } + WSContentBegin(200, CT_PLAIN); + WSContentSend_P(PSTR("%d"), ZbUpload.state); + WSContentEnd(); return; }