diff --git a/Tools/AP_Bootloader/bl_protocol.cpp b/Tools/AP_Bootloader/bl_protocol.cpp index a270abb81e031..193c39780cd60 100644 --- a/Tools/AP_Bootloader/bl_protocol.cpp +++ b/Tools/AP_Bootloader/bl_protocol.cpp @@ -49,12 +49,17 @@ #include "bl_protocol.h" #include "support.h" #include "can.h" +#include "AP_Bootloader_config.h" #include #if EXT_FLASH_SIZE_MB #include #endif #include +#define FORCE_VERSION_H_INCLUDE +#include "ap_version.h" +#undef FORCE_VERSION_H_INCLUDE + // #pragma GCC optimize("O0") @@ -106,6 +111,7 @@ #define PROTO_GET_CHIP 0x2c // read chip version (MCU IDCODE) #define PROTO_SET_DELAY 0x2d // set minimum boot delay #define PROTO_GET_CHIP_DES 0x2e // read chip version In ASCII +#define PROTO_GET_VERSION 0x2f // read version #define PROTO_BOOT 0x30 // boot the application #define PROTO_DEBUG 0x31 // emit debug information - format not defined #define PROTO_SET_BAUD 0x33 // baud rate on uart @@ -1047,6 +1053,29 @@ bootloader(unsigned timeout) } break; + // read the bootloader version (not to be confused with protocol revision) + // + // command: GET_VERSION/EOC + // reply: /INSYNC/OK + case PROTO_GET_VERSION: { + uint8_t buffer[MAX_VERSION_LENGTH]; + + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + uint32_t len = strlen(GIT_VERSION_EXTENDED); + if (len > MAX_VERSION_LENGTH) { + len = MAX_VERSION_LENGTH; + } + memcpy(buffer, GIT_VERSION_EXTENDED, len); + + cout_word(len); + cout(buffer, len); + } + break; + #ifdef BOOT_DELAY_ADDRESS case PROTO_SET_DELAY: { diff --git a/Tools/AP_Bootloader/bl_protocol.h b/Tools/AP_Bootloader/bl_protocol.h index cb56bf6f3837c..0eb3858fc9cf7 100644 --- a/Tools/AP_Bootloader/bl_protocol.h +++ b/Tools/AP_Bootloader/bl_protocol.h @@ -14,6 +14,7 @@ void bootloader(unsigned timeout); #endif #define MAX_DES_LENGTH 20 +#define MAX_VERSION_LENGTH 32 #define arraySize(a) (sizeof((a))/sizeof(((a)[0]))) diff --git a/Tools/AP_Bootloader/wscript b/Tools/AP_Bootloader/wscript index 172db17626123..89c7e545bb83f 100644 --- a/Tools/AP_Bootloader/wscript +++ b/Tools/AP_Bootloader/wscript @@ -10,6 +10,8 @@ def build(bld): else: flashiface_lib = [] + _build_dynamic_sources(bld) + bld.ap_stlib( name= 'AP_Bootloader_libs', use='dronecan', @@ -34,3 +36,19 @@ def build(bld): use=['AP_Bootloader_libs', 'libcanard', 'dronecan'], program_groups='bootloader' ) + +def _build_dynamic_sources(bld): + def write_version_header(tsk): + bld = tsk.generator.bld + return bld.write_version_header(tsk.outputs[0].abspath()) + + bld( + name='ap_version', + target='ap_version.h', + vars=['AP_VERSION_ITEMS'], + rule=write_version_header, + ) + + bld.env.prepend_value('INCLUDES', [ + bld.bldnode.abspath(), + ]) diff --git a/Tools/ardupilotwaf/boards.py b/Tools/ardupilotwaf/boards.py index b3382ee88370c..b80f760f0ccf0 100644 --- a/Tools/ardupilotwaf/boards.py +++ b/Tools/ardupilotwaf/boards.py @@ -553,7 +553,9 @@ def pre_build(self, bld): self.embed_ROMFS_files(bld) def build(self, bld): + git_hash_ext = bld.git_head_hash(short=True, hash_abbrev=16) bld.ap_version_append_str('GIT_VERSION', bld.git_head_hash(short=True)) + bld.ap_version_append_str('GIT_VERSION_EXTENDED', git_hash_ext) bld.ap_version_append_int('GIT_VERSION_INT', int("0x" + bld.git_head_hash(short=True), base=16)) bld.ap_version_append_str('AP_BUILD_ROOT', bld.srcnode.abspath()) import time diff --git a/Tools/ardupilotwaf/git_submodule.py b/Tools/ardupilotwaf/git_submodule.py index e2c727e05bb97..05edf06ae065a 100644 --- a/Tools/ardupilotwaf/git_submodule.py +++ b/Tools/ardupilotwaf/git_submodule.py @@ -156,19 +156,19 @@ def _post_fun(bld): def git_submodule_post_fun(bld): bld.add_post_fun(_post_fun) -def _git_head_hash(ctx, path, short=False): +def _git_head_hash(ctx, path, short=False, hash_abbrev=8): cmd = [ctx.env.get_flat('GIT'), 'rev-parse'] if short: - cmd.append('--short=8') + cmd.append(f'--short={hash_abbrev}') cmd.append('HEAD') out = ctx.cmd_and_log(cmd, quiet=Context.BOTH, cwd=path) return out.strip() @conf -def git_submodule_head_hash(self, name, short=False): +def git_submodule_head_hash(self, name, short=False, hash_abbrev=8): module_node = self.srcnode.make_node(os.path.join('modules', name)) - return _git_head_hash(self, module_node.abspath(), short=short) + return _git_head_hash(self, module_node.abspath(), short=short, hash_abbrev=hash_abbrev) @conf -def git_head_hash(self, short=False): - return _git_head_hash(self, self.srcnode.abspath(), short=short) +def git_head_hash(self, short=False, hash_abbrev=8): + return _git_head_hash(self, self.srcnode.abspath(), short=short, hash_abbrev=hash_abbrev) diff --git a/Tools/scripts/uploader.py b/Tools/scripts/uploader.py index b926b26c23279..936c1496b8008 100755 --- a/Tools/scripts/uploader.py +++ b/Tools/scripts/uploader.py @@ -225,6 +225,7 @@ class uploader(object): GET_CHIP = b'\x2c' # rev5+ , get chip version SET_BOOT_DELAY = b'\x2d' # rev5+ , set boot delay GET_CHIP_DES = b'\x2e' # rev5+ , get chip description in ASCII + GET_SOFTWARE = b'\x2f' MAX_DES_LENGTH = 20 REBOOT = b'\x30' @@ -262,7 +263,8 @@ def __init__(self, source_system=None, source_component=None, no_extf=False, - force_erase=False): + force_erase=False, + identify_only=False): self.MAVLINK_REBOOT_ID1 = bytearray(b'\xfe\x21\x72\xff\x00\x4c\x00\x00\x40\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x01\x00\x00\x53\x6b') # NOQA self.MAVLINK_REBOOT_ID0 = bytearray(b'\xfe\x21\x45\xff\x00\x4c\x00\x00\x40\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x00\x00\x00\xcc\x37') # NOQA if target_component is None: @@ -273,6 +275,7 @@ def __init__(self, source_component = 1 self.no_extf = no_extf self.force_erase = force_erase + self.identify_only = identify_only # open the port, keep the default timeout short so we can poll quickly self.port = serial.Serial(portname, baudrate_bootloader, timeout=2.0, write_timeout=2.0) @@ -437,6 +440,17 @@ def __getCHIPDes(self): peices = value.split(",") return peices + # send the GET_SOFTWARE command + def __getBootloaderSoftware(self): + self.__send(uploader.GET_SOFTWARE + uploader.EOC) + length = self.__recv_int() + print(f"RX Len: {length}") + value = self.__recv(length) + if runningPython3: + value = value.decode('ascii') + self.__getSync() + return value + def __drawProgressBar(self, label, progress, maxVal): if maxVal < progress: progress = maxVal @@ -737,6 +751,13 @@ def identify(self): self.board_rev = self.__getInfo(uploader.INFO_BOARD_REV) self.fw_maxsize = self.__getInfo(uploader.INFO_FLASH_SIZE) + if self.identify_only: + # Only run if we are trying to identify the board + try: + self.git_hash_bl = self.__getBootloaderSoftware() + except Exception: + self.__sync() + def dump_board_info(self): # OTP added in v4: print("Bootloader Protocol: %u" % self.bl_rev) @@ -839,6 +860,9 @@ def dump_board_info(self): print(" board_type: %u" % self.board_type) print(" board_rev: %u" % self.board_rev) + if hasattr(self, "git_hash_bl") and self.git_hash_bl is not None: + print(" git hash (Bootloader): %s" % self.git_hash_bl) + print("Identification complete") def board_name_for_board_id(self, board_id): @@ -1162,7 +1186,8 @@ def main(): args.source_system, args.source_component, args.no_extf, - args.force_erase) + args.force_erase, + args.identify) except Exception as e: if not is_WSL and not is_WSL2 and "win32" not in _platform: