vouch-opensource / mcumgr-client

client for mcumgr commands
Apache License 2.0
31 stars 13 forks source link

How to switch to the image uploaded in the slot 1? #19

Open umair-uas opened 9 months ago

umair-uas commented 9 months ago

The go mcumgr client has some commands for image test and image confirm <hash> to test and confirm the uploaded image, I don't seem to see how it is done using this client. I am able to upload the image and can also reset ,the functionality that was just added I think. But I am not able to switch to the newly uploaded image.

Here is what I mean :

 mcumgr-client -d /dev/ttyACM0 list
mcumgr-client 0.0.3, Copyright © 2023 Vouch.io LLC

13:44:25 [INFO] send image list request
13:44:25 [INFO] response: {
  "images": [
    {
      "hash": [
        143,
        216,
        200,
        104,
        234,
        205,
        70,
        55,
        185,
        70,
        196,
        253,
        228,
        109,
        99,
        197,
        203,
        58,
        234,
        157,
        155,
        58,
        127,
        29,
        239,
        106,
        149,
        143,
        234,
        36,
        12,
        252
      ],
      "slot": 0,
      "active": true,
      "pending": false,
      "version": "1.1.1",
      "bootable": true,
      "confirmed": true,
      "permanent": false
    },
    {
      "hash": [
        143,
        216,
        200,
        104,
        234,
        205,
        70,
        55,
        185,
        70,
        196,
        253,
        228,
        109,
        99,
        197,
        203,
        58,
        234,
        157,
        155,
        58,
        127,
        29,
        239,
        106,
        149,
        143,
        234,
        36,
        12,
        252
      ],
      "slot": 1,
      "active": false,
      "pending": false,
      "version": "1.1.1",
      "bootable": true,
      "confirmed": false,
      "permanent": false
    }
  ],
  "splitStatus": 0
}

now when I upload the image

  mcumgr-client -m 256 -d /dev/ttyACM0 upload build-dongle-update/zephyr/app_update.bin
mcumgr-client 0.0.3, Copyright © 2023 Vouch.io LLC

13:54:05 [INFO] upload file: build-dongle-update/zephyr/app_update.bin
13:54:05 [INFO] flashing to slot 1
13:54:05 [INFO] 226567 bytes to transfer
  [00:00:12] [=================================================================================================================================] 221.26 KiB/221.26 KiB (0s)13:54:18 [INFO] upload took 13s

NOTE: (see I had to reduce the MTU to 256, default does not work I don't know why, any way that's another issue)

I can see it being uploaded correctly

mcumgr-client -d /dev/ttyACM0 list
mcumgr-client 0.0.3, Copyright © 2023 Vouch.io LLC

13:55:05 [INFO] send image list request
13:55:05 [INFO] response: {
  "images": [
    {
      "hash": [
        143,
        216,
        200,
        104,
        234,
        205,
        70,
        55,
        185,
        70,
        196,
        253,
        228,
        109,
        99,
        197,
        203,
        58,
        234,
        157,
        155,
        58,
        127,
        29,
        239,
        106,
        149,
        143,
        234,
        36,
        12,
        252
      ],
      "slot": 0,
      "active": true,
      "pending": false,
      "version": "1.1.1",
      "bootable": true,
      "confirmed": true,
      "permanent": false
    },
    {
      "hash": [
        255,
        148,
        49,
        169,
        189,
        101,
        39,
        214,
        71,
        242,
        38,
        40,
        206,
        34,
        22,
        7,
        108,
        39,
        191,
        13,
        228,
        192,
        129,
        55,
        25,
        71,
        61,
        45,
        111,
        40,
        111,
        188
      ],
      "slot": 1,
      "active": false,
      "pending": false,
      "version": "1.0.2",
      "bootable": true,
      "confirmed": false,
      "permanent": false
    }
  ],
  "splitStatus": 0
}

Even after resetting the device it does not move it to slot 0 and nor can I test or confirm the image.

Frank-Buss commented 9 months ago

Right, these commands are not implemented. We don't need them at the moment, I think because of the "CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y" setting. But feel free to submit a PR, and I'll integrated it, should be easy.

umair-uas commented 9 months ago

So how do you use the uploaded image in slot 1 then ? I do have CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y in my prj.conf but still when I upload it goes to slot 1,I have no idea how it will be used after the reset .

Frank-Buss commented 9 months ago

