diff --git a/.github/workflows/compile-rtk-firmware.yml b/.github/workflows/compile-rtk-firmware.yml index cb3c58be7..f28e60008 100644 --- a/.github/workflows/compile-rtk-firmware.yml +++ b/.github/workflows/compile-rtk-firmware.yml @@ -71,7 +71,7 @@ jobs: ArduinoJson@6.19.4 pubsubclient@2.8.0 ESP32_BleSerial@1.0.4 - "SparkFun u-blox GNSS v3"@3.0.7 + "SparkFun u-blox GNSS v3"@3.0.8 "SparkFun MAX1704x Fuel Gauge Arduino Library"@1.0.4 "SparkFun LIS2DH12 Arduino Library"@1.0.3 "ESP32-OTA-Pull"@1.0.0 diff --git a/Firmware/RTK_Surveyor/Base.ino b/Firmware/RTK_Surveyor/Base.ino index 5db7a9fd8..c9a7a9f9b 100644 --- a/Firmware/RTK_Surveyor/Base.ino +++ b/Firmware/RTK_Surveyor/Base.ino @@ -141,9 +141,15 @@ bool surveyInStart() if (surveyInReset() == false) { - systemPrintln("Survey reset failed"); + systemPrintln("Survey reset failed - attempt 1/3"); if (surveyInReset() == false) - systemPrintln("Survey reset failed - 2nd attempt"); + { + systemPrintln("Survey reset failed - attempt 2/3"); + if (surveyInReset() == false) + { + systemPrintln("Survey reset failed - attempt 3/3"); + } + } } } @@ -292,6 +298,13 @@ bool startFixedBase() //Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc. void DevUBLOXGNSS::processRTCM(uint8_t incoming) { + //We need to prevent ntripServerProcessRTCM from writing data via Ethernet (SPI W5500) + //during an SPI checkUbloxSpi... + //We can pass incoming to ntripServerProcessRTCM if the GNSS is I2C or the variant does not have Ethernet. + //For the Ref Stn, processRTCMBuffer is called manually from inside ntripServerUpdate + if ((USE_SPI_GNSS) && (HAS_ETHERNET)) + return; + //Check for too many digits if (settings.enableResetDisplay == true) { @@ -319,3 +332,44 @@ void DevUBLOXGNSS::processRTCM(uint8_t incoming) espnowProcessRTCM(incoming); } } + +//For Ref Stn (USE_SPI_GNSS and HAS_ETHERNET), call ntripServerProcessRTCM manually if there is RTCM data in the buffer +void processRTCMBuffer() +{ + if ((USE_I2C_GNSS) || (!HAS_ETHERNET)) + return; + + //Check if there is any data waiting in the RTCM buffer + uint16_t rtcmBytesAvail = theGNSS.rtcmBufferAvailable(); + if (rtcmBytesAvail > 0) + { + //Check for too many digits + if (settings.enableResetDisplay == true) + { + if (rtcmPacketsSent > 99) rtcmPacketsSent = 1; //Trim to two digits to avoid overlap + } + else + { + if (rtcmPacketsSent > 999) rtcmPacketsSent = 1; //Trim to three digits to avoid log icon and increasing bar + } + + while (rtcmBytesAvail > 0) + { + uint8_t incoming; + + if (theGNSS.extractRTCMBufferData(&incoming, 1) != 1) + return; + + rtcmBytesAvail--; + + //Data in the u-blox library RTCM buffer is pre-checked. We don't need to check it again here. + + rtcmLastReceived = millis(); + rtcmBytesSent++; + + ntripServerProcessRTCM(incoming); + + espnowProcessRTCM(incoming); + } + } +} diff --git a/Firmware/RTK_Surveyor/Begin.ino b/Firmware/RTK_Surveyor/Begin.ino index 12617dab7..e410fb726 100644 --- a/Firmware/RTK_Surveyor/Begin.ino +++ b/Firmware/RTK_Surveyor/Begin.ino @@ -631,6 +631,7 @@ void beginGNSS() //Use gnssHandlerBufferSize for now. TODO: work out if the SPI GNSS needs its own buffer size setting //Also used by Tasks.ino theGNSS.setFileBufferSize(settings.gnssHandlerBufferSize); + theGNSS.setRTCMBufferSize(settings.gnssHandlerBufferSize); } if (USE_I2C_GNSS) @@ -671,6 +672,12 @@ void beginGNSS() displayGNSSFail(1000); return; } + if (theGNSS.getRTCMBufferSize() != settings.gnssHandlerBufferSize) //Need to call getRTCMBufferSize after begin + { + log_d("GNSS offline - no RAM for RTCM buffer"); + displayGNSSFail(1000); + return; + } } //Increase transactions to reduce transfer time @@ -841,7 +848,7 @@ void beginLEDs() //Configure the on board MAX17048 fuel gauge void beginFuelGauge() { - if (productVariant == REFERENCE_STATION) + if (HAS_NO_BATTERY) return; //Reference station does not have a battery //Set up the MAX17048 LiPo fuel gauge diff --git a/Firmware/RTK_Surveyor/Display.ino b/Firmware/RTK_Surveyor/Display.ino index 746db1c7b..6ac393989 100644 --- a/Firmware/RTK_Surveyor/Display.ino +++ b/Firmware/RTK_Surveyor/Display.ino @@ -126,6 +126,21 @@ void beginDisplay() systemPrintln("Display not detected"); } +//Avoid code repetition +void displayBatteryVsEthernet() +{ + if (HAS_BATTERY) + icons |= ICON_BATTERY; //Top right + else //if (HAS_ETHERNET) + { + if (online.ethernetStatus == ETH_CONNECTED) + blinking_icons |= ICON_ETHERNET; //Don't blink if link is up + else + blinking_icons ^= ICON_ETHERNET; + icons |= (blinking_icons & ICON_ETHERNET); //Top Right + } +} + //Given the system state, display the appropriate information void updateDisplay() { @@ -205,16 +220,7 @@ void updateDisplay() | ICON_HORIZONTAL_ACCURACY //Center right | paintSIV() //Bottom left | ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; case (STATE_ROVER_NO_FIX): @@ -222,16 +228,7 @@ void updateDisplay() | ICON_HORIZONTAL_ACCURACY //Center right | paintSIV() //Bottom left | ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; case (STATE_ROVER_FIX): @@ -239,16 +236,7 @@ void updateDisplay() | ICON_HORIZONTAL_ACCURACY //Center right | paintSIV() //Bottom left | ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; case (STATE_ROVER_RTK_FLOAT): @@ -257,16 +245,7 @@ void updateDisplay() | ICON_HORIZONTAL_ACCURACY //Center right | paintSIV() //Bottom left | ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; case (STATE_ROVER_RTK_FIX): @@ -274,16 +253,7 @@ void updateDisplay() | ICON_HORIZONTAL_ACCURACY //Center right | paintSIV() //Bottom left | ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; @@ -300,74 +270,29 @@ void updateDisplay() | ICON_HORIZONTAL_ACCURACY //Center right | paintSIV() //Bottom left | ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; case (STATE_BASE_TEMP_SURVEY_STARTED): icons = ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left paintBaseTempSurveyStarted(); break; case (STATE_BASE_TEMP_TRANSMITTING): icons = ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left paintRTCM(); break; case (STATE_BASE_FIXED_NOT_STARTED): icons = 0; //Top right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left break; case (STATE_BASE_FIXED_TRANSMITTING): icons = ICON_LOGGING; //Bottom right - if (productVariant != REFERENCE_STATION) - icons |= ICON_BATTERY; //Top right - else - { - if (online.ethernetStatus == ETH_CONNECTED) - blinking_icons |= ICON_ETHERNET; //Don't blink if link is up - else - blinking_icons ^= ICON_ETHERNET; - icons |= (blinking_icons & ICON_ETHERNET); //Top Right - } + displayBatteryVsEthernet(); //Top right iconsRadio = setRadioIcons(); //Top left paintRTCM(); break; @@ -3268,7 +3193,7 @@ const uint8_t * getMacAddress() return wifiMACAddress; #endif #ifdef COMPILE_ETHERNET - else if (online.ethernetStatus >= ETH_BEGUN_NO_LINK) + else if ((online.ethernetStatus >= ETH_STARTED_CHECK_CABLE) && (online.ethernetStatus <= ETH_CONNECTED)) return ethernetMACAddress; #endif #endif diff --git a/Firmware/RTK_Surveyor/Form.ino b/Firmware/RTK_Surveyor/Form.ino index 75ac4e461..7dcfab337 100644 --- a/Firmware/RTK_Surveyor/Form.ino +++ b/Firmware/RTK_Surveyor/Form.ino @@ -763,7 +763,12 @@ void createSettingsString(char* newSettings) stringRecord(newSettings, "logFileName", logFileName); - if (productVariant != REFERENCE_STATION) //Ref Stn does not have a battery + if (HAS_NO_BATTERY) //Ref Stn does not have a battery + { + stringRecord(newSettings, "batteryIconFileName", "src/BatteryBlank.png"); + stringRecord(newSettings, "batteryPercent", " "); + } + else { //Determine battery icon int iconLevel = 0; @@ -921,7 +926,12 @@ void createDynamicDataString(char* settingsCSV) stringRecord(settingsCSV, "ecefY", ecefY, 3); stringRecord(settingsCSV, "ecefZ", ecefZ, 3); - if (productVariant != REFERENCE_STATION) //Ref Stn does not have a battery + if (HAS_NO_BATTERY) //Ref Stn does not have a battery + { + stringRecord(settingsCSV, "batteryIconFileName", "src/BatteryBlank.png"); + stringRecord(settingsCSV, "batteryPercent", " "); + } + else { //Determine battery icon int iconLevel = 0; diff --git a/Firmware/RTK_Surveyor/NtripClient.ino b/Firmware/RTK_Surveyor/NtripClient.ino index ec332ac71..76f2bfae0 100644 --- a/Firmware/RTK_Surveyor/NtripClient.ino +++ b/Firmware/RTK_Surveyor/NtripClient.ino @@ -367,12 +367,7 @@ void ntripClientUpdate() #ifdef COMPILE_ETHERNET if (HAS_ETHERNET) { - if (online.ethernetStatus < ETH_BEGUN_NO_LINK) - { - systemPrintln("Error: Please connect Ethernet before starting NTRIP Client"); - ntripClientStop(true); //Do not allocate new wifiClient - } - else + if ((online.ethernetStatus >= ETH_STARTED_CHECK_CABLE) && (online.ethernetStatus <= ETH_CONNECTED)) { //Pause until connection timeout has passed if (millis() - ntripClientLastConnectionAttempt > ntripClientConnectionAttemptTimeout) @@ -382,6 +377,11 @@ void ntripClientUpdate() ntripClientSetState(NTRIP_CLIENT_WIFI_ETHERNET_STARTED); } } + else + { + systemPrintln("Error: Please connect Ethernet before starting NTRIP Client"); + ntripClientStop(true); //Do not allocate new wifiClient + } } else #endif @@ -412,7 +412,7 @@ void ntripClientUpdate() { if (online.ethernetStatus == ETH_CONNECTED) ntripClientSetState(NTRIP_CLIENT_WIFI_ETHERNET_CONNECTED); - else if (online.ethernetStatus >= ETH_BEGUN_NO_LINK) + else ntripClientSetState(NTRIP_CLIENT_OFF); } else diff --git a/Firmware/RTK_Surveyor/NtripServer.ino b/Firmware/RTK_Surveyor/NtripServer.ino index d4c02373d..44d66a2da 100644 --- a/Firmware/RTK_Surveyor/NtripServer.ino +++ b/Firmware/RTK_Surveyor/NtripServer.ino @@ -336,6 +336,10 @@ void ntripServerUpdate() return; } + //For Ref Stn, process any RTCM data waiting in the u-blox library RTCM Buffer + //This causes the state change from NTRIP_SERVER_WAIT_GNSS_DATA to NTRIP_SERVER_CONNECTING + processRTCMBuffer(); + if (settings.enableNtripServer == false) { //If user turns off NTRIP Server via settings, stop server @@ -365,12 +369,7 @@ void ntripServerUpdate() #ifdef COMPILE_ETHERNET if (HAS_ETHERNET) { - if (online.ethernetStatus < ETH_BEGUN_NO_LINK) - { - systemPrintln("Error: Please connect Ethernet before starting NTRIP Server"); - ntripServerStop(true); //Do not allocate new wifiClient - } - else + if ((online.ethernetStatus >= ETH_STARTED_CHECK_CABLE) && (online.ethernetStatus <= ETH_CONNECTED)) { //Pause until connection timeout has passed if (millis() - ntripServerLastConnectionAttempt > ntripServerConnectionAttemptTimeout) @@ -380,6 +379,11 @@ void ntripServerUpdate() ntripServerSetState(NTRIP_SERVER_WIFI_ETHERNET_STARTED); } } + else + { + systemPrintln("Error: Please connect Ethernet before starting NTRIP Server"); + ntripServerStop(true); //Do not allocate new wifiClient + } } else #endif @@ -410,7 +414,7 @@ void ntripServerUpdate() { if (online.ethernetStatus == ETH_CONNECTED) ntripServerSetState(NTRIP_SERVER_WIFI_ETHERNET_CONNECTED); - else if (online.ethernetStatus >= ETH_BEGUN_NO_LINK) + else ntripServerSetState(NTRIP_SERVER_OFF); } else diff --git a/Firmware/RTK_Surveyor/States.ino b/Firmware/RTK_Surveyor/States.ino index 2a93dea39..82e5c58e5 100644 --- a/Firmware/RTK_Surveyor/States.ino +++ b/Firmware/RTK_Surveyor/States.ino @@ -347,7 +347,18 @@ void updateSystemState() { systemPrintf("Survey-In took more than %d minutes. Returning to rover mode.\r\n", maxSurveyInWait_s / 60); - surveyInReset(); + if (surveyInReset() == false) + { + systemPrintln("Survey reset failed - attempt 1/3"); + if (surveyInReset() == false) + { + systemPrintln("Survey reset failed - attempt 2/3"); + if (surveyInReset() == false) + { + systemPrintln("Survey reset failed - attempt 3/3"); + } + } + } changeState(STATE_ROVER_NOT_STARTED); } diff --git a/Firmware/RTK_Surveyor/form.h b/Firmware/RTK_Surveyor/form.h index 5b2dac0d4..215c429de 100644 --- a/Firmware/RTK_Surveyor/form.h +++ b/Firmware/RTK_Surveyor/form.h @@ -26,7 +26,7 @@ // python main_js_zipper.py static const uint8_t main_js[] PROGMEM = { - 0x1F, 0x8B, 0x08, 0x08, 0x7B, 0x44, 0x40, 0x64, 0x02, 0xFF, 0x6D, 0x61, 0x69, 0x6E, 0x2E, 0x6A, + 0x1F, 0x8B, 0x08, 0x08, 0x2E, 0xCF, 0x41, 0x64, 0x02, 0xFF, 0x6D, 0x61, 0x69, 0x6E, 0x2E, 0x6A, 0x73, 0x2E, 0x67, 0x7A, 0x69, 0x70, 0x00, 0xED, 0x7D, 0xEB, 0x5A, 0x1B, 0x3B, 0xB2, 0xE8, 0xFF, 0xF9, 0xBE, 0x79, 0x07, 0x8D, 0xCF, 0x3A, 0x63, 0x7B, 0x30, 0xC6, 0x36, 0xF7, 0x10, 0xB2, 0x0F, 0x60, 0x48, 0x38, 0x83, 0xC1, 0x1F, 0x26, 0xC9, 0x4A, 0xD6, 0xE4, 0xB0, 0x1B, 0x5B, 0x98, 0x9E, @@ -790,7 +790,7 @@ static const uint8_t main_js[] PROGMEM = { // python index_html_zipper.py static const uint8_t index_html[] PROGMEM = { - 0x1F, 0x8B, 0x08, 0x08, 0x7D, 0x44, 0x40, 0x64, 0x02, 0xFF, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x2E, + 0x1F, 0x8B, 0x08, 0x08, 0x22, 0xCF, 0x41, 0x64, 0x02, 0xFF, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x2E, 0x67, 0x7A, 0x69, 0x70, 0x00, 0xED, 0x7D, 0xFB, 0x72, 0xE2, 0x48, 0xB3, 0xE7, 0xFF, 0x1B, 0xB1, 0xEF, 0x50, 0x1F, 0x67, 0xCF, 0xB6, 0x7B, 0x8F, 0xC1, 0x80, 0xF1, 0x75, 0xBA, 0x1D, 0x81, 0xF1, 0xA5, 0x1D, 0x9F, 0x2F, 0xAC, 0x61, 0xBA, 0x67, 0x66, 0x63, 0xB7, diff --git a/Firmware/RTK_Surveyor/menuEthernet.ino b/Firmware/RTK_Surveyor/menuEthernet.ino index c6972b456..aa552e97f 100644 --- a/Firmware/RTK_Surveyor/menuEthernet.ino +++ b/Firmware/RTK_Surveyor/menuEthernet.ino @@ -17,10 +17,6 @@ void beginEthernet() switch (online.ethernetStatus) { - default: - log_d("Unknown status"); - break; - case (ETH_NOT_STARTED): Ethernet.init(pin_Ethernet_CS); @@ -90,6 +86,9 @@ void beginEthernet() case (ETH_CAN_NOT_BEGIN): break; + default: + log_d("Unknown status"); + break; } #endif ///COMPILE_ETHERNET } diff --git a/Firmware/RTK_Surveyor/settings.h b/Firmware/RTK_Surveyor/settings.h index c5baba01b..0020ecfdd 100644 --- a/Firmware/RTK_Surveyor/settings.h +++ b/Firmware/RTK_Surveyor/settings.h @@ -81,6 +81,10 @@ ProductVariant productVariant = RTK_SURVEYOR; //The rising edge of the TP signal indicates the true top-of-second #define HAS_GNSS_TP_INT (productVariant == REFERENCE_STATION) +//Macro to show if the the RTK variant has no battery +#define HAS_NO_BATTERY (productVariant == REFERENCE_STATION) +#define HAS_BATTERY (!HAS_NO_BATTERY) + typedef enum { BUTTON_ROVER = 0, diff --git a/Firmware/Tools/index_html_zipper.py b/Firmware/Tools/index_html_zipper.py index 56385b394..2e3e51093 100644 --- a/Firmware/Tools/index_html_zipper.py +++ b/Firmware/Tools/index_html_zipper.py @@ -126,7 +126,10 @@ content = f_in_2.read() count = 0 + for c in content[:-2]: + if count == 0: + f_out.write(bytes(' ', 'utf-8')) f_out.write(bytes("0x{:02X},".format(c), 'utf-8')) count += 1 if count == 16: @@ -135,6 +138,8 @@ else: f_out.write(bytes(' ', 'utf-8')) + if count == 0: + f_out.write(bytes(' ', 'utf-8')) f_out.write(bytes("0x{:02X}\r\n".format(content[-1]), 'utf-8')) f_out.write(f_in_3.read()) diff --git a/Firmware/Tools/main_js_zipper.py b/Firmware/Tools/main_js_zipper.py index 3f5b507de..56c27dcff 100644 --- a/Firmware/Tools/main_js_zipper.py +++ b/Firmware/Tools/main_js_zipper.py @@ -126,7 +126,10 @@ content = f_in_2.read() count = 0 + for c in content[:-2]: + if count == 0: + f_out.write(bytes(' ', 'utf-8')) f_out.write(bytes("0x{:02X},".format(c), 'utf-8')) count += 1 if count == 16: @@ -135,6 +138,8 @@ else: f_out.write(bytes(' ', 'utf-8')) + if count == 0: + f_out.write(bytes(' ', 'utf-8')) f_out.write(bytes("0x{:02X}\r\n".format(content[-1]), 'utf-8')) f_out.write(f_in_3.read()) diff --git a/Firmware/Tools/png_zipper.py b/Firmware/Tools/png_zipper.py index 2c07f9b40..12ecf9c85 100644 --- a/Firmware/Tools/png_zipper.py +++ b/Firmware/Tools/png_zipper.py @@ -70,6 +70,8 @@ content = f_in.read() count = 0 for c in content[:-2]: + if count == 0: + f_out.write(bytes(' ', 'utf-8')) f_out.write(bytes("0x{:02X},".format(c), 'utf-8')) count += 1 if count == 16: @@ -78,6 +80,8 @@ else: f_out.write(bytes(' ', 'utf-8')) + if count == 0: + f_out.write(bytes(' ', 'utf-8')) f_out.write(bytes("0x{:02X}\r\n".format(content[-1]), 'utf-8')) print('Step 3: delete',zippedfilename)