Skip to content

Commit 2a5429a

Browse files
bdracoprokomakuba2k2
authored
[realtek-ambz2] Add OTA implementation for RTL8720CF (#344)
* [realtek-ambz2] Implement OTA * Fix uf2 filename * Fix encode_for_define for Windows compatibility * Format lt_ota.c with clang-format * Update cores/realtek-ambz2/base/api/lt_ota.c --------- Co-authored-by: Martin Prokopič <[email protected]> Co-authored-by: Kuba Szczodrzyński <[email protected]>
1 parent 29303f7 commit 2a5429a

File tree

3 files changed

+138
-8
lines changed

3 files changed

+138
-8
lines changed

builder/family/realtek-ambz2.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from os.path import isfile, join
44
from shutil import copyfile
55

6+
from ltchiptool.soc.ambz2.util.models.config import ImageConfig
67
from platformio.platform.base import PlatformBase
78
from platformio.platform.board import PlatformBoardConfig
89
from SCons.Script import DefaultEnvironment, Environment
@@ -15,6 +16,22 @@
1516

1617
COMPONENT_DIR = join("$SDK_DIR", "component")
1718

19+
20+
# Get image decryption public key
21+
def get_public_key(private: bytes) -> bytes:
22+
from ltchiptool.util.curve25519 import X25519PrivateKey
23+
24+
key = X25519PrivateKey.from_private_bytes(private)
25+
return key.public_key()
26+
27+
28+
def encode_for_define(data: bytes) -> str:
29+
# use C array initializer syntax to avoid shell escaping issues on Windows
30+
return "{" + ",".join(f"0x{byte:02x}" for byte in data) + "}"
31+
32+
33+
public_key_bytes = get_public_key(ImageConfig(**board.get("image")).keys.decryption)
34+
1835
# Flags
1936
queue.AppendPublic(
2037
CCFLAGS=[
@@ -39,6 +56,7 @@
3956
("__ARM_ARCH_8M_MAIN__", "1"),
4057
("CONFIG_BUILD_RAM", "1"),
4158
"V8M_STKOVF",
59+
("IMAGE_PUBLIC_KEY", encode_for_define(public_key_bytes)),
4260
],
4361
CPPPATH=[
4462
# allow including <ctype.h> from GCC instead of RTL SDK
@@ -424,12 +442,14 @@
424442
LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""',
425443
# UF2OTA input list
426444
UF2OTA=[
427-
# same OTA images for flasher and device
428-
f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2;flasher:ota1,ota2",
445+
# use unmodified image for flasher
446+
f"{image_firmware_is},{image_firmware_is}=flasher:ota1,ota2",
447+
# use same image for device OTA
448+
f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2",
429449
# having flashed an application image, update the bootloader and partition table (incl. keys)
430450
f"{image_bootloader},{image_bootloader}=flasher:boot,boot",
431451
f"{image_part_table},{image_part_table}=flasher:part_table,part_table",
432452
# clearing headers of the "other" OTA image (hence the indexes are swapped)
433-
f"{image_ota_clear},{image_ota_clear}=device:ota2,ota1;flasher:ota2,ota1",
453+
f"{image_ota_clear},{image_ota_clear}=flasher:ota2,ota1",
434454
],
435455
)
Lines changed: 114 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,133 @@
1-
/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */
1+
/* Copyright (c) Martin Prokopič 2024-12-03. */
22

3+
#include <device_lock.h>
34
#include <libretiny.h>
5+
#include <osdep_service.h>
46
#include <sdk_private.h>
57

8+
// from SDK
9+
extern uint32_t sys_update_ota_get_curr_fw_idx(void);
10+
11+
#define FLASH_SECTOR_SIZE 0x1000
12+
// IMAGE_PUBLIC_KEY is defined by the build script as an array initializer
13+
#define IMAGE_PUBLIC_KEY_OFFSET 32
14+
#define IMAGE_PUBLIC_KEY_LENGTH 32
15+
16+
static const uint8_t lt_image_public_key[] = IMAGE_PUBLIC_KEY;
17+
18+
typedef enum {
19+
INVALID = 0,
20+
DISABLED = 1,
21+
ENABLED = 2,
22+
} lt_ota_image_state_t;
23+
24+
static bool lt_ota_get_image_offset(uint8_t index, uint32_t *offset) {
25+
switch (index) {
26+
case 1:
27+
*offset = FLASH_OTA1_OFFSET;
28+
break;
29+
case 2:
30+
*offset = FLASH_OTA2_OFFSET;
31+
break;
32+
default:
33+
return false;
34+
}
35+
return true;
36+
}
37+
38+
static uint8_t lt_ota_get_other_index(uint8_t index) {
39+
return index ^ 0b11; // 1 -> 2, 2 -> 1
40+
}
41+
42+
static lt_ota_image_state_t lt_ota_get_image_state(uint8_t index) {
43+
uint32_t offset;
44+
if (!lt_ota_get_image_offset(index, &offset))
45+
return INVALID;
46+
47+
uint8_t public_key[IMAGE_PUBLIC_KEY_LENGTH];
48+
uint32_t num_read = lt_flash_read(offset + IMAGE_PUBLIC_KEY_OFFSET, public_key, sizeof(public_key));
49+
if (num_read != sizeof(public_key))
50+
return INVALID;
51+
52+
if (memcmp(public_key, lt_image_public_key, sizeof(public_key)) == 0)
53+
return ENABLED;
54+
55+
public_key[0] = ~(public_key[0]);
56+
if (memcmp(public_key, lt_image_public_key, sizeof(public_key)) == 0)
57+
return DISABLED;
58+
59+
return INVALID;
60+
}
61+
62+
static bool lt_ota_set_image_enabled(uint8_t index, bool new_enabled) {
63+
uint32_t offset;
64+
if (!lt_ota_get_image_offset(index, &offset))
65+
return false;
66+
67+
_irqL irqL;
68+
uint8_t *header = (uint8_t *)malloc(FLASH_SECTOR_SIZE);
69+
70+
rtw_enter_critical(NULL, &irqL);
71+
device_mutex_lock(RT_DEV_LOCK_FLASH);
72+
flash_stream_read(&lt_flash_obj, offset, FLASH_SECTOR_SIZE, header);
73+
74+
bool enabled = header[IMAGE_PUBLIC_KEY_OFFSET] == lt_image_public_key[0];
75+
if (enabled != new_enabled) {
76+
// negate first byte of OTA signature
77+
header[0] = ~(header[0]);
78+
// negate first byte of public key
79+
header[IMAGE_PUBLIC_KEY_OFFSET] = ~(header[IMAGE_PUBLIC_KEY_OFFSET]);
80+
81+
// write to flash
82+
hal_flash_sector_erase(lt_flash_obj.phal_spic_adaptor, offset);
83+
hal_flash_burst_write(lt_flash_obj.phal_spic_adaptor, FLASH_SECTOR_SIZE, offset, header);
84+
}
85+
86+
device_mutex_unlock(RT_DEV_LOCK_FLASH);
87+
rtw_exit_critical(NULL, &irqL);
88+
free(header);
89+
90+
return true;
91+
}
92+
93+
// public interface implementation
94+
695
lt_ota_type_t lt_ota_get_type() {
796
return OTA_TYPE_DUAL;
897
}
998

1099
bool lt_ota_is_valid(uint8_t index) {
11-
return false;
100+
return lt_ota_get_image_state(index) != INVALID;
12101
}
13102

14103
uint8_t lt_ota_dual_get_current() {
15-
return 0;
104+
// ambz2 uses virtual memory, so we can't use function address to determine active image
105+
// use the SDK instead
106+
return sys_update_ota_get_curr_fw_idx();
16107
}
17108

18109
uint8_t lt_ota_dual_get_stored() {
19-
return 0;
110+
// bootloader prioritizes FW1 if both are valid
111+
return lt_ota_get_image_state(1) == ENABLED ? 1 : 2;
20112
}
21113

22114
bool lt_ota_switch(bool revert) {
23-
return false;
115+
uint8_t current = lt_ota_dual_get_current();
116+
uint8_t stored = lt_ota_dual_get_stored();
117+
if ((current == stored) == revert)
118+
return true;
119+
120+
uint8_t to_enable = lt_ota_get_other_index(stored);
121+
uint8_t to_disable = stored;
122+
123+
if (!lt_ota_is_valid(to_enable))
124+
return false;
125+
126+
// enable first, so there is always at least one enabled image
127+
if (!lt_ota_set_image_enabled(to_enable, true))
128+
return false;
129+
if (!lt_ota_set_image_enabled(to_disable, false))
130+
return false;
131+
132+
return true;
24133
}

cores/realtek-ambz2/base/lt_defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
#define LT_HAS_LWIP2 1
88
#define LT_HAS_MBEDTLS 1
99
#define LT_HAS_PRINTF 1
10+
#define LT_HAS_OTA 1
1011
#define LT_HW_BLE 1

0 commit comments

Comments
 (0)