It is a bit tricky. We use mcuboot to update the image. So we figured that we don't need the usual swap process, because we can always update it again from mcuboot, if something went wrong. And with the setting "CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y", slot 1 is actually slot 0, see flash_map_extended.c:

#if defined(CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
int flash_area_id_from_direct_image(int image_id)
{
    switch (image_id) {
    case 0:
    case 1:
        return FIXED_PARTITION_ID(slot0_partition);
...

And we also have our custom sign script:

python3 `west topdir`/bootloader/mcuboot/scripts/imgtool.py sign --confirm --header-size 0x400 --align 32 --version 0.0.0+0 --slot-size 0xe0000 build/zephyr/zephyr.bin firmware-image-slot1.bin

This creates a pre-confirmed image. And the flash partition table is defined like this:

                        flash0: flash@8000000 {
                                compatible = "st,stm32-nv-flash", "soc-nv-flash";
                                write-block-size = < 0x20 >;
                                erase-block-size = < 0x20000 >;
                                max-erase-time = < 0xfa0 >;
                                reg = < 0x8000000 0x200000 >;
                                partitions {
                                        compatible = "fixed-partitions";
                                        #address-cells = < 0x1 >;
                                        #size-cells = < 0x1 >;
                                        boot_partition: partition@0 {
                                                reg = < 0x0 0x20000 >;
                                                read-only;
                                        };
                                        slot0_partition: partition@20000 {
                                                reg = < 0x20000 0xe0000 >;
                                                label = "image-0";
                                        };
                                        storage_partition: partition@100000 {
                                                reg = < 0x100000 0x120000 >;
                                        };
                                        slot1_partition: partition@120000 {
                                                reg = < 0x120000 0xe0000 >;
                                                label = "image-1";
                                        };
                                };
                        };

We have also a slot 2, to update an external flash with application data:

                        mt25ql512: qspi-nor-flash@0 {
                                compatible = "st,stm32-qspi-nor";
                                reg = < 0x0 >;
                                qspi-max-frequency = < 0x7ed6b40 >;
                                spi-bus-width = < 0x4 >;
                                size = < 0x20000000 >;
                                partitions {
                                        compatible = "fixed-partitions";
                                        #address-cells = < 0x1 >;
                                        #size-cells = < 0x1 >;
                                        slot2_partition: partition@0 {
                                                reg = < 0x0 0x4000000 >;
                                                label = "image-2";
                                        };
                                };
                        };

All this allows us to directly update slot 1 (which is in fact slot 0, as shown above, which is the slot used to boot the image for the first core), and also slot 2 for the external flash. I reserved slot 1 for later, if we want someday update it from the application instead of mcuboot, with the usual swap on reboot process, or if we want to use the second core of the STM32, which is currently disabled.

umair-uas commented 8 months ago

It is a bit tricky. We use mcuboot to update the image. So we figured that we don't need the usual swap process, because we can always update it again from mcuboot, if something went wrong. And with the setting "CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y", slot 1 is actually slot 0, see flash_map_extended.c:

#if defined(CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
int flash_area_id_from_direct_image(int image_id)
{
    switch (image_id) {
    case 0:
    case 1:
        return FIXED_PARTITION_ID(slot0_partition);
...

And we also have our custom sign script:

python3 `west topdir`/bootloader/mcuboot/scripts/imgtool.py sign --confirm --header-size 0x400 --align 32 --version 0.0.0+0 --slot-size 0xe0000 build/zephyr/zephyr.bin firmware-image-slot1.bin

This creates a pre-confirmed image. And the flash partition table is defined like this:

                        flash0: flash@8000000 {
                                compatible = "st,stm32-nv-flash", "soc-nv-flash";
                                write-block-size = < 0x20 >;
                                erase-block-size = < 0x20000 >;
                                max-erase-time = < 0xfa0 >;
                                reg = < 0x8000000 0x200000 >;
                                partitions {
                                        compatible = "fixed-partitions";
                                        #address-cells = < 0x1 >;
                                        #size-cells = < 0x1 >;
                                        boot_partition: partition@0 {
                                                reg = < 0x0 0x20000 >;
                                                read-only;
                                        };
                                        slot0_partition: partition@20000 {
                                                reg = < 0x20000 0xe0000 >;
                                                label = "image-0";
                                        };
                                        storage_partition: partition@100000 {
                                                reg = < 0x100000 0x120000 >;
                                        };
                                        slot1_partition: partition@120000 {
                                                reg = < 0x120000 0xe0000 >;
                                                label = "image-1";
                                        };
                                };
                        };

We have also a slot 2, to update an external flash with application data:

                        mt25ql512: qspi-nor-flash@0 {
                                compatible = "st,stm32-qspi-nor";
                                reg = < 0x0 >;
                                qspi-max-frequency = < 0x7ed6b40 >;
                                spi-bus-width = < 0x4 >;
                                size = < 0x20000000 >;
                                partitions {
                                        compatible = "fixed-partitions";
                                        #address-cells = < 0x1 >;
                                        #size-cells = < 0x1 >;
                                        slot2_partition: partition@0 {
                                                reg = < 0x0 0x4000000 >;
                                                label = "image-2";
                                        };
                                };
                        };

All this allows us to directly update slot 1 (which is in fact slot 0, as shown above, which is the slot used to boot the image for the first core), and also slot 2 for the external flash. I reserved slot 1 for later, if we want someday update it from the application instead of mcuboot, with the usual swap on reboot process, or if we want to use the second core of the STM32, which is currently disabled.

Thanks for the clarification. In our use case ,we have BLE Dongle , we use two virtual interfaces /dev/ttyACM0 and /dev/ttyACM1 on it. On one our application runs using HCI UART. On the second interface we upload the image with mcumgr.

mcumgr --conntype serial --connstring "/dev/ttyACM1,baud=115200,mtu=512" image list
Images:
 image=0 slot=0
    version: 2.2.3
    bootable: true
    flags: active confirmed
    hash: ead226ff89d69a0a9f441c227cd91f70bedaf947042a2d3fd2a5a0963ce2df3f
 image=0 slot=1
    version: 2.2.1
    bootable: true
    flags:
    hash: eeb089d0eee135e2663f8af9595b1456ee0bb4c8ee74bef8768f199c030aa06b
Split status: N/A (0)

❯ mcumgr --conntype serial --connstring "/dev/ttyACM1,baud=115200,mtu=512" image confirm ""
Images:
 image=0 slot=0
    version: 2.2.3
    bootable: true
    flags: active confirmed
    hash: ead226ff89d69a0a9f441c227cd91f70bedaf947042a2d3fd2a5a0963ce2df3f
 image=0 slot=1
    version: 2.2.1
    bootable: true
    flags:
    hash: eeb089d0eee135e2663f8af9595b1456ee0bb4c8ee74bef8768f199c030aa06b
Split status: N/A (0)

So when uploading the image , it goes here to slot=1, and then I have to do whole testing, confirming to make the image active in slot 0.

Frank-Buss commented 8 months ago

Ok, this sounds like what we do for another hardware, which we update OTA with Bluetooth while the application is running. We are using pre-confirmed images for this as well (see the custom Python sign step I wrote), which avoids the testing and confirming step on the device. Should be effectively the same as the "image confirm" step of the Go mcumgr program, if you don't need the confirm step done by the app on the device.

But could be that HCI UART is different. If you have a sample project of your configuration for the nRF5340-DK, then I can test it.

umair-uas commented 8 months ago

Ok, this sounds like what we do for another hardware, which we update OTA with Bluetooth while the application is running. We are using pre-confirmed images for this as well (see the custom Python sign step I wrote), which avoids the testing and confirming step on the device. Should be effectively the same as the "image confirm" step of the Go mcumgr program, if you don't need the confirm step done by the app on the device.

But could be that HCI UART is different. If you have a sample project of your configuration for the nRF5340-DK, then I can test it.

We use the sample project from Zephyr for HCI UART for nrf52840dongle, should work with nrf5340dk as well. [zephyr-sample-hci_uart](https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/bluetooth/hci_uart)

FARLY7 commented 5 months ago

Right, these commands are not implemented. We don't need them at the moment, I think because of the "CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y" setting. But feel free to submit a PR, and I'll integrated it, should be easy.

We use dual-bank updates over serial. A second serial port is offered for mcumgr, where we upload the image, mark it for testing, and also confirm it after running.

Unfortunately, we cannot use this tool because of the missing support for marking images for testing/confirmed. We will need to stick with the poor Go version.

This feature would be really nice if you can add it. If not, I can have a look when I get some time :)