rBoot tutorial for ESP8266 – OTA updates

Ok, hope you’re still with me after my previous massive post. Now I’m going to show you how to perform an over-the-air (OTA) update with rBoot. I’ve covered all the background already, so this should be pretty straight forward as long as you have a simple two rom rBoot setup running.

Now add rboot.h, rboot-ota.h and rboot-ota.c to your project and call the rboot_ota_start function. How you invoke the OTA update code is up to you, the sample project on GitHub (now updated) has a simple command line interface over the UART allowing the user to enter the command “ota”.

rboot_ota_start takes an rboot_ota struct with the options for the update.

typedef struct {
	uint8 ip[4];
	uint16 port;
	uint8 *request;
	uint8 rom_slot;
	ota_callback callback;
} rboot_ota;
  • ip is the ip address of the web server to download the new rom from.
  • port is the web server port (usually 80).
  • request is a complete http request which will be sent to the web server, this may seem like a slightly odd way to do it, but it gives you full control over what is sent and it’s the same way the SDK OTA update works.
  • rom_slot is the number of the rom slot on the flash to update, starting at zero. In our two rom example that will be either 0 or 1 (and the opposite to the one we are currently running).
  • callback is a user function that will be called when the update is completed (either success or failure), it is passed a pointer to the rboot_ota structure and a bool to indicate success or failure. This is where you will then switch to the new rom (using rboot_set_current_rom) and restart the device.

Example

static void ICACHE_FLASH_ATTR OtaUpdate_CallBack(void *arg, bool result) {

	char msg[40];
	rboot_ota *upServer = (rboot_ota*)arg;

	if(result == true) {
		// success, reboot
		os_sprintf(msg, "Firmware updated, rebooting to rom %d...\r\n", upServer->rom_slot);
		uart0_send(msg);
		rboot_set_current_rom(upServer->rom_slot);
		system_restart();
	} else {
		// fail, cleanup
		uart0_send("Firmware update failed!\r\n");
		os_free(upServer->request);
		os_free(upServer);
	}
}

static const uint8 ota_ip[] = {192,168,7,5};
#define HTTP_HEADER "Connection: keep-alive\r\nCache-Control: no-cache\r\nUser-Agent: rBoot-Sample/1.0\r\nAccept: */*\r\n\r\n"

static void ICACHE_FLASH_ATTR OtaUpdate() {

	uint8 slot;
	rboot_ota *ota;

	// create the update structure
	ota = (rboot_ota*)os_zalloc(sizeof(rboot_ota));
	os_memcpy(ota->ip, ota_ip, 4);
	ota->port = 80;
	ota->callback = (ota_callback)OtaUpdate_CallBack;
	ota->request = (uint8 *)os_zalloc(512);

	// select rom slot to flash
	slot = rboot_get_current_rom();
	if (slot == 0) slot = 1; else slot = 0;
	ota->rom_slot = slot;

	// actual http request
	os_sprintf((char*)ota->request,
		"GET /%s HTTP/1.1\r\nHost: "IPSTR"\r\n" HTTP_HEADER,
		(slot == 0 ? "rom0.bin" : "rom1.bin"),
		IP2STR(ota->ip));

	// start the upgrade process
	if (rboot_ota_start(ota)) {
		uart0_send("Updating...\r\n");
	} else {
		uart0_send("Updating failed!\r\n\r\n");
		os_free(ota->request);
		os_free(ota);
	}

}

It’s really that simple, that’s all you need to add to your application to be able to perform OTA updates. You might want to put in a version check, so it only updates if there is a new version, but that’s up to you.

Web Server

All that remains is to drop rom0.bin and rom1.bin in the root of your web server. Obviously you can change where it looks for the files with a small tweak to the code above.

5 comments

  1. Hi Richard, I have an issue with OTA during the writing to the flash. I am using Peter Scargill’s code which includes your rboot and with a brand new device it works for the first time I do an OTA and it reboots into ROM1. I’ve done this with the 4 new devices I just received. If I do a subsequent update I get an error such as E:M 5856 and it indicates that the ROM is bad and reboots on the current one. It always seems to be at the same memory location too. I enabled the debug to show the writes.

    write addr: 0x002359c0, len: 0x05b4
    E:M 5856
    write addr: 0x00235f74, len: 0x05b4

    Monitoring the USB current and it doesn’t use more than 115 mA so at first I thought this was a power issue.

    1. I’m getting the same thing. Just occasionally the ESP is giving upgrade_recvcb 5840 bytes of data to deal with. See here for why: http://bbs.espressif.com/viewtopic.php?f=7&t=1664&sid=5323983d0e4409895ddcf5f4688a02e9&start=10

      The E:M statement is a failure to alloc memory. rboot_write_flash doesn’t handle this properly – it just exits when this happens, and while it returns false this isn’t dealt with anywhere. Which means nothing gets written this time around and 5840 bytes of your ROM is missed out. That explains why your ROM is bad!

      I’ve fixed this by limiting the alloc to 1460 (plus any bytes required for alignment) – so basically just dealing with the data in rboot_write_flash in 1460 byte chunks. That seems to work.

      I’m not sure if the system is just fundamentally limited to a maximum value in pvPortMalloc – or just unable to allocate such a large contiguous chunk.

  2. I have been trying to update over the air using your instructions above. Besides showing ‘running rom0’ on serial monitor, when I type ota, nothing happens. I am a newbie to esp8266 and programming in general. If you can give some detailed guide as to how to update ota, it would help.
    Not only this, I added the files to my own blink program but didn’t work there as well. I am sure I am missing something crucial. Please help.

Leave a comment