From 9ead50a96ad99b8e6e8c07799648bd55c9ae5ec5 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 16 Aug 2024 13:34:11 +0100 Subject: [PATCH 1/7] Initial commit of OTA update example --- pico_w/wifi/CMakeLists.txt | 2 + pico_w/wifi/ota_update/CMakeLists.txt | 46 +++ pico_w/wifi/ota_update/lwipopts.h | 10 + pico_w/wifi/ota_update/main.json | 61 +++ pico_w/wifi/ota_update/picow_ota_update.c | 375 ++++++++++++++++++ .../wifi/python_test_tcp/python_ota_update.py | 69 ++++ 6 files changed, 563 insertions(+) create mode 100644 pico_w/wifi/ota_update/CMakeLists.txt create mode 100644 pico_w/wifi/ota_update/lwipopts.h create mode 100644 pico_w/wifi/ota_update/main.json create mode 100644 pico_w/wifi/ota_update/picow_ota_update.c create mode 100644 pico_w/wifi/python_test_tcp/python_ota_update.py diff --git a/pico_w/wifi/CMakeLists.txt b/pico_w/wifi/CMakeLists.txt index 31797084b..e623c05a1 100644 --- a/pico_w/wifi/CMakeLists.txt +++ b/pico_w/wifi/CMakeLists.txt @@ -20,6 +20,8 @@ else() add_subdirectory_exclude_platforms(http_client) add_subdirectory_exclude_platforms(mqtt) + add_subdirectory_exclude_platforms(ota_update rp2040) + if (NOT PICO_MBEDTLS_PATH) message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined") else() diff --git a/pico_w/wifi/ota_update/CMakeLists.txt b/pico_w/wifi/ota_update/CMakeLists.txt new file mode 100644 index 000000000..ecb0aeaef --- /dev/null +++ b/pico_w/wifi/ota_update/CMakeLists.txt @@ -0,0 +1,46 @@ +add_executable(picow_ota_update_background + picow_ota_update.c + ) +target_compile_definitions(picow_ota_update_background PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" + PICO_CRT0_IMAGE_TYPE_TBYB=1 + ) +target_include_directories(picow_ota_update_background PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts + ) +target_link_libraries(picow_ota_update_background + pico_cyw43_arch_lwip_threadsafe_background + pico_stdlib + boot_uf2_headers + ) + +pico_sign_binary(picow_ota_update_background) +# pico_set_binary_type(picow_ota_update_background no_flash) +# pico_package_uf2_output(picow_ota_update_background 0x10000000) + +pico_add_extra_outputs(picow_ota_update_background) + +add_executable(picow_ota_update_poll + picow_ota_update.c + ) +target_compile_definitions(picow_ota_update_poll PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" + PICO_CRT0_IMAGE_TYPE_TBYB=1 + ) +target_include_directories(picow_ota_update_poll PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts + ) +target_link_libraries(picow_ota_update_poll + pico_cyw43_arch_lwip_poll + pico_stdlib + boot_uf2_headers + ) + +# pico_set_binary_type(picow_ota_update_background no_flash) +# pico_package_uf2_output(picow_ota_update_background 0x10000000) + +pico_add_extra_outputs(picow_ota_update_poll) diff --git a/pico_w/wifi/ota_update/lwipopts.h b/pico_w/wifi/ota_update/lwipopts.h new file mode 100644 index 000000000..8571ed509 --- /dev/null +++ b/pico_w/wifi/ota_update/lwipopts.h @@ -0,0 +1,10 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +// Generally you would define your own explicit list of lwIP options +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html) +// +// This example uses a common include to avoid repetition +#include "lwipopts_examples_common.h" + +#endif diff --git a/pico_w/wifi/ota_update/main.json b/pico_w/wifi/ota_update/main.json new file mode 100644 index 000000000..b52e5c2fe --- /dev/null +++ b/pico_w/wifi/ota_update/main.json @@ -0,0 +1,61 @@ +{ + "version": [1, 0], + "unpartitioned": { + "families": ["absolute"], + "permissions": { + "secure": "rw", + "nonsecure": "rw", + "bootloader": "rw" + } + }, + "partitions": [ + { + "name": "Main A", + "id": 0, + "size": "500K", + "families": ["rp2350-arm-s", "rp2350-riscv"], + "permissions": { + "secure": "rw", + "nonsecure": "rw", + "bootloader": "rw" + } + }, + { + "name": "Main B", + "id": 0, + "size": "500K", + "families": ["rp2350-arm-s", "rp2350-riscv"], + "permissions": { + "secure": "rw", + "nonsecure": "rw", + "bootloader": "rw" + }, + "link": ["a", 0] + }, + { + "name": "Firmware A", + "id": "0x123456789abcdef0", + "size": "240K", + "families": ["0x12345678"], + "permissions": { + "secure": "rw", + "nonsecure": "rw", + "bootloader": "rw" + }, + "ignored_during_riscv_boot": true + }, + { + "name": "Firmware B", + "id": 12345, + "size": "240K", + "families": ["0x12345678"], + "permissions": { + "secure": "rw", + "nonsecure": "rw", + "bootloader": "rw" + }, + "link": ["a", 2], + "ignored_during_riscv_boot": true + } + ] +} diff --git a/pico_w/wifi/ota_update/picow_ota_update.c b/pico_w/wifi/ota_update/picow_ota_update.c new file mode 100644 index 000000000..45d11a22f --- /dev/null +++ b/pico_w/wifi/ota_update/picow_ota_update.c @@ -0,0 +1,375 @@ +/** + * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include "pico/bootrom.h" +#include "boot/picobin.h" +#include "boot/picoboot.h" +#include "boot/uf2.h" + +#include "bootrom_structs.h" + +#include "lwip/pbuf.h" +#include "lwip/tcp.h" + +#define TCP_PORT 4242 +// #define DEBUG_printf(...) printf(__VA_ARGS__) +#define DEBUG_printf(...) +#define BUF_SIZE 512 +#define POLL_TIME_S 5 + +#define FLASH_SECTOR_ERASE_SIZE 4096u + +typedef struct TCP_SERVER_T_ { + struct tcp_pcb *server_pcb; + struct tcp_pcb *client_pcb; + bool complete; + uint8_t buffer_sent[BUF_SIZE]; + uint8_t buffer_recv[BUF_SIZE]; + int sent_len; + int recv_len; + int num_blocks; + int blocks_done; + uint32_t family_id; + uint32_t flash_update; + int32_t write_offset; + uint32_t write_size; + uint32_t highest_erased_sector; +} TCP_SERVER_T; + +typedef struct uf2_block uf2_block_t; + +static TCP_SERVER_T* tcp_server_init(void) { + TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T)); + if (!state) { + DEBUG_printf("failed to allocate state\n"); + return NULL; + } + return state; +} + + +static __attribute__((aligned(4))) uint8_t workarea[4 * 1024]; + +static inline void __enable_irq(void) +{ + pico_default_asm_volatile("cpsie i" : : : "memory"); +} + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +static inline void __disable_irq(void) +{ + pico_default_asm_volatile("cpsid i" : : : "memory"); +} + +static err_t tcp_server_close(void *arg) { + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + err_t err = ERR_OK; + if (state->client_pcb != NULL) { + tcp_arg(state->client_pcb, NULL); + tcp_poll(state->client_pcb, NULL, 0); + tcp_sent(state->client_pcb, NULL); + tcp_recv(state->client_pcb, NULL); + tcp_err(state->client_pcb, NULL); + err = tcp_close(state->client_pcb); + if (err != ERR_OK) { + DEBUG_printf("close failed %d, calling abort\n", err); + tcp_abort(state->client_pcb); + err = ERR_ABRT; + } + state->client_pcb = NULL; + } + if (state->server_pcb) { + tcp_arg(state->server_pcb, NULL); + tcp_close(state->server_pcb); + state->server_pcb = NULL; + } + return err; +} + +static err_t tcp_server_result(void *arg, int status) { + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + if (status == 0) { + DEBUG_printf("test success\n"); + } else { + DEBUG_printf("test failed %d\n", status); + } + state->complete = true; + return tcp_server_close(arg); +} + +static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + DEBUG_printf("tcp_server_sent %u\n", len); + state->sent_len += len; + + if (state->sent_len >= BUF_SIZE) { + + // We should get the data back from the client + state->recv_len = 0; + DEBUG_printf("Waiting for buffer from client\n"); + } + + return ERR_OK; +} + +err_t tcp_server_send_data(void *arg, struct tcp_pcb *tpcb) +{ + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + + state->sent_len = 0; + DEBUG_printf("Writing %ld bytes to client\n", BUF_SIZE); + // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you + // can use this method to cause an assertion in debug mode, if this method is called when + // cyw43_arch_lwip_begin IS needed + cyw43_arch_lwip_check(); + err_t err = tcp_write(tpcb, state->buffer_recv, BUF_SIZE, TCP_WRITE_FLAG_COPY); + if (err != ERR_OK) { + DEBUG_printf("Failed to write data %d\n", err); + return tcp_server_result(arg, -1); + } + return ERR_OK; +} + +err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + if (!p) { + return tcp_server_result(arg, -1); + } + // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you + // can use this method to cause an assertion in debug mode, if this method is called when + // cyw43_arch_lwip_begin IS needed + cyw43_arch_lwip_check(); + if (p->tot_len > 0) { + DEBUG_printf("tcp_server_recv %d/%d err %d\n", p->tot_len, state->recv_len, err); + + // Receive the buffer + const uint16_t buffer_left = BUF_SIZE - state->recv_len; + state->recv_len += pbuf_copy_partial(p, state->buffer_recv + state->recv_len, + p->tot_len > buffer_left ? buffer_left : p->tot_len, 0); + tcp_recved(tpcb, p->tot_len); + } + pbuf_free(p); + + // Have we have received the whole buffer + if (state->recv_len == BUF_SIZE) { + + // check it matches + uf2_block_t* block; + block = (uf2_block_t*)state->buffer_recv; + + if (state->num_blocks == 0) { + state->num_blocks = block->num_blocks; + state->family_id = block->file_size; // or familyID; + + resident_partition_t uf2_target_partition; + rom_flash_flush_cache(); + rom_get_uf2_target_partition(workarea, sizeof(workarea), state->family_id, &uf2_target_partition); + printf("Code Target partition is %lx %lx\n", uf2_target_partition.permissions_and_location, uf2_target_partition.permissions_and_flags); + + uint16_t first_sector_number = (uf2_target_partition.permissions_and_location & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB; + uint16_t last_sector_number = (uf2_target_partition.permissions_and_location & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB; + uint32_t code_start_addr = first_sector_number * 0x1000; + uint32_t code_end_addr = (last_sector_number + 1) * 0x1000; + uint32_t code_size = code_end_addr - code_start_addr; + printf("Start %lx, End %lx, Size %lx\n", code_start_addr, code_end_addr, code_size); + + state->flash_update = code_start_addr + XIP_BASE; + state->write_offset = code_start_addr + XIP_BASE - block->target_addr; + state->write_size = code_size; + DEBUG_printf("Write Offset %lx, Size %lx\n", state->write_offset, state->write_size); + } + + if (state->blocks_done != block->block_no) { + DEBUG_printf("block number mismatch\n"); + return tcp_server_result(arg, -1); + } + DEBUG_printf("tcp_server_recv buffer ok\n"); + + // Write to flash + struct cflash_flags flags; + int8_t ret; + if (block->target_addr / FLASH_SECTOR_ERASE_SIZE > state->highest_erased_sector) { + flags.flags = + (CFLASH_OP_VALUE_ERASE << CFLASH_OP_LSB) | + (CFLASH_SECLEVEL_VALUE_SECURE << CFLASH_SECLEVEL_LSB) | + (CFLASH_ASPACE_VALUE_STORAGE << CFLASH_ASPACE_LSB); + __disable_irq(); + ret = rom_flash_op(flags, + block->target_addr + state->write_offset, + FLASH_SECTOR_ERASE_SIZE, NULL); + __enable_irq(); + state->highest_erased_sector = block->target_addr / FLASH_SECTOR_ERASE_SIZE; + DEBUG_printf("Checked Erase Returned %d, start %x, size %x, highest erased %x\n", ret, block->target_addr + state->write_offset, FLASH_SECTOR_ERASE_SIZE, state->highest_erased_sector); + } + flags.flags = + (CFLASH_OP_VALUE_PROGRAM << CFLASH_OP_LSB) | + (CFLASH_SECLEVEL_VALUE_SECURE << CFLASH_SECLEVEL_LSB) | + (CFLASH_ASPACE_VALUE_STORAGE << CFLASH_ASPACE_LSB); + __disable_irq(); + ret = rom_flash_op(flags, + block->target_addr + state->write_offset, + 256, (void*)block->data); + __enable_irq(); + DEBUG_printf("Checked Program Returned %d, start %x, size %x\n", ret, block->target_addr + state->write_offset, 256); + + // Download complete? + state->blocks_done++; + if (state->blocks_done >= state->num_blocks) { + tcp_server_result(arg, 0); + return ERR_OK; + } + + // Send another buffer + return tcp_server_send_data(arg, state->client_pcb); + } + return ERR_OK; +} + +static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) { + DEBUG_printf("tcp_server_poll_fn\n"); + return tcp_server_result(arg, -1); // no response is an error? +} + +static void tcp_server_err(void *arg, err_t err) { + if (err != ERR_ABRT) { + DEBUG_printf("tcp_client_err_fn %d\n", err); + tcp_server_result(arg, err); + } +} + +static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) { + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + if (err != ERR_OK || client_pcb == NULL) { + DEBUG_printf("Failure in accept\n"); + tcp_server_result(arg, err); + return ERR_VAL; + } + DEBUG_printf("Client connected\n"); + + state->client_pcb = client_pcb; + tcp_arg(client_pcb, state); + tcp_sent(client_pcb, tcp_server_sent); + tcp_recv(client_pcb, tcp_server_recv); + tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2); + tcp_err(client_pcb, tcp_server_err); + + return ERR_OK; +} + +static bool tcp_server_open(void *arg) { + TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT); + + struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); + if (!pcb) { + DEBUG_printf("failed to create pcb\n"); + return false; + } + + err_t err = tcp_bind(pcb, NULL, TCP_PORT); + if (err) { + DEBUG_printf("failed to bind to port %u\n", TCP_PORT); + return false; + } + + state->server_pcb = tcp_listen_with_backlog(pcb, 1); + if (!state->server_pcb) { + DEBUG_printf("failed to listen\n"); + if (pcb) { + tcp_close(pcb); + } + return false; + } + + tcp_arg(state->server_pcb, state); + tcp_accept(state->server_pcb, tcp_server_accept); + + return true; +} + +int main() { + stdio_init_all(); + + if (cyw43_arch_init()) { + printf("failed to initialise\n"); + return 1; + } + + cyw43_arch_enable_sta_mode(); + + printf("Connecting to Wi-Fi...\n"); + if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { + printf("failed to connect.\n"); + return 1; + } else { + printf("Connected.\n"); + } + + boot_info_t boot_info = {}; + int ret = rom_get_boot_info(&boot_info); + printf("Boot partition was %d\n", boot_info.partition); + + if (rom_get_last_boot_type() == BOOT_TYPE_FLASH_UPDATE) { + printf("Someone updated into me\n"); + printf("Params were %x %x\n", boot_info.reboot_params[0], boot_info.reboot_params[1]); + printf("Update info %x\n", boot_info.tbyb_and_update_info); + printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); + printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); + printf("Workarea at %x\n", workarea); + __disable_irq(); + ret = rom_explicit_buy(workarea, sizeof(workarea)); + __enable_irq(); + printf("Buy returned %d\n", ret); + ret = rom_get_boot_info(&boot_info); + printf("Update info now %x\n", boot_info.tbyb_and_update_info); + printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); + printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); + } + + + TCP_SERVER_T *state = tcp_server_init(); + if (!state) { + return -1; + } + if (!tcp_server_open(state)) { + tcp_server_result(state, -1); + return -1; + } + while(!state->complete) { + // the following #ifdef is only here so this same example can be used in multiple modes; + // you do not need it in your code +#if PICO_CYW43_ARCH_POLL + // if you are using pico_cyw43_arch_poll, then you must poll periodically from your + // main loop (not from a timer) to check for Wi-Fi driver or lwIP work that needs to be done. + cyw43_arch_poll(); + // you can poll as often as you like, however if you have nothing else to do you can + // choose to sleep until either a specified time, or cyw43_arch_poll() has work to do: + cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); +#else + // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work + // is done via interrupt in the background. This sleep is just an example of some (blocking) + // work you might be doing. + sleep_ms(1000); +#endif + } + + cyw43_arch_deinit(); + int ret = rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_FLASH_UPDATE, 1000, state->flash_update, 0); + printf("Done - rebooting for a flash update boot %d\n", ret); + free(state); + sleep_ms(2000); + return 0; +} diff --git a/pico_w/wifi/python_test_tcp/python_ota_update.py b/pico_w/wifi/python_test_tcp/python_ota_update.py new file mode 100644 index 000000000..61d4d408c --- /dev/null +++ b/pico_w/wifi/python_test_tcp/python_ota_update.py @@ -0,0 +1,69 @@ +#!/usr/bin/python + +import socket +import sys + +# Check server ip address set +if len(sys.argv) < 2: + raise RuntimeError('pass IP address of the server') + +# Check file is set +if len(sys.argv) < 3: + raise RuntimeError('pass UF2 file for update') + +# Set the server address here like 1.2.3.4 +SERVER_ADDR = sys.argv[1] + +# These constants should match the server +BUF_SIZE = 512 +SERVER_PORT = 4242 + +# Open socket to the server +sock = socket.socket() +addr = (SERVER_ADDR, SERVER_PORT) +sock.connect(addr) + +file = sys.argv[2] + +with open(file, 'rb') as f: + data = f.read() + +data = bytearray(data) + +data = data[BUF_SIZE:] + +print("Len data", len(data), "/512", len(data) / BUF_SIZE) + +# Repeat test for a number of iterations +for i in range(len(data) // BUF_SIZE): + print("I", i, "of", len(data) // BUF_SIZE)#, ' '*10, end='\r') + uf2_buf = data[i*BUF_SIZE:(i+1)*BUF_SIZE] + + # Send the data back to the server + write_len = sock.send(uf2_buf) + if write_len != BUF_SIZE: + raise RuntimeError('wrong amount of data written') + + if i < (len(data) // BUF_SIZE) - 1: + # Read BUF_SIZE bytes from the server + total_size = BUF_SIZE + read_buf = b'' + while total_size > 0: + buf = sock.recv(BUF_SIZE) + # print('read %d bytes from server' % len(buf)) + total_size -= len(buf) + read_buf += buf + + # Check size of data received + if len(read_buf) != BUF_SIZE: + raise RuntimeError('wrong amount of data read %d', len(read_buf)) + + # Check same data received + if read_buf != uf2_buf: + for i in range(512): + print(f"Sent {uf2_buf[i]:02x} Recv {read_buf[i]:02x}") + raise RuntimeError('buffer mismatch') + +# All done +sock.close() +print("upload completed") From 8c13360c16b799ba5cdc3136a8b33ce034515629 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 16 Aug 2024 16:26:01 +0100 Subject: [PATCH 2/7] Speedup and add hashing --- pico_w/wifi/ota_update/CMakeLists.txt | 13 +- pico_w/wifi/ota_update/picow_ota_update.c | 252 +++++++++--------- .../wifi/python_test_tcp/python_ota_update.py | 34 ++- 3 files changed, 156 insertions(+), 143 deletions(-) diff --git a/pico_w/wifi/ota_update/CMakeLists.txt b/pico_w/wifi/ota_update/CMakeLists.txt index ecb0aeaef..7e70ee918 100644 --- a/pico_w/wifi/ota_update/CMakeLists.txt +++ b/pico_w/wifi/ota_update/CMakeLists.txt @@ -13,10 +13,15 @@ target_include_directories(picow_ota_update_background PRIVATE target_link_libraries(picow_ota_update_background pico_cyw43_arch_lwip_threadsafe_background pico_stdlib + pico_sha256 boot_uf2_headers ) -pico_sign_binary(picow_ota_update_background) +pico_hash_binary(picow_ota_update_background) +get_target_property(hasSigfile picow_ota_update_background PICOTOOL_SIGFILE) +if (hasSigfile) + pico_sign_binary(picow_ota_update_background) +endif() # pico_set_binary_type(picow_ota_update_background no_flash) # pico_package_uf2_output(picow_ota_update_background 0x10000000) @@ -37,9 +42,15 @@ target_include_directories(picow_ota_update_poll PRIVATE target_link_libraries(picow_ota_update_poll pico_cyw43_arch_lwip_poll pico_stdlib + pico_sha256 boot_uf2_headers ) +pico_hash_binary(picow_ota_update_poll) +get_target_property(hasSigfile picow_ota_update_poll PICOTOOL_SIGFILE) +if (hasSigfile) + pico_sign_binary(picow_ota_update_poll) +endif() # pico_set_binary_type(picow_ota_update_background no_flash) # pico_package_uf2_output(picow_ota_update_background 0x10000000) diff --git a/pico_w/wifi/ota_update/picow_ota_update.c b/pico_w/wifi/ota_update/picow_ota_update.c index 45d11a22f..9a6d40ec3 100644 --- a/pico_w/wifi/ota_update/picow_ota_update.c +++ b/pico_w/wifi/ota_update/picow_ota_update.c @@ -9,6 +9,7 @@ #include "pico/stdlib.h" #include "pico/cyw43_arch.h" +#include "pico/sha256.h" #include "pico/bootrom.h" #include "boot/picobin.h" #include "boot/picoboot.h" @@ -22,16 +23,16 @@ #define TCP_PORT 4242 // #define DEBUG_printf(...) printf(__VA_ARGS__) #define DEBUG_printf(...) -#define BUF_SIZE 512 +#define BUF_SIZE 2048 #define POLL_TIME_S 5 #define FLASH_SECTOR_ERASE_SIZE 4096u -typedef struct TCP_SERVER_T_ { +typedef struct TCP_UPDATE_SERVER_T_ { struct tcp_pcb *server_pcb; struct tcp_pcb *client_pcb; bool complete; - uint8_t buffer_sent[BUF_SIZE]; + uint8_t buffer_sent[SHA256_RESULT_BYTES]; uint8_t buffer_recv[BUF_SIZE]; int sent_len; int recv_len; @@ -42,12 +43,12 @@ typedef struct TCP_SERVER_T_ { int32_t write_offset; uint32_t write_size; uint32_t highest_erased_sector; -} TCP_SERVER_T; +} TCP_UPDATE_SERVER_T; typedef struct uf2_block uf2_block_t; -static TCP_SERVER_T* tcp_server_init(void) { - TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T)); +static TCP_UPDATE_SERVER_T* tcp_update_server_init(void) { + TCP_UPDATE_SERVER_T *state = calloc(1, sizeof(TCP_UPDATE_SERVER_T)); if (!state) { DEBUG_printf("failed to allocate state\n"); return NULL; @@ -58,24 +59,8 @@ static TCP_SERVER_T* tcp_server_init(void) { static __attribute__((aligned(4))) uint8_t workarea[4 * 1024]; -static inline void __enable_irq(void) -{ - pico_default_asm_volatile("cpsie i" : : : "memory"); -} - - -/** - \brief Disable IRQ Interrupts - \details Disables IRQ interrupts by setting special-purpose register PRIMASK. - Can only be executed in Privileged modes. - */ -static inline void __disable_irq(void) -{ - pico_default_asm_volatile("cpsid i" : : : "memory"); -} - -static err_t tcp_server_close(void *arg) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; +static err_t tcp_update_server_close(void *arg) { + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; err_t err = ERR_OK; if (state->client_pcb != NULL) { tcp_arg(state->client_pcb, NULL); @@ -99,23 +84,23 @@ static err_t tcp_server_close(void *arg) { return err; } -static err_t tcp_server_result(void *arg, int status) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; +static err_t tcp_update_server_result(void *arg, int status) { + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; if (status == 0) { DEBUG_printf("test success\n"); } else { DEBUG_printf("test failed %d\n", status); } state->complete = true; - return tcp_server_close(arg); + return tcp_update_server_close(arg); } -static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; - DEBUG_printf("tcp_server_sent %u\n", len); +static err_t tcp_update_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; + DEBUG_printf("tcp_update_server_sent %u\n", len); state->sent_len += len; - if (state->sent_len >= BUF_SIZE) { + if (state->sent_len >= SHA256_RESULT_BYTES) { // We should get the data back from the client state->recv_len = 0; @@ -125,35 +110,35 @@ static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { return ERR_OK; } -err_t tcp_server_send_data(void *arg, struct tcp_pcb *tpcb) +err_t tcp_update_server_send_data(void *arg, struct tcp_pcb *tpcb) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; state->sent_len = 0; - DEBUG_printf("Writing %ld bytes to client\n", BUF_SIZE); + DEBUG_printf("Writing %ld bytes to client\n", SHA256_RESULT_BYTES); // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you // can use this method to cause an assertion in debug mode, if this method is called when // cyw43_arch_lwip_begin IS needed cyw43_arch_lwip_check(); - err_t err = tcp_write(tpcb, state->buffer_recv, BUF_SIZE, TCP_WRITE_FLAG_COPY); + err_t err = tcp_write(tpcb, state->buffer_sent, SHA256_RESULT_BYTES, TCP_WRITE_FLAG_COPY); if (err != ERR_OK) { DEBUG_printf("Failed to write data %d\n", err); - return tcp_server_result(arg, -1); + return tcp_update_server_result(arg, -1); } return ERR_OK; } -err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; +err_t tcp_update_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; if (!p) { - return tcp_server_result(arg, -1); + return tcp_update_server_result(arg, -1); } // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you // can use this method to cause an assertion in debug mode, if this method is called when // cyw43_arch_lwip_begin IS needed cyw43_arch_lwip_check(); if (p->tot_len > 0) { - DEBUG_printf("tcp_server_recv %d/%d err %d\n", p->tot_len, state->recv_len, err); + DEBUG_printf("tcp_update_server_recv %d/%d err %d\n", p->tot_len, state->recv_len, err); // Receive the buffer const uint16_t buffer_left = BUF_SIZE - state->recv_len; @@ -166,111 +151,124 @@ err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err // Have we have received the whole buffer if (state->recv_len == BUF_SIZE) { - // check it matches - uf2_block_t* block; - block = (uf2_block_t*)state->buffer_recv; - - if (state->num_blocks == 0) { - state->num_blocks = block->num_blocks; - state->family_id = block->file_size; // or familyID; - - resident_partition_t uf2_target_partition; - rom_flash_flush_cache(); - rom_get_uf2_target_partition(workarea, sizeof(workarea), state->family_id, &uf2_target_partition); - printf("Code Target partition is %lx %lx\n", uf2_target_partition.permissions_and_location, uf2_target_partition.permissions_and_flags); - - uint16_t first_sector_number = (uf2_target_partition.permissions_and_location & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB; - uint16_t last_sector_number = (uf2_target_partition.permissions_and_location & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB; - uint32_t code_start_addr = first_sector_number * 0x1000; - uint32_t code_end_addr = (last_sector_number + 1) * 0x1000; - uint32_t code_size = code_end_addr - code_start_addr; - printf("Start %lx, End %lx, Size %lx\n", code_start_addr, code_end_addr, code_size); - - state->flash_update = code_start_addr + XIP_BASE; - state->write_offset = code_start_addr + XIP_BASE - block->target_addr; - state->write_size = code_size; - DEBUG_printf("Write Offset %lx, Size %lx\n", state->write_offset, state->write_size); - } - - if (state->blocks_done != block->block_no) { - DEBUG_printf("block number mismatch\n"); - return tcp_server_result(arg, -1); - } - DEBUG_printf("tcp_server_recv buffer ok\n"); - - // Write to flash - struct cflash_flags flags; - int8_t ret; - if (block->target_addr / FLASH_SECTOR_ERASE_SIZE > state->highest_erased_sector) { + for (int i=0; i < BUF_SIZE/sizeof(uf2_block_t); i++) { + // check it matches + uf2_block_t* block; + block = (uf2_block_t*)(state->buffer_recv + i * sizeof(uf2_block_t)); + + if (state->num_blocks == 0) { + state->num_blocks = block->num_blocks; + state->family_id = block->file_size; // or familyID; + + resident_partition_t uf2_target_partition; + rom_flash_flush_cache(); + rom_get_uf2_target_partition(workarea, sizeof(workarea), state->family_id, &uf2_target_partition); + printf("Code Target partition is %lx %lx\n", uf2_target_partition.permissions_and_location, uf2_target_partition.permissions_and_flags); + + uint16_t first_sector_number = (uf2_target_partition.permissions_and_location & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB; + uint16_t last_sector_number = (uf2_target_partition.permissions_and_location & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB; + uint32_t code_start_addr = first_sector_number * 0x1000; + uint32_t code_end_addr = (last_sector_number + 1) * 0x1000; + uint32_t code_size = code_end_addr - code_start_addr; + printf("Start %lx, End %lx, Size %lx\n", code_start_addr, code_end_addr, code_size); + + state->flash_update = code_start_addr + XIP_BASE; + state->write_offset = code_start_addr + XIP_BASE - block->target_addr; + state->write_size = code_size; + DEBUG_printf("Write Offset %lx, Size %lx\n", state->write_offset, state->write_size); + } + + if (state->blocks_done != block->block_no) { + DEBUG_printf("block number mismatch - expected %d, got %d\n", state->blocks_done, block->block_no); + return tcp_update_server_result(arg, -1); + } + if (state->family_id != block->file_size) { + DEBUG_printf("family id mismatch\n"); + return tcp_update_server_result(arg, -1); + } + DEBUG_printf("tcp_update_server_recv buffer ok\n"); + + // Write to flash + struct cflash_flags flags; + int8_t ret; + if (block->target_addr / FLASH_SECTOR_ERASE_SIZE > state->highest_erased_sector) { + flags.flags = + (CFLASH_OP_VALUE_ERASE << CFLASH_OP_LSB) | + (CFLASH_SECLEVEL_VALUE_SECURE << CFLASH_SECLEVEL_LSB) | + (CFLASH_ASPACE_VALUE_STORAGE << CFLASH_ASPACE_LSB); + ret = rom_flash_op(flags, + block->target_addr + state->write_offset, + FLASH_SECTOR_ERASE_SIZE, NULL); + state->highest_erased_sector = block->target_addr / FLASH_SECTOR_ERASE_SIZE; + DEBUG_printf("Checked Erase Returned %d, start %x, size %x, highest erased %x\n", ret, block->target_addr + state->write_offset, FLASH_SECTOR_ERASE_SIZE, state->highest_erased_sector); + } flags.flags = - (CFLASH_OP_VALUE_ERASE << CFLASH_OP_LSB) | + (CFLASH_OP_VALUE_PROGRAM << CFLASH_OP_LSB) | (CFLASH_SECLEVEL_VALUE_SECURE << CFLASH_SECLEVEL_LSB) | (CFLASH_ASPACE_VALUE_STORAGE << CFLASH_ASPACE_LSB); - __disable_irq(); ret = rom_flash_op(flags, block->target_addr + state->write_offset, - FLASH_SECTOR_ERASE_SIZE, NULL); - __enable_irq(); - state->highest_erased_sector = block->target_addr / FLASH_SECTOR_ERASE_SIZE; - DEBUG_printf("Checked Erase Returned %d, start %x, size %x, highest erased %x\n", ret, block->target_addr + state->write_offset, FLASH_SECTOR_ERASE_SIZE, state->highest_erased_sector); - } - flags.flags = - (CFLASH_OP_VALUE_PROGRAM << CFLASH_OP_LSB) | - (CFLASH_SECLEVEL_VALUE_SECURE << CFLASH_SECLEVEL_LSB) | - (CFLASH_ASPACE_VALUE_STORAGE << CFLASH_ASPACE_LSB); - __disable_irq(); - ret = rom_flash_op(flags, - block->target_addr + state->write_offset, - 256, (void*)block->data); - __enable_irq(); - DEBUG_printf("Checked Program Returned %d, start %x, size %x\n", ret, block->target_addr + state->write_offset, 256); - - // Download complete? - state->blocks_done++; - if (state->blocks_done >= state->num_blocks) { - tcp_server_result(arg, 0); - return ERR_OK; + 256, (void*)block->data); + DEBUG_printf("Checked Program Returned %d, start %x, size %x\n", ret, block->target_addr + state->write_offset, 256); + + // Download complete? + state->blocks_done++; + if (state->blocks_done >= state->num_blocks) { + tcp_update_server_result(arg, 0); + return ERR_OK; + } } + // Hash the received data + pico_sha256_state_t sha_state; + int rc = pico_sha256_start_blocking(&sha_state, SHA256_BIG_ENDIAN, true); // using some DMA system resources + hard_assert(rc == PICO_OK); + pico_sha256_update_blocking(&sha_state, (const uint8_t*)state->buffer_recv, sizeof(state->buffer_recv)); + + // Get the result of the sha256 calculation + sha256_result_t* result; + result = (sha256_result_t*)state->buffer_sent; + pico_sha256_finish(&sha_state, result); + // Send another buffer - return tcp_server_send_data(arg, state->client_pcb); + return tcp_update_server_send_data(arg, state->client_pcb); } return ERR_OK; } -static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) { - DEBUG_printf("tcp_server_poll_fn\n"); - return tcp_server_result(arg, -1); // no response is an error? +static err_t tcp_update_server_poll(void *arg, struct tcp_pcb *tpcb) { + DEBUG_printf("tcp_update_server_poll_fn\n"); + return tcp_update_server_result(arg, -1); // no response is an error? } -static void tcp_server_err(void *arg, err_t err) { +static void tcp_update_server_err(void *arg, err_t err) { if (err != ERR_ABRT) { DEBUG_printf("tcp_client_err_fn %d\n", err); - tcp_server_result(arg, err); + tcp_update_server_result(arg, err); } } -static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; +static err_t tcp_update_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) { + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; if (err != ERR_OK || client_pcb == NULL) { DEBUG_printf("Failure in accept\n"); - tcp_server_result(arg, err); + tcp_update_server_result(arg, err); return ERR_VAL; } DEBUG_printf("Client connected\n"); state->client_pcb = client_pcb; tcp_arg(client_pcb, state); - tcp_sent(client_pcb, tcp_server_sent); - tcp_recv(client_pcb, tcp_server_recv); - tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2); - tcp_err(client_pcb, tcp_server_err); + tcp_sent(client_pcb, tcp_update_server_sent); + tcp_recv(client_pcb, tcp_update_server_recv); + tcp_poll(client_pcb, tcp_update_server_poll, POLL_TIME_S * 2); + tcp_err(client_pcb, tcp_update_server_err); return ERR_OK; } -static bool tcp_server_open(void *arg) { - TCP_SERVER_T *state = (TCP_SERVER_T*)arg; +static bool tcp_update_server_open(void *arg) { + TCP_UPDATE_SERVER_T *state = (TCP_UPDATE_SERVER_T*)arg; printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT); struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); @@ -295,7 +293,7 @@ static bool tcp_server_open(void *arg) { } tcp_arg(state->server_pcb, state); - tcp_accept(state->server_pcb, tcp_server_accept); + tcp_accept(state->server_pcb, tcp_update_server_accept); return true; } @@ -329,9 +327,7 @@ int main() { printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); printf("Workarea at %x\n", workarea); - __disable_irq(); ret = rom_explicit_buy(workarea, sizeof(workarea)); - __enable_irq(); printf("Buy returned %d\n", ret); ret = rom_get_boot_info(&boot_info); printf("Update info now %x\n", boot_info.tbyb_and_update_info); @@ -340,12 +336,12 @@ int main() { } - TCP_SERVER_T *state = tcp_server_init(); + TCP_UPDATE_SERVER_T *state = tcp_update_server_init(); if (!state) { return -1; } - if (!tcp_server_open(state)) { - tcp_server_result(state, -1); + if (!tcp_update_server_open(state)) { + tcp_update_server_result(state, -1); return -1; } while(!state->complete) { @@ -355,19 +351,17 @@ int main() { // if you are using pico_cyw43_arch_poll, then you must poll periodically from your // main loop (not from a timer) to check for Wi-Fi driver or lwIP work that needs to be done. cyw43_arch_poll(); - // you can poll as often as you like, however if you have nothing else to do you can - // choose to sleep until either a specified time, or cyw43_arch_poll() has work to do: - cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); -#else - // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work - // is done via interrupt in the background. This sleep is just an example of some (blocking) - // work you might be doing. - sleep_ms(1000); #endif + + // Do your application code here + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + sleep_ms(250); + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + sleep_ms(250); } cyw43_arch_deinit(); - int ret = rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_FLASH_UPDATE, 1000, state->flash_update, 0); + ret = rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_FLASH_UPDATE, 1000, state->flash_update, 0); printf("Done - rebooting for a flash update boot %d\n", ret); free(state); sleep_ms(2000); diff --git a/pico_w/wifi/python_test_tcp/python_ota_update.py b/pico_w/wifi/python_test_tcp/python_ota_update.py index 61d4d408c..b49453e85 100644 --- a/pico_w/wifi/python_test_tcp/python_ota_update.py +++ b/pico_w/wifi/python_test_tcp/python_ota_update.py @@ -2,6 +2,7 @@ import socket import sys +import hashlib # Check server ip address set if len(sys.argv) < 2: @@ -15,7 +16,8 @@ SERVER_ADDR = sys.argv[1] # These constants should match the server -BUF_SIZE = 512 +BUF_SIZE = 2048 +UF2_BLOCK = 512 SERVER_PORT = 4242 # Open socket to the server @@ -30,13 +32,19 @@ data = bytearray(data) -data = data[BUF_SIZE:] +# Skip abs block +data = data[UF2_BLOCK:] -print("Len data", len(data), "/512", len(data) / BUF_SIZE) +print("Len data", len(data), f"/{BUF_SIZE}", len(data) / BUF_SIZE) + +while (len(data) % BUF_SIZE != 0): + data.extend([0] * UF2_BLOCK) + +print("Len data now", len(data), f"/{BUF_SIZE}", len(data) / BUF_SIZE) # Repeat test for a number of iterations for i in range(len(data) // BUF_SIZE): - print("I", i, "of", len(data) // BUF_SIZE)#, ' '*10, end='\r') + print("I", i, "of", len(data) // BUF_SIZE, ' '*10, end='\r') uf2_buf = data[i*BUF_SIZE:(i+1)*BUF_SIZE] # Send the data back to the server @@ -45,25 +53,25 @@ raise RuntimeError('wrong amount of data written') if i < (len(data) // BUF_SIZE) - 1: - # Read BUF_SIZE bytes from the server - total_size = BUF_SIZE + # Read 32 bytes from the server + total_size = 32 read_buf = b'' while total_size > 0: - buf = sock.recv(BUF_SIZE) + buf = sock.recv(32) # print('read %d bytes from server' % len(buf)) total_size -= len(buf) read_buf += buf # Check size of data received - if len(read_buf) != BUF_SIZE: + if len(read_buf) != 32: raise RuntimeError('wrong amount of data read %d', len(read_buf)) - # Check same data received - if read_buf != uf2_buf: - for i in range(512): - print(f"Sent {uf2_buf[i]:02x} Recv {read_buf[i]:02x}") + # Check the hash matches + h = hashlib.new('sha256') + h.update(uf2_buf) + if read_buf != h.digest(): raise RuntimeError('buffer mismatch') # All done sock.close() -print("upload completed") +print("\nupload completed") From a17808d08c8abb8e3e698c1a4eaaf15bc04f152e Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 16 Aug 2024 18:13:44 +0100 Subject: [PATCH 3/7] Tidy up --- pico_w/wifi/ota_update/picow_ota_update.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pico_w/wifi/ota_update/picow_ota_update.c b/pico_w/wifi/ota_update/picow_ota_update.c index 9a6d40ec3..373486754 100644 --- a/pico_w/wifi/ota_update/picow_ota_update.c +++ b/pico_w/wifi/ota_update/picow_ota_update.c @@ -15,8 +15,6 @@ #include "boot/picoboot.h" #include "boot/uf2.h" -#include "bootrom_structs.h" - #include "lwip/pbuf.h" #include "lwip/tcp.h" @@ -322,17 +320,14 @@ int main() { if (rom_get_last_boot_type() == BOOT_TYPE_FLASH_UPDATE) { printf("Someone updated into me\n"); - printf("Params were %x %x\n", boot_info.reboot_params[0], boot_info.reboot_params[1]); - printf("Update info %x\n", boot_info.tbyb_and_update_info); - printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); - printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); - printf("Workarea at %x\n", workarea); + if (boot_info.reboot_params[0]) printf("Flash update base was %x\n", boot_info.reboot_params[0]); + if (boot_info.tbyb_and_update_info) printf("Update info %x\n", boot_info.tbyb_and_update_info); + if (always->zero_init.tbyb_flag_flash_addr) printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); + if (always->zero_init.version_downgrade_erase_flash_addr) printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); ret = rom_explicit_buy(workarea, sizeof(workarea)); - printf("Buy returned %d\n", ret); + if (ret) printf("Buy returned %d\n", ret); ret = rom_get_boot_info(&boot_info); - printf("Update info now %x\n", boot_info.tbyb_and_update_info); - printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); - printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); + if (boot_info.tbyb_and_update_info) printf("Update info now %x\n", boot_info.tbyb_and_update_info); } From e4911e9986625eeceb40ce421da955712ff8a9fe Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 20 Aug 2024 14:01:42 +0100 Subject: [PATCH 4/7] Tidy up and use pico_use_partition_firmware function --- CMakeLists.txt | 3 +++ pico_w/wifi/ota_update/CMakeLists.txt | 14 ++++++-------- pico_w/wifi/ota_update/main.json | 4 ++-- {bootloaders/encrypted => sample_keys}/private.pem | 0 4 files changed, 11 insertions(+), 10 deletions(-) rename {bootloaders/encrypted => sample_keys}/private.pem (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c78ad9449..fb40e924e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,9 @@ function(add_subdirectory_exclude_platforms NAME) add_subdirectory(${NAME}) endfunction() +# Set signing file for entire project +set_property(GLOBAL PROPERTY PICOTOOL_SIGFILE "${CMAKE_CURRENT_LIST_DIR}/sample_keys/private.pem") + # Add blink example add_subdirectory_exclude_platforms(blink) add_subdirectory_exclude_platforms(blink_simple) diff --git a/pico_w/wifi/ota_update/CMakeLists.txt b/pico_w/wifi/ota_update/CMakeLists.txt index 7e70ee918..13e80a5b3 100644 --- a/pico_w/wifi/ota_update/CMakeLists.txt +++ b/pico_w/wifi/ota_update/CMakeLists.txt @@ -17,11 +17,10 @@ target_link_libraries(picow_ota_update_background boot_uf2_headers ) +pico_use_partition_firmware(picow_ota_update_background) + pico_hash_binary(picow_ota_update_background) -get_target_property(hasSigfile picow_ota_update_background PICOTOOL_SIGFILE) -if (hasSigfile) - pico_sign_binary(picow_ota_update_background) -endif() +pico_sign_binary(picow_ota_update_background) # pico_set_binary_type(picow_ota_update_background no_flash) # pico_package_uf2_output(picow_ota_update_background 0x10000000) @@ -46,11 +45,10 @@ target_link_libraries(picow_ota_update_poll boot_uf2_headers ) +pico_use_partition_firmware(picow_ota_update_poll) + pico_hash_binary(picow_ota_update_poll) -get_target_property(hasSigfile picow_ota_update_poll PICOTOOL_SIGFILE) -if (hasSigfile) - pico_sign_binary(picow_ota_update_poll) -endif() +pico_sign_binary(picow_ota_update_poll) # pico_set_binary_type(picow_ota_update_background no_flash) # pico_package_uf2_output(picow_ota_update_background 0x10000000) diff --git a/pico_w/wifi/ota_update/main.json b/pico_w/wifi/ota_update/main.json index b52e5c2fe..9a25cc7b1 100644 --- a/pico_w/wifi/ota_update/main.json +++ b/pico_w/wifi/ota_update/main.json @@ -12,7 +12,7 @@ { "name": "Main A", "id": 0, - "size": "500K", + "size": "1748K", "families": ["rp2350-arm-s", "rp2350-riscv"], "permissions": { "secure": "rw", @@ -23,7 +23,7 @@ { "name": "Main B", "id": 0, - "size": "500K", + "size": "1748K", "families": ["rp2350-arm-s", "rp2350-riscv"], "permissions": { "secure": "rw", diff --git a/bootloaders/encrypted/private.pem b/sample_keys/private.pem similarity index 100% rename from bootloaders/encrypted/private.pem rename to sample_keys/private.pem From 24a1c684ab80654b90982cf70bdec814078150c2 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 20 Aug 2024 18:27:24 +0100 Subject: [PATCH 5/7] Little extra fixes --- bootloaders/encrypted/CMakeLists.txt | 4 ++-- pico_w/wifi/CMakeLists.txt | 5 ++--- pico_w/wifi/ota_update/main.json | 11 +++++++---- pico_w/wifi/ota_update/picow_ota_update.c | 1 + 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/bootloaders/encrypted/CMakeLists.txt b/bootloaders/encrypted/CMakeLists.txt index f29f0efe2..6b3fe74a0 100644 --- a/bootloaders/encrypted/CMakeLists.txt +++ b/bootloaders/encrypted/CMakeLists.txt @@ -53,7 +53,7 @@ add_linker_script(enc_bootloader "0x20070000" "64k") pico_set_otp_key_output_file(enc_bootloader ${CMAKE_CURRENT_BINARY_DIR}/otp.json) # sign, hash, and clear SRAM -pico_sign_binary(enc_bootloader ${CMAKE_CURRENT_LIST_DIR}/private.pem) +pico_sign_binary(enc_bootloader) pico_hash_binary(enc_bootloader) pico_load_map_clear_sram(enc_bootloader) @@ -87,7 +87,7 @@ pico_set_binary_type(hello_serial_enc no_flash) add_linker_script(hello_serial_enc "0x20000000" "448k") # sign, hash, and encrypt -pico_sign_binary(hello_serial_enc ${CMAKE_CURRENT_LIST_DIR}/private.pem) +pico_sign_binary(hello_serial_enc) pico_hash_binary(hello_serial_enc) pico_encrypt_binary(hello_serial_enc ${CMAKE_CURRENT_LIST_DIR}/privateaes.bin) diff --git a/pico_w/wifi/CMakeLists.txt b/pico_w/wifi/CMakeLists.txt index e623c05a1..badc762f0 100644 --- a/pico_w/wifi/CMakeLists.txt +++ b/pico_w/wifi/CMakeLists.txt @@ -20,11 +20,10 @@ else() add_subdirectory_exclude_platforms(http_client) add_subdirectory_exclude_platforms(mqtt) - add_subdirectory_exclude_platforms(ota_update rp2040) - if (NOT PICO_MBEDTLS_PATH) - message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined") + message("Skipping some examples as PICO_MBEDTLS_PATH is not defined") else() add_subdirectory_exclude_platforms(tls_client) + add_subdirectory_exclude_platforms(ota_update rp2040) endif() endif() diff --git a/pico_w/wifi/ota_update/main.json b/pico_w/wifi/ota_update/main.json index 9a25cc7b1..5ecc5fe4d 100644 --- a/pico_w/wifi/ota_update/main.json +++ b/pico_w/wifi/ota_update/main.json @@ -12,7 +12,7 @@ { "name": "Main A", "id": 0, - "size": "1748K", + "size": "1744K", "families": ["rp2350-arm-s", "rp2350-riscv"], "permissions": { "secure": "rw", @@ -23,7 +23,7 @@ { "name": "Main B", "id": 0, - "size": "1748K", + "size": "1744K", "families": ["rp2350-arm-s", "rp2350-riscv"], "permissions": { "secure": "rw", @@ -35,6 +35,7 @@ { "name": "Firmware A", "id": "0x123456789abcdef0", + "start": "3500k", "size": "240K", "families": ["0x12345678"], "permissions": { @@ -42,7 +43,8 @@ "nonsecure": "rw", "bootloader": "rw" }, - "ignored_during_riscv_boot": true + "ignored_during_riscv_boot": true, + "no_reboot_on_uf2_download": true }, { "name": "Firmware B", @@ -55,7 +57,8 @@ "bootloader": "rw" }, "link": ["a", 2], - "ignored_during_riscv_boot": true + "ignored_during_riscv_boot": true, + "no_reboot_on_uf2_download": true } ] } diff --git a/pico_w/wifi/ota_update/picow_ota_update.c b/pico_w/wifi/ota_update/picow_ota_update.c index 373486754..ab8c518bf 100644 --- a/pico_w/wifi/ota_update/picow_ota_update.c +++ b/pico_w/wifi/ota_update/picow_ota_update.c @@ -189,6 +189,7 @@ err_t tcp_update_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, er // Write to flash struct cflash_flags flags; int8_t ret; + (void)ret; if (block->target_addr / FLASH_SECTOR_ERASE_SIZE > state->highest_erased_sector) { flags.flags = (CFLASH_OP_VALUE_ERASE << CFLASH_OP_LSB) | From 6e8e154382c98eaba9033c27ecebae68e1ba781e Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 3 Oct 2024 14:19:37 +0100 Subject: [PATCH 6/7] Remove bootrom structs dependency --- pico_w/wifi/ota_update/picow_ota_update.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pico_w/wifi/ota_update/picow_ota_update.c b/pico_w/wifi/ota_update/picow_ota_update.c index ab8c518bf..8904417ab 100644 --- a/pico_w/wifi/ota_update/picow_ota_update.c +++ b/pico_w/wifi/ota_update/picow_ota_update.c @@ -323,8 +323,6 @@ int main() { printf("Someone updated into me\n"); if (boot_info.reboot_params[0]) printf("Flash update base was %x\n", boot_info.reboot_params[0]); if (boot_info.tbyb_and_update_info) printf("Update info %x\n", boot_info.tbyb_and_update_info); - if (always->zero_init.tbyb_flag_flash_addr) printf("TBYB flash address is %x\n", always->zero_init.tbyb_flag_flash_addr); - if (always->zero_init.version_downgrade_erase_flash_addr) printf("TBYB erase address is %x\n", always->zero_init.version_downgrade_erase_flash_addr); ret = rom_explicit_buy(workarea, sizeof(workarea)); if (ret) printf("Buy returned %d\n", ret); ret = rom_get_boot_info(&boot_info); From 885b05854a27c95a67dac10dc1a4a486bfb1381b Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 7 Apr 2025 18:08:48 +0100 Subject: [PATCH 7/7] Update to work with latest SDK version --- pico_w/wifi/ota_update/CMakeLists.txt | 4 ++-- pico_w/wifi/ota_update/main.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pico_w/wifi/ota_update/CMakeLists.txt b/pico_w/wifi/ota_update/CMakeLists.txt index 13e80a5b3..accba9236 100644 --- a/pico_w/wifi/ota_update/CMakeLists.txt +++ b/pico_w/wifi/ota_update/CMakeLists.txt @@ -17,7 +17,7 @@ target_link_libraries(picow_ota_update_background boot_uf2_headers ) -pico_use_partition_firmware(picow_ota_update_background) +pico_use_wifi_firmware_partition(picow_ota_update_background) pico_hash_binary(picow_ota_update_background) pico_sign_binary(picow_ota_update_background) @@ -45,7 +45,7 @@ target_link_libraries(picow_ota_update_poll boot_uf2_headers ) -pico_use_partition_firmware(picow_ota_update_poll) +pico_use_wifi_firmware_partition(picow_ota_update_poll) pico_hash_binary(picow_ota_update_poll) pico_sign_binary(picow_ota_update_poll) diff --git a/pico_w/wifi/ota_update/main.json b/pico_w/wifi/ota_update/main.json index 5ecc5fe4d..c9e989bd6 100644 --- a/pico_w/wifi/ota_update/main.json +++ b/pico_w/wifi/ota_update/main.json @@ -34,10 +34,10 @@ }, { "name": "Firmware A", - "id": "0x123456789abcdef0", + "id": "0x776966696669726d", "start": "3500k", "size": "240K", - "families": ["0x12345678"], + "families": ["data"], "permissions": { "secure": "rw", "nonsecure": "rw", @@ -50,7 +50,7 @@ "name": "Firmware B", "id": 12345, "size": "240K", - "families": ["0x12345678"], + "families": ["data"], "permissions": { "secure": "rw", "nonsecure": "rw",