Skip to content

Commit

Permalink
iot2050-eio-manager: Add module firmware update
Browse files Browse the repository at this point in the history
Signed-off-by: Li Hua Qian <[email protected]>
  • Loading branch information
huaqianli committed Dec 18, 2023
1 parent 8ebd309 commit 2c3b067
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ message SyncTimeReply {
*/
message UpdateFirmwareRequest {
int32 entity = 1;
string firmware = 2;
bytes firmware = 2;
string firmware_type = 3;
}

/* UpdateFirmwareReply
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ class SyncTimeReply(_message.Message):
def __init__(self, status: _Optional[int] = ..., message: _Optional[str] = ...) -> None: ...

class UpdateFirmwareRequest(_message.Message):
__slots__ = ["entity", "firmware"]
__slots__ = ["entity", "firmware", "firmware_type"]
ENTITY_FIELD_NUMBER: _ClassVar[int]
FIRMWARE_FIELD_NUMBER: _ClassVar[int]
FIRMWARE_TYPE_FIELD_NUMBER: _ClassVar[int]
entity: int
firmware: str
def __init__(self, entity: _Optional[int] = ..., firmware: _Optional[str] = ...) -> None: ...
firmware: bytes
firmware_type: str
def __init__(self, entity: _Optional[int] = ..., firmware: _Optional[bytes] = ..., firmware_type: _Optional[str] = ...) -> None: ...

class UpdateFirmwareReply(_message.Message):
__slots__ = ["status", "message"]
Expand Down
74 changes: 54 additions & 20 deletions recipes-app/iot2050-eio-manager/files/iot2050-eio-cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def show_progress_bar(task, interval):
time.sleep(interval)


def do_update_firmware(firmware):
def do_update_firmware(firmware, firmware_type):
with grpc.insecure_channel(iot2050_eio_api_server) as channel:
stub = EIOManagerStub(channel)
print("===================================================")
Expand All @@ -65,7 +65,8 @@ def do_update_firmware(firmware):
with ThreadPoolExecutor(max_workers=1) as pool:
future = pool.submit(
stub.UpdateFirmware,
UpdateFirmwareRequest(firmware=firmware)
UpdateFirmwareRequest(firmware=firmware,
firmware_type=firmware_type)
)
show_progress_bar(future, 0.3)
print()
Expand All @@ -86,8 +87,10 @@ def do_update_firmware(firmware):
2. %(prog)s config retrieve config.yaml
Retrieve the config from Extended IO Controller and store into config.yaml
3. %(prog)s fwu controller [firmware.bin]
update firmware for Extended IO Controller, using firmware.bin if provided,
Update firmware for Extended IO Controller, using firmware.bin if provided,
otherwise using the stock firmware file.
3. %(prog)s fwu module -s 1 -fwa fwa.bin
Update firmware a of the module in slot 1
Example Configuration File:
Expand All @@ -112,11 +115,27 @@ def do_update_firmware(firmware):
help='Config file in yaml format')

fwu_parser = subparsers.add_parser("fwu", help='firmware update help')
fwu_parser.add_argument('action', metavar='ACTION',
choices=['controller', 'module'],
help='Specify the firmware update type')
fwu_parser.add_argument('firmware', nargs='?', metavar='FIRMWARE', type=str,
help='Firmware file')
fwu_subparsers = fwu_parser.add_subparsers(help='sub-command help',
title='fwu-commands',
dest="fwu_command")
controller_parser = fwu_subparsers.add_parser("controller", help='controller help')
controller_parser.add_argument('firmware', nargs='?', metavar='FIRMWARE',
type=argparse.FileType('rb'),
help='Firmware file')
module_parser = fwu_subparsers.add_parser("module", help='module help')
module_parser.add_argument('firmware', nargs='?', metavar='FIRMWARE',
type=argparse.FileType('rb'),
help='Firmware file')
module_parser.add_argument('-s', '--slot',
help='Specify the slot number',
nargs=1)
group = module_parser.add_mutually_exclusive_group()
group.add_argument('-fwa', '--firmware-a',
help='Update firmware a of module',
action='store_true')
group.add_argument('-fwb', '--firmware-b',
help='Update firmware b of module',
action='store_true')

args = parser.parse_args()

Expand All @@ -142,23 +161,38 @@ def do_update_firmware(firmware):
with open(args.config, 'w', encoding='ascii') as f_config:
f_config.write(config_returned)
elif args.command == 'fwu':
if args.firmware:
firmware = args.firmware
else:
firmware = EIO_FWU_MAP3_FW_BIN
status, message = do_fwu_check()
if status == 0:
# no need to update!
print(message)
sys.exit(0)
if args.fwu_command == 'controller':
if args.firmware:
firmware = args.firmware.read()
else:
firmware = EIO_FWU_MAP3_FW_BIN
status, message = do_fwu_check()
if status == 0:
# no need to update!
print(message)
sys.exit(0)

response = do_update_firmware(firmware, "map3")
elif args.fwu_command == 'module':
if not args.slot or \
(not args.firmware_a and not args.firmware_b):
module_parser.print_help(sys.stderr)
sys.exit(1)
if args.firmware_a:
firmware_type = f'slot{args.slot[0]}/fwa'
elif args.firmware_b:
firmware_type = f'slot{args.slot[0]}/fwb'
firmware = args.firmware.read()
response = do_update_firmware(firmware, firmware_type)

response = do_update_firmware(firmware)
if response.status:
print(f"ERROR: {response.message}")
print("EIO firmware update failed, please try again!")
print(f"EIO {args.fwu_command} firmware update failed, please try again!")
sys.exit(1)

print("EIO firmware update completed. Please reboot the device.")
print(f"EIO {args.fwu_command} firmware update completed."
f" Please reboot the {args.fwu_command}!")
else:
parser.print_help(sys.stderr)
sys.exit(1)

Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def SyncTime(self, request: SyncTimeRequest, context):
return SyncTimeReply(status=0, message=f'{time}')

def UpdateFirmware(self, request: UpdateFirmwareRequest, context):
status, message = update_firmware(request.firmware)
status, message = update_firmware(request.firmware, request.firmware_type)
return UpdateFirmwareReply(status=status, message=f'{message}')

def CheckFWU(self, request: CheckFWURequest, context):
Expand Down
51 changes: 36 additions & 15 deletions recipes-app/iot2050-eio-manager/files/iot2050_eio_fwu.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from iot2050_eio_global import (
EIO_FS_FW_VER,
EIO_FWU_META,
EIO_MODULE_PATH,
EIO_FWU_MAP3_FW_BIN
)

Expand Down Expand Up @@ -74,7 +75,7 @@ class EIOFirmware():
MAP3_CERTIFICATE_OFFSET = MAP3_FLASH_SIZE_1_MB - 32 * 1024

def __init__(self, firmware):
self.firmware = open(firmware, "rb")
self.firmware = firmware

self.chip = gpiod.Chip("/dev/gpiochip2")
self.spi_mux_pin = self.chip.get_line(86)
Expand All @@ -95,8 +96,7 @@ def __get_write_firmware(self):
read_buffer = ctypes.create_string_buffer(self.MAP3_FLASH_SIZE_1_MB)
self.flash_prog.read(read_buffer, self.MAP3_FLASH_SIZE_1_MB)

self.firmware.seek(0)
write_firmware = self.firmware.read()
write_firmware = self.firmware
# Firmware and certificate partitions are required, other
# partitions are reserved.
write_firmware = write_firmware[:self.MAP3_FIRMWARE_SIZE] \
Expand Down Expand Up @@ -128,31 +128,52 @@ def __del__(self):
self.spi_mux_pin.release()
if hasattr(self, "flash_prog") and self.flash_prog:
self.flash_prog.release()
self.firmware.close()


class ModuleFirmware():
def __init__(self, firmware, firmware_type):
self.firmware = firmware
self.firmware_target = EIO_MODULE_PATH + firmware_type

def write(self):
with open(self.firmware_target, "wb") as f:
try:
f.write(self.firmware)
except OSError as e:
raise UpgradeError(f"ModuleFirmware writes failed: {e}")


class FirmwareUpdate():
"""
The FirmwareUpdate models the firmware updating behavior for all
firmware update.
"""
def __init__(self, firmware):
def __init__(self, firmware, firmware_type):
self.firmwares = {}
self.firmwares["map3"] = EIOFirmware(firmware)
self.to_verify = True
if "map3" == firmware_type:
self.firmwares[firmware_type] = EIOFirmware(firmware)
if "slot" in firmware_type:
self.firmwares[firmware_type] = ModuleFirmware(firmware, firmware_type)
self.to_verify = False

if not self.firmwares:
raise UpgradeError("No valid firmware!")

def update(self):
"""Update the firmware to the specified flash"""

for firmware_type in self.firmwares:
self.firmwares[firmware_type].write()

content = self.firmwares[firmware_type].write_firmware
firmware_md5 = self.__get_md5_digest(content)
content = self.firmwares[firmware_type].read()
read_out_md5 = self.__get_md5_digest(content)
if self.to_verify:
content = self.firmwares[firmware_type].write_firmware
firmware_md5 = self.__get_md5_digest(content)
content = self.firmwares[firmware_type].read()
read_out_md5 = self.__get_md5_digest(content)

if firmware_md5 != read_out_md5:
raise UpgradeError("Firmware digest verification failed")
if firmware_md5 != read_out_md5:
raise UpgradeError("Firmware digest verification failed")

def __get_md5_digest(self, content):
"""Verify the update integrity"""
Expand Down Expand Up @@ -180,7 +201,7 @@ def collect_fwu_info(self) -> tuple[int, str]:
Returns:
tuple[int, str]:
The 1st int element indicates the firmware status:
- 0: means no need to update
- 1: means firmware need update.
- 2: means firmware need update, however, the firmware
Expand Down Expand Up @@ -208,9 +229,9 @@ def collect_fwu_info(self) -> tuple[int, str]:
return status, message


def update_firmware(firmware):
def update_firmware(firmware, firmware_type):
try:
FirmwareUpdate(firmware).update()
FirmwareUpdate(firmware, firmware_type).update()
return 0, "Firmware upgrade successfully!"
except UpgradeError as e:
return 1, e
4 changes: 4 additions & 0 deletions recipes-app/iot2050-eio-manager/files/iot2050_eio_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
# Extended IO FUSE filesystem path for eio events
'EIO_FS_EVENT': '/eiofs/log/event',

# Extended IO FUSE filesystem path for modules
'EIO_MODULE_PATH': '/eiofs/controller/',

# EIO Firmware Update: Meta data
'EIO_FWU_META': '/usr/lib/iot2050/eio/firmware-version',

Expand Down Expand Up @@ -57,6 +60,7 @@
EIO_FS_CONFIG = effective_conf['EIO_FS_CONFIG']
EIO_FS_FW_VER = effective_conf['EIO_FS_FW_VER']
EIO_FS_EVENT = effective_conf['EIO_FS_EVENT']
EIO_MODULE_PATH = effective_conf['EIO_MODULE_PATH']
EIO_FWU_META = effective_conf['EIO_FWU_META']
EIO_FWU_MAP3_FW_BIN = effective_conf['EIO_FWU_MAP3_FW_BIN']
EIO_SCHEMA_ROOT = effective_conf['EIO_SCHEMA_ROOT']
Expand Down

0 comments on commit 2c3b067

Please sign in to comment.