| 
2 | 2 | 
 
  | 
3 | 3 | #include <libretiny.h>  | 
4 | 4 | #include <sdk_private.h>  | 
 | 5 | +#include <osdep_service.h>  | 
 | 6 | +#include <device_lock.h>  | 
 | 7 | + | 
 | 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  | 
 | 13 | +#define IMAGE_PUBLIC_KEY_OFFSET 32  | 
 | 14 | +#define IMAGE_PUBLIC_KEY_LENGTH 32  | 
 | 15 | + | 
 | 16 | +typedef enum {  | 
 | 17 | +	INVALID	 = 0,  | 
 | 18 | +	DISABLED = 1,  | 
 | 19 | +	ENABLED	 = 2,  | 
 | 20 | +} lt_ota_image_state_t;  | 
 | 21 | + | 
 | 22 | +static bool lt_ota_get_image_offset(uint8_t index, uint32_t *offset) {  | 
 | 23 | +	switch (index) {  | 
 | 24 | +		case 1:  | 
 | 25 | +			*offset = FLASH_OTA1_OFFSET;  | 
 | 26 | +			break;  | 
 | 27 | +		case 2:  | 
 | 28 | +			*offset = FLASH_OTA2_OFFSET;  | 
 | 29 | +			break;  | 
 | 30 | +		default:  | 
 | 31 | +			return false;  | 
 | 32 | +	}  | 
 | 33 | +	return true;  | 
 | 34 | +}  | 
 | 35 | + | 
 | 36 | +static uint8_t lt_ota_get_other_index(uint8_t index) {  | 
 | 37 | +	return index ^ 0b11; // 1 -> 2, 2 -> 1  | 
 | 38 | +}  | 
 | 39 | + | 
 | 40 | +static lt_ota_image_state_t lt_ota_get_image_state(uint8_t index) {  | 
 | 41 | +	uint32_t offset;  | 
 | 42 | +	if (!lt_ota_get_image_offset(index, &offset))  | 
 | 43 | +		return INVALID;  | 
 | 44 | + | 
 | 45 | +	uint8_t public_key[IMAGE_PUBLIC_KEY_LENGTH];  | 
 | 46 | +	uint32_t num_read = lt_flash_read(offset + IMAGE_PUBLIC_KEY_OFFSET, public_key, sizeof(public_key));  | 
 | 47 | +	if (num_read != sizeof(public_key))  | 
 | 48 | +		return INVALID;  | 
 | 49 | + | 
 | 50 | +	if (memcmp(public_key, IMAGE_PUBLIC_KEY, sizeof(public_key)) == 0)  | 
 | 51 | +		return ENABLED;  | 
 | 52 | + | 
 | 53 | +	public_key[0] = ~(public_key[0]);  | 
 | 54 | +	if (memcmp(public_key, IMAGE_PUBLIC_KEY, sizeof(public_key)) == 0)  | 
 | 55 | +		return DISABLED;  | 
 | 56 | + | 
 | 57 | +	return INVALID;  | 
 | 58 | +}  | 
 | 59 | + | 
 | 60 | +static bool lt_ota_set_image_enabled(uint8_t index, bool new_enabled) {  | 
 | 61 | +	uint32_t offset;  | 
 | 62 | +	if (!lt_ota_get_image_offset(index, &offset))  | 
 | 63 | +		return false;  | 
 | 64 | + | 
 | 65 | +	_irqL irqL;  | 
 | 66 | +	uint8_t *header = (uint8_t *)malloc(FLASH_SECTOR_SIZE);  | 
 | 67 | + | 
 | 68 | +	rtw_enter_critical(NULL, &irqL);  | 
 | 69 | +	device_mutex_lock(RT_DEV_LOCK_FLASH);  | 
 | 70 | +	flash_stream_read(<_flash_obj, offset, FLASH_SECTOR_SIZE, header);  | 
 | 71 | + | 
 | 72 | +	bool enabled = header[IMAGE_PUBLIC_KEY_OFFSET] == IMAGE_PUBLIC_KEY[0];  | 
 | 73 | +	if (enabled != new_enabled) {  | 
 | 74 | +		// negate first byte of OTA signature  | 
 | 75 | +		header[0] = ~(header[0]);  | 
 | 76 | +		// negate first byte of public key  | 
 | 77 | +		header[IMAGE_PUBLIC_KEY_OFFSET] = ~(header[IMAGE_PUBLIC_KEY_OFFSET]);  | 
 | 78 | + | 
 | 79 | +		// write to flash  | 
 | 80 | +		hal_flash_sector_erase(lt_flash_obj.phal_spic_adaptor, offset);  | 
 | 81 | +		hal_flash_burst_write(lt_flash_obj.phal_spic_adaptor, FLASH_SECTOR_SIZE, offset, header);  | 
 | 82 | +	}  | 
 | 83 | + | 
 | 84 | +	device_mutex_unlock(RT_DEV_LOCK_FLASH);  | 
 | 85 | +	rtw_exit_critical(NULL, &irqL);  | 
 | 86 | +	free(header);  | 
 | 87 | + | 
 | 88 | +	return true;  | 
 | 89 | +}  | 
 | 90 | + | 
 | 91 | +// public interface implementation  | 
5 | 92 | 
 
  | 
6 | 93 | lt_ota_type_t lt_ota_get_type() {  | 
7 | 94 | 	return OTA_TYPE_DUAL;  | 
8 | 95 | }  | 
9 | 96 | 
 
  | 
10 | 97 | bool lt_ota_is_valid(uint8_t index) {  | 
11 |  | -	return false;  | 
 | 98 | +	return lt_ota_get_image_state(index) != INVALID;  | 
12 | 99 | }  | 
13 | 100 | 
 
  | 
14 | 101 | uint8_t lt_ota_dual_get_current() {  | 
15 |  | -	return 0;  | 
 | 102 | +	// ambz2 uses virtual memory, so we can't use function address to determine active image  | 
 | 103 | +	// use the SDK instead  | 
 | 104 | +	return sys_update_ota_get_curr_fw_idx();  | 
16 | 105 | }  | 
17 | 106 | 
 
  | 
18 | 107 | uint8_t lt_ota_dual_get_stored() {  | 
19 |  | -	return 0;  | 
 | 108 | +	// bootloader prioritizes FW1 if both are valid  | 
 | 109 | +	return lt_ota_get_image_state(1) == ENABLED ? 1 : 2;  | 
20 | 110 | }  | 
21 | 111 | 
 
  | 
22 | 112 | bool lt_ota_switch(bool revert) {  | 
23 |  | -	return false;  | 
 | 113 | +	uint8_t current = lt_ota_dual_get_current();  | 
 | 114 | +	uint8_t stored	= lt_ota_dual_get_stored();  | 
 | 115 | +	if ((current == stored) == revert)  | 
 | 116 | +		return true;  | 
 | 117 | + | 
 | 118 | +	uint8_t to_enable  = lt_ota_get_other_index(stored);  | 
 | 119 | +	uint8_t to_disable = stored;  | 
 | 120 | + | 
 | 121 | +	if (!lt_ota_is_valid(to_enable))  | 
 | 122 | +		return false;  | 
 | 123 | + | 
 | 124 | +	// enable first, so there is always at least one enabled image  | 
 | 125 | +	if (!lt_ota_set_image_enabled(to_enable, true))  | 
 | 126 | +		return false;  | 
 | 127 | +	if (!lt_ota_set_image_enabled(to_disable, false))  | 
 | 128 | +		return false;  | 
 | 129 | + | 
 | 130 | +	return true;  | 
24 | 131 | }  | 
0 commit comments