The main design principle of the OTA mechanims is reliability: never end up with a bricked device, roll back on any failure. Therefore, an OTA process never updates firmware code or data in-place. Any failure (e.g. power loss) can end up in broken device. Thus, an OTA mechanism uses independent self-contained flash paritions to hold firmware images (code and data), and an intelligent boot loader makes a decision which partition to boot:
Here is a high level overview of the OTA procedure:
OTA.UpdateRPC command, or other. You can create your method using an OTA API.
conf9.jsonconfiguration files, or any other files. Remember: if a firmware image contains a file, it'll override an existing file during OTA. Never put files like
conf9.jsonin your firmware.
mgos_upd_commit()is called, which sets a "commit" flag in the boot config, marking this firmware "OK". A commit call could be done automatically after the health-checks, or manually by the user. If the commit is not made, a boot config still has "commit" flag not set.
The in-depth example of the OTA on CC3200 is given at embedded.com article - Updating firmware reliably
This is the simplest method, very useful for development. Of course it works
only if the device is directly visible. In order to enable HTTP POST OTA
handler, include ota-http-server
library in your
mos.yml. Then, you
can build a new firmware and push it using this command:
curl -v -F file=@build/fw.zip -F commit_timeout=60 http://IP_ADDR/update
If the boot config is stored in only one location, it makes it susceptible to failure during updates, which are usually performed as a read-erase-write operation: a reboot after erase and before write is complete could render device unbootable. The time between the two is short, but we set out to make our update process safe at all points, so we have to deal with it. The way we do it by using two config files with versioning, or sequencing. A sequencer is a monotonically decreasing number, so of the two files the one with smaller sequencer is more recent - on figure 2, config 1 is selected as active because it has smaller sequencer. When writing a new config file, we always use the currently inactive (older) slot and it will not become newer until it is written - erased config will be older than any valid one because erased NOR flash is filled with all 1s: