Page 2 of 4

Re: OTA clarification

Posted: Fri Feb 24, 2017 12:30 am
by imtiaz
Hi Angus,

Even if the ota image is not present at all and you set the OTA data to say boot from that OTA image - the bootloader will attempt to boot from it and then fail verify and then do nothing. As long as the partition table has the OTA partitions that is...

Code: Select all

 if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
        return 0;
    }
So I've added a bit of code in the bootloader so that if the return is 0 - it will then attempt to load factory image

Code: Select all

if(unpack_load_app(&load_part_pos) == 0)
    {
    		ESP_LOGE(TAG, "Trying to boot to factory");
    		load_part_pos = bs.factory;
    		if(unpack_load_app(&load_part_pos) == 0)
    		{
    			ESP_LOGE(TAG, "CATOSTROPHIC FAILURE - Factory image failed verify"); //cant do anything if factory image has failed
    		}
    }
and Ive also added a failsafe option so if a button is held down for 10 seconds on bootup the bootloader will load the factory image.

So in the meantime how can I keep my bootloader changes since it is part of the IDF ? I really dont want to have my own repository for this.

Thanks
Imtiaz

Re: OTA clarification

Posted: Fri Feb 24, 2017 2:02 am
by ESP_Angus
imtiaz wrote:Hi Angus,

Even if the ota image is not present at all and you set the OTA data to say boot from that OTA image - the bootloader will attempt to boot from it and then fail verify and then do nothing. As long as the partition table has the OTA partitions that is...
Right, that's not good and we will fix it. What I meant to point out is that (at least with recent IDF) esp_ota_set_boot_partition() should fail to set that OTA partition as the boot partition, if the image doesn't verify.
imtiaz wrote: So in the meantime how can I keep my bootloader changes since it is part of the IDF ? I really dont want to have my own repository for this.
You can override components on a per-project basis. In your project directory, make a PROJECT_DIR/components/bootloader directory and copy the contents of IDF_PATH/components/bootloader to here. This bootloader component will be used in preference to the IDF one.

When updating IDF, you'll need to manually keep an eye out for other updates to the bootloader source and roll these into your copy of the component.

Re: OTA clarification

Posted: Fri Feb 24, 2017 2:27 am
by imtiaz
You can override components on a per-project basis. In your project directory, make a PROJECT_DIR/components/bootloader directory and copy the contents of IDF_PATH/components/bootloader to here. This bootloader component will be used in preference to the IDF one.
Thats a brilliant feature - well done

Re: OTA clarification

Posted: Fri Aug 18, 2017 8:13 am
by hybryd
Hi Imtiaz,
Can you share your button override code that you added to the custom bootloader?

and Ive also added a failsafe option so if a button is held down for 10 seconds on bootup the bootloader will load the factory image.

Re: OTA clarification

Posted: Mon Oct 16, 2017 8:37 pm
by imtiaz
Hi hybrid,

sorry I have been away from the forums - do you still need this?

Re: OTA clarification

Posted: Sun Oct 22, 2017 11:07 pm
by cmorgan
imtiaz wrote:Hi hybrid,

sorry I have been away from the forums - do you still need this?
I could use it here, I'm in a similar spot and would like to re-use the 'boot' mode switch to initiate a factory image boot.

Re: OTA clarification

Posted: Sun Nov 05, 2017 6:41 pm
by imtiaz
1 - copy the entire bootloader component from the idf into your application
2 - add the following functon somewhere and repurpose for your button input pin and timeout requirements

Code: Select all

/**
 *  @function :     ForceFactoryBoot
 *  @description:   Add by Imtiaz @ Syrp for failsafe mode
 *
 *  @inputs:        void
 */
static uint8_t ForceFactoryBoot(void)
{
    #define GPIO_INPUT_FORCE_FACTORY     4
    uint8_t timer = 0;
      gpio_pad_select_gpio(GPIO_INPUT_FORCE_FACTORY);
     ets_delay_us(10000); //delay 10 msecs
    while(GPIO_INPUT_GET(GPIO_INPUT_FORCE_FACTORY))
    {
    	ESP_LOGE(TAG, "OTA Pin is Active : %d!",timer);
    	ets_delay_us(1000000);
    	timer++;
    	if(timer == 10)
    	{
    		ESP_LOGE(TAG, "Forcing Factory : %d!",GPIO_INPUT_GET(GPIO_INPUT_FORCE_FACTORY));
    		return 1;
    	}
    }
    return 0;
}
3 - add this line of code to line # 332 in the file

Code: Select all

if (bs->ota_info.offset != 0 && !ForceFactoryBoot())
should do it

Re: OTA clarification

Posted: Mon Nov 20, 2017 7:49 pm
by cmorgan
Thanks for the pointers and the example code!

Re: OTA clarification

Posted: Tue Nov 21, 2017 3:56 am
by chegewara
Its nice solution and i would use it, but what if i dont want to alter bootloader? Ive been thinking today a while. First solution i have found and make it working was to install OTA app on factory partition, add snippet to main app which will erase otadata partition with

Code: Select all

spi_flash_erase_range()
if during reset i press button on pin i chose. Its some workaround and it works nicely, especially with boot wifi app.
But then i figured out better way. There is nowhere said that we HAVE to have factory partition. We can just have 2 ota partitions and one of them use like factory and the other like ota partition. This way we can have first partition small and for main app bigger. Now we dont have to use any workaround because we have api to switch between ota partitions.
Just thought i will share this story and this may help someone.

Re: OTA clarification

Posted: Mon Mar 19, 2018 12:07 pm
by davdav
Hi,

I re-open this thread to have confirmation we can have only FACTORY and 1 OTA partition.

Our project is getting bigger (>1MB) and we need at least 1MB for FAT filesystem so we would like to have just 1 OTA partion and switch between factory and that OTA partition (both of them of 1.5MB).


Do you think the pseudo-code below is it ok?

Code: Select all

const esp_partition_t *factory //Here need to define all information for factory partition (type,subtype,address)

//Check current partition
const esp_partition_t *running = esp_ota_get_running_partition();

if (running->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0)
{
	//If partition is ota_0, then set next update to factory partition
	update_partition = esp_ota_get_next_update_partition(factory);
}

Thanks