Skip to content

Commit

Permalink
Commonise flash-based OTA. Add h7 support.
Browse files Browse the repository at this point in the history
  • Loading branch information
cpq committed Sep 24, 2023
1 parent 377d6ac commit c515e6d
Show file tree
Hide file tree
Showing 22 changed files with 2,060 additions and 1,164 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ INCS ?= -Isrc -I.
SSL ?=
CWD ?= $(realpath $(CURDIR))
ENV ?= -e Tmp=. -e WINEDEBUG=-all
DOCKER ?= docker run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
DOCKER_BIN ?= docker
DOCKER ?= $(DOCKER_BIN) run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS)
IPV6 ?= 1
ASAN ?= -fsanitize=address,undefined,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common
Expand Down Expand Up @@ -175,7 +176,7 @@ mongoose.c: Makefile $(wildcard src/*.c) $(wildcard src/drivers/*.c)
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@

mongoose.h: $(HDRS) Makefile
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/sys.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@


clean: clean_examples clean_embedded
Expand Down
18 changes: 7 additions & 11 deletions examples/device-dashboard/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,20 +238,16 @@ static void handle_firmware_rollback(struct mg_connection *c) {
}

static size_t print_status(void (*out)(char, void *), void *ptr, va_list *ap) {
struct mg_ota_data *os = va_arg(*ap, struct mg_ota_data *);
return mg_xprintf(
out, ptr, "{%m:%s,%m:%c%x%c,%m:%u,%m:%u,%m:%u,%m:%u,%m:%u}",
MG_ESC("valid"), os->magic == MG_OTA_MAGIC ? "true" : "false",
MG_ESC("magic"), '"', os->magic, '"', MG_ESC("crc32"), os->crc32,
MG_ESC("size"), os->size, MG_ESC("time"), os->time, MG_ESC("booted"),
os->booted, MG_ESC("golden"), os->golden);
int fw = va_arg(*ap, int);
return mg_xprintf(out, ptr, "{%m:%d,%m:%c%lx%c,%m:%u,%m:%u}",
MG_ESC("status"), mg_ota_status(fw), MG_ESC("crc32"), '"',
mg_ota_crc32(fw), '"', MG_ESC("size"), mg_ota_size(fw),
MG_ESC("timestamp"), mg_ota_timestamp(fw));
}

static void handle_firmware_status(struct mg_connection *c) {
struct mg_ota_data od[2];
mg_ota_status(od);
mg_http_reply(c, 200, s_json_header, "[%M,%M]\n", print_status, &od[0],
print_status, &od[1]);
mg_http_reply(c, 200, s_json_header, "[%M,%M]\n", print_status,
MG_FIRMWARE_CURRENT, print_status, MG_FIRMWARE_PREVIOUS);
}

static void handle_sys_reset(struct mg_connection *c) {
Expand Down
1,431 changes: 718 additions & 713 deletions examples/device-dashboard/packed_fs.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/device-dashboard/web_root/main.css

Large diffs are not rendered by default.

40 changes: 22 additions & 18 deletions examples/device-dashboard/web_root/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,18 @@ function Main({}) {
};

function FirmwareStatus({title, info, children}) {
const state = ['UNAVAILABLE', 'FIRST_BOOT', 'NOT_COMMITTED', 'COMMITTED'][(info.status || 0) % 4];
const valid = info.status > 0;
return html`
<div class="bg-white py-1 divide-y border rounded">
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
${title}
<//>
<div class="px-4 py-2 relative">
<div class="my-1">CRC32: ${info.valid ? info.crc32.toString(16) : 'n/a'}<//>
<div class="my-1">Size: ${info.valid ? info.size : 'n/a'}<//>
<div class="my-1">Flashed at: ${info.valid ? new Date(info.time * 1000).toLocaleString() : 'n/a'}<//>
<div class="my-1">State: ${info.valid ? (info.golden == 0 ? 'commtited' : 'NOT committed') : 'n/a'}<//>
<div class="my-1">Status: ${state}<//>
<div class="my-1">CRC32: ${valid ? info.crc32.toString(16) : 'n/a'}<//>
<div class="my-1">Size: ${valid ? info.size : 'n/a'}<//>
<div class="my-1">Flashed at: ${valid ? new Date(info.timestamp * 1000).toLocaleString() : 'n/a'}<//>
${children}
<//>
<//>`;
Expand All @@ -206,7 +208,6 @@ function FirmwareUpdate({}) {
const [info, setInfo] = useState([{}, {}]);
const refresh = () => fetch('api/firmware/status').then(r => r.json()).then(r => setInfo(r));
useEffect(refresh, []);
const state = ['new', 'dirty', 'clean'][(info.state || 0) % 3];
const oncommit = ev => fetch('api/firmware/commit')
.then(r => r.json())
.then(refresh);
Expand All @@ -223,12 +224,14 @@ function FirmwareUpdate({}) {
return html`
<div class="m-4 gap-4 grid grid-cols-1 lg:grid-cols-2">
<${FirmwareStatus} title="Current firmware image" info=${info[0]}>
<${Button} cls="mr-2" title="Commit this firmware"
onclick=${oncommit} icon=${Icons.thumbUp} disabled=${clean} />
<${Button} title="Reboot device" onclick=${onreboot} icon=${Icons.refresh} clsx="absolute top-4 right-4" />
<${UploadFileButton} class="mt-2"
title="Upload new firmware: choose .bin file:" onupload=${onupload}
url="api/firmware/upload" accept=".bin,.uf2" />
<div class="flex flex-wrap gap-2">
<${Button} title="Commit this firmware"
onclick=${oncommit} icon=${Icons.thumbUp} disabled=${clean} />
<${Button} title="Reboot device" onclick=${onreboot} icon=${Icons.refresh} clsx="absolute top-4 right-4" />
<${UploadFileButton}
title="Upload new firmware: choose .bin file:" onupload=${onupload}
url="api/firmware/upload" accept=".bin,.uf2" />
<//>
<//>
<${FirmwareStatus} title="Previous firmware image" info=${info[1]}>
<${Button} title="Rollback to this firmware" onclick=${onrollback}
Expand All @@ -238,10 +241,11 @@ function FirmwareUpdate({}) {
<div class="bg-white border shadow-lg">
<${DeveloperNote}>
<div class="my-2">
When new firmware gets flashed, its status is unreliable, "not
committed". In order to become "committed" (verified), a firmware must
be committed. If a firmware is not committed, then the next boot
reverts back to the previous firmware.
When a new firmware gets flashed, its status is marked as, "first_boot".
That is an unreliable (uncommitted) firmware. A user may choose
to revert back to the previous committed firmware on the subsequent
boots. Clicking on the "commit" button calls "mg_ota_commit()" function
which commits the firmware.
<//>
<div class="my-2">
This GUI loads a firmware file and sends it chunk by chunk to the
Expand All @@ -254,8 +258,8 @@ function FirmwareUpdate({}) {
<div class="bg-white border shadow-lg">
<${DeveloperNote}>
<div>
Firmware udpdate mechanism defines 3 API functions that the
target device must implement: ota_begin(), ota_write() and ota_end()
Firmware update mechanism defines 3 API functions that the target
device must implement: mg_ota_begin(), mg_ota_write() and mg_ota_end()
<//>
<div class="my-2">
RESTful API handlers use ota_xxx() API to save firmware to flash.
Expand All @@ -264,7 +268,7 @@ function FirmwareUpdate({}) {
<//>
<div class="my-2">
<a class="link text-blue-600 underline"
href="https://mongoose.ws/webinars/">Subscribe to our free webinar</a> to
href="https://mongoose.ws/webinars/">Join our free webinar</a> to
get detailed explanations about possible firmware updates strategies
and implementation demo
<//>
Expand Down
12 changes: 3 additions & 9 deletions examples/stm32/nucleo-h563zi-make-baremetal-builtin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h5/Include
CFLAGS += -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard
CFLAGS += -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard $(CFLAGS_EXTRA)
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map

SOURCES = main.c syscalls.c sysinit.c
SOURCES = main.c syscalls.c sysinit.c mongoose.c net.c packed_fs.c
SOURCES += cmsis_h5/Source/Templates/gcc/startup_stm32h563xx.s # ST startup file. Compiler-dependent!

# Mongoose-specific. See https://mongoose.ws/documentation/#build-options
SOURCES += mongoose.c net.c packed_fs.c
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1
CFLAGS += -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1
CFLAGS += -DMG_ENABLE_DRIVER_STM32H=1 -DMG_OTA=MG_OTA_STM32H5 $(CFLAGS_EXTRA)

# Example specific build options. See README.md
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"

Expand All @@ -32,7 +26,7 @@ firmware.elf: cmsis_core cmsis_h5 $(SOURCES) hal.h link.ld Makefile
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@

flash: firmware.bin
st-flash --debug --freq=200 --reset write $< 0x8000000
st-flash --reset write $< 0x8000000

cmsis_core: # ARM CMSIS core headers
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
Expand Down
19 changes: 19 additions & 0 deletions examples/stm32/nucleo-h563zi-make-baremetal-builtin/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ int main(void) {
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level

#if MG_OTA == MG_OTA_FLASH
// If we don't have any OTA info saved, e.g. we're pre-flashed, then
// call mg_ota_commit() to mark this firmware as reliable
if (mg_ota_status(MG_FIRMWARE_CURRENT) == MG_OTA_UNAVAILABLE) mg_ota_commit();

// Demonstrate the use of mg_flash_{load/save} functions for keeping device
// configuration data on flash. Increment boot count on every boot.
struct deviceconfig {
uint32_t boot_count;
int some_other_data;
};
uint32_t key = 0x12345678; // A unique key, one per data type
struct deviceconfig dc = {}; // Initialise to some default values
mg_flash_load(NULL, key, &dc, sizeof(dc)); // Load from flash
dc.boot_count++; // Increment boot count
mg_flash_save(NULL, key, &dc, sizeof(dc)); // And save back
MG_INFO(("Boot count: %u", dc.boot_count));
#endif

// Initialise Mongoose network stack
struct mg_tcpip_driver_stm32h_data driver_data = {.mdc_cr = 4};
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#define MG_ARCH MG_ARCH_NEWLIB
#define MG_OTA MG_OTA_FLASH

#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_CUSTOM_MILLIS 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_PACKED_FS 1
#define MG_ENABLE_DRIVER_STM32H 1
#define MG_ENABLE_STM32H5 1
#define MG_ENABLE_LINES 1
11 changes: 2 additions & 9 deletions examples/stm32/nucleo-h743zi-make-baremetal-builtin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map

SOURCES = main.c syscalls.c sysinit.c
SOURCES = main.c syscalls.c sysinit.c mongoose.c net.c packed_fs.c
SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h743xx.s # ST startup file. Compiler-dependent!

# Mongoose-specific. See https://mongoose.ws/documentation/#build-options
SOURCES += mongoose.c net.c packed_fs.c
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1
CFLAGS += -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1
CFLAGS += -DMG_ENABLE_DRIVER_STM32H=1 $(CFLAGS_EXTRA)

# Example specific build options. See README.md
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"

Expand Down Expand Up @@ -56,7 +50,6 @@ test update: CFLAGS += -DUART_DEBUG=USART1
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
# grep 'MQTT connected' /tmp/output.txt # Check for MQTT connection success

clean:
$(RM) firmware.* *.su cmsis_core cmsis_h7 mbedtls
4 changes: 4 additions & 0 deletions examples/stm32/nucleo-h743zi-make-baremetal-builtin/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ int main(void) {
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level

// If we don't have any OTA info saved, e.g. we're pre-flashed, then
// call mg_ota_commit() to mark this firmware as reliable
if (mg_ota_status(MG_FIRMWARE_CURRENT) == MG_OTA_UNAVAILABLE) mg_ota_commit();

// Initialise Mongoose network stack
struct mg_tcpip_driver_stm32h_data driver_data = {.mdc_cr = 4};
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#define MG_ARCH MG_ARCH_NEWLIB
#define MG_OTA MG_OTA_FLASH

#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_CUSTOM_MILLIS 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_PACKED_FS 1
#define MG_ENABLE_DRIVER_STM32H 1
#define MG_ENABLE_STM32H7 1
#define MG_ENABLE_LINES 1
Loading

0 comments on commit c515e6d

Please sign in to comment.