Page 1 of 1

Read binary from running partition

Posted: Tue Oct 10, 2023 7:50 am
by InterBilly
I am working on a hobby project where I need to copy the running application from one ESP to another (but not with WIFI or ethernet).
For guidance I looked at simple_ota_example from ESP-IDF and created a little test that should read the running binary per 8 bytes.
However, I have no idea how I should determine the amount of data to copy and how to check if the data is correct.
I tried to compare the data that is read with the binary by using the CMD command: "certutil -encodehex simple_ota.bin simple_ota.txt" but the data differs greatly.
On top of all that my C skills may be a little rusty, here is what I tried:

Code: Select all

    const char* typeNames[] = {"ESP_PARTITION_TYPE_APP", "ESP_PARTITION_TYPE_DATA", "ESP_PARTITION_TYPE_ANY"};
    const char* subtypeNames[] = {"ESP_PARTITION_SUBTYPE_APP_FACTORY", "ESP_PARTITION_SUBTYPE_APP_OTA_MIN"};


    const esp_partition_t *runnPar = esp_ota_get_running_partition();
    printf("Running partition:\n");
    printf("address: 0x%lX\n", runnPar->address);
    printf("size: %ld\n", runnPar->size); // size of partition, not binary
    printf("partition label: %s\n", runnPar->label);
    printf("type: %s\n", typeNames[runnPar->type]);
    printf("subtype: %s\n", subtypeNames[runnPar->subtype]);

    uint8_t byte_amt = 8;
    uint8_t *data = (uint8_t *)malloc(sizeof(uint8_t) * byte_amt);    
    for (size_t i = 0; i < runnPar->size; i+=8)
    {
        esp_err_t ret = esp_partition_read(runnPar, runnPar->address + i, data, 8);
        for (int j = 0; j < byte_amt; j++)
        {
            printf("%02X ", data[i+j]);
        }
        printf("\n");
        vTaskDelay(10);
    }
Any advice is greatly appreciated.

Re: Read binary from running partition

Posted: Tue Oct 10, 2023 11:44 am
by MicroController
The currently running application is already mmapped into the CPU's address space. That's why I would try to avoid reading the same physical address space via the partition API and instead read directly from the existing virtual address space.
I'm just not sure right now what virtual address range the application partition gets mapped to.

Re: Read binary from running partition

Posted: Wed Oct 11, 2023 3:48 am
by ESP_Sprite
MicroController wrote:
Tue Oct 10, 2023 11:44 am
The currently running application is already mmapped into the CPU's address space.
I don't think that is entirely true: the application consists of chunks that are loaded into RAM and chunks that are executed directly from flash. I think only the bit that executes directly from flash is mmap()ped in, not the other bits.

InterBilly: your issue is that partition->address is the offset in the flash chip, while esp_partition_read needs the offset in the partition. You should get the correct data with esp_partition_read(runnPar, i, data, 8);

The size of the binary is encoded in the application image; you can figure it out but beware it's not super-trivial. As usual, the esp-idf docs have the details. There is an API call that does this in an easier way, but for some reason there's not really any documentation for it, possibly this snippet helps.

Re: Read binary from running partition

Posted: Wed Oct 11, 2023 7:04 pm
by MicroController
ESP_Sprite wrote:
Wed Oct 11, 2023 3:48 am
I think only the bit that executes directly from flash is mmap()ped in, not the other bits.
Makes total sense. I forgot about IRAM :roll:

Re: Read binary from running partition

Posted: Thu Oct 12, 2023 1:46 am
by ESP_Sprite
MicroController wrote:
Wed Oct 11, 2023 7:04 pm
Makes total sense. I forgot about IRAM :roll:
Aside from that, there's not only code in an application. For instance, the .data section will be copied to DRAM and also not mmap'ped.

Re: Read binary from running partition

Posted: Thu Oct 12, 2023 9:34 am
by InterBilly
Thanks for the suggestions, now when I read the partition I can see the same data as in the .bin file so that looks good! :D

Next I tried to write this data on the OTA partition of another ESP, unfortunately I'm having difficulties again:
When I try to start a new OTA 'session' like this:

Code: Select all

const esp_partition_t *target = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
esp_ota_handle_t *ota_handle = NULL;
esp_err_t retv = esp_ota_begin(target, OTA_SIZE_UNKNOWN, update_handle);
esp_ota_begin() returns error code 258/0x102 : Invalid argument because the update handle is NULL. But as I understand the documentation esp_ota_begin() is supposed to initialize this handle: "out_handle – On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls.". I must be missing something here.

In the OTA example `simple_ota_example` this handle is part of the `esp_https_ota_handle` struct (which I am not using as I am not using http(s)) but I can't see anywhere where the needed handle is given a value before used in esp_ota_begin().

In the 'native_ota_example' the handle is given zero as value before handed to esp_ota_begin(), this does not make a difference for me.

Are there any examples of how to use OTA when supplying the new image yourself via your program and not https?

Re: Read binary from running partition

Posted: Thu Oct 12, 2023 9:47 am
by ghost07
First of all, pass the handle by reference:

Code: Select all

esp_ota_handle_t update_handle = NULL;
esp_err_t retv = esp_ota_begin(target, OTA_SIZE_UNKNOWN, &update_handle);
Notice the ampersand (&) in argument passing, and handle declaration as normal variable, not a pointer.

Second thing, check if result from esp_partition_find_first() is not NULL.

Re: Read binary from running partition

Posted: Thu Oct 12, 2023 7:37 pm
by InterBilly
Rookie mistake :( my C is rusty to say the least. It works perfectly now, thanks a lot!