Skip to content

Commit

Permalink
use cmake to generate OTA and patch bin firmware
Browse files Browse the repository at this point in the history
  • Loading branch information
devbis committed Oct 8, 2023
1 parent deff0e3 commit 604757c
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 2 deletions.
15 changes: 14 additions & 1 deletion cmake/TelinkSDK.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ SET(CMAKE_ASM_FLAGS "-fomit-frame-pointer -fshort-enums -Wall -Wpacked -Wcast-al
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections -Wl,-uss_apsmeSwitchKeyReq -Os -fshort-enums -nostartfiles -fno-rtti -fno-exceptions -fno-use-cxa-atexit -fno-threadsafe-statics -Wl,--gc-sections " CACHE INTERNAL "executable linker flags")


FUNCTION(ADD_BIN_TARGET TARGET)
FUNCTION(ADD_BIN_TARGET TARGET TOOLS_PATH)
IF(EXECUTABLE_OUTPUT_PATH)
SET(FILENAME "${EXECUTABLE_OUTPUT_PATH}/${TARGET}")
ELSE()
Expand All @@ -35,6 +35,19 @@ FUNCTION(ADD_BIN_TARGET TARGET)
ADD_CUSTOM_TARGET("${TARGET}.bin"
DEPENDS ${TARGET}
COMMAND ${CMAKE_OBJCOPY} -Obinary ${FILENAME} ${FILENAME}.bin
COMMAND python3 ${TOOLS_PATH}/tl_check_fw.py ${FILENAME}.bin
)
ENDFUNCTION()

FUNCTION(ADD_OTA_TARGET TARGET TOOLS_PATH)
IF(EXECUTABLE_OUTPUT_PATH)
SET(FILENAME "${EXECUTABLE_OUTPUT_PATH}/${TARGET}")
ELSE()
SET(FILENAME "${TARGET}")
ENDIF()
ADD_CUSTOM_TARGET("${TARGET}.ota"
DEPENDS ${TARGET}.bin
COMMAND python3 ${TOOLS_PATH}/make_ota.py ${FILENAME}.bin -o ${FILENAME}.ota
)
ENDFUNCTION()

Expand Down
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,5 @@ TARGET_LINK_LIBRARIES(${TARGET}
-Wl,--end-group
)

ADD_BIN_TARGET(${TARGET})
ADD_BIN_TARGET(${TARGET} ${PROJECT_SOURCE_DIR}/tools)
ADD_OTA_TARGET(${TARGET} ${PROJECT_SOURCE_DIR}/tools)
61 changes: 61 additions & 0 deletions tools/make_ota.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env python3

import argparse
import binascii
import struct

OTA_MAGIC = b'\x5d\x02'


def main(args):
assert args.input_file != args.output

with open(args.input_file, 'rb') as bin_file:
bin_file.seek(0, 0)
firmware = bytearray(bin_file.read(-1))
if firmware[6:8] != OTA_MAGIC:
# Ensure FW size is multiple of 16
padding = 16 - len(firmware) % 16
if padding < 16:
firmware += b'\xFF' * padding
# Fix FW length
firmware[0x18:0x1c] = (len(firmware) + 4).to_bytes(4, byteorder='little')
# Add magic constant
firmware[6:8] = OTA_MAGIC
# Add CRC
crc = binascii.crc32(firmware) ^ 0xffffffff
firmware += crc.to_bytes(4, byteorder='little')

ota_hdr_s = struct.Struct('<I5HIH32sI')
header_size = 56
firmware_len = len(firmware)
total_image_size = firmware_len + header_size + 6
ota_hdr = ota_hdr_s.pack(
0xbeef11e,
0x100, # header version is 0x0100
header_size,
0, # ota_ext_hdr_value if ota_ext_hdr else 0,
int.from_bytes(firmware[18:20], byteorder='little'), # args.manufacturer,
int.from_bytes(firmware[20:22], byteorder='little'), # args.image_type,
args.set_version or int.from_bytes(firmware[2:6], byteorder='little'), # 0x10023001 # options.File_Version
args.ota_version, # options.stack_version,
b'\x00' * 32, # OTA_Header_String.encode(),
total_image_size,
)
ota_hdr += struct.pack('<HI', 0, firmware_len)
with open(args.output, 'wb') as output:
bin_file.seek(0, 0)
output.write(ota_hdr)
output.write(firmware)
print("%s was created with ZCL OTA Header." % args.output)


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("input_file", help="path to input file")
parser.add_argument("-o", '--output', help="path to output file", required=True)
# sync with g_zcl_basicAttrs.stackVersion
parser.add_argument("-s", '--ota-version', type=int, help="OTA stack version", default=2)
parser.add_argument("-v", '--set-version', type=lambda x: int(x, 0), help="Override version from BIN")
_args = parser.parse_args()
main(_args)
26 changes: 26 additions & 0 deletions tools/tl_check_fw.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python3

import binascii
import sys
# https://github.com/pvvx/ATC_MiThermometer/issues/186#issuecomment-1030410603
with open(sys.argv[1], 'rb') as f:
firmware = bytearray(f.read(-1))

if firmware[6:8] != b'\x5d\x02':
# Ensure FW size is multiple of 16
padding = 16 - len(firmware) % 16
if padding < 16:
firmware += b'\xFF' * padding
# Fix FW length
firmware[0x18:0x1c] = (len(firmware)+4).to_bytes(4, byteorder='little')
# Add magic constant
firmware[6:8] = b'\x5d\x02'
# Add CRC
crc = binascii.crc32(firmware) ^ 0xffffffff
firmware += crc.to_bytes(4, byteorder='little')
# Write the new firmware back to the file
with open(sys.argv[1], 'wb') as f:
f.write(firmware)
print("Firmware patched!")
else:
print("Firmware already patched!")

0 comments on commit 604757c

Please sign in to comment.