diff --git a/boards/arm/rtl8762gn_evb/rtl8762gn_evb.dts b/boards/arm/rtl8762gn_evb/rtl8762gn_evb.dts index ae6ba61d764ee..8410b003d0c10 100644 --- a/boards/arm/rtl8762gn_evb/rtl8762gn_evb.dts +++ b/boards/arm/rtl8762gn_evb/rtl8762gn_evb.dts @@ -24,6 +24,7 @@ }; &flash { + reg = <0x4000000 DT_SIZE_K(1024)>; partitions { compatible = "fixed-partitions"; #address-cells = <1>; @@ -58,7 +59,11 @@ }; app_partition: partition@2d000 { label = "app-image"; - reg = <0x2D000 DT_SIZE_K(828)>; + reg = <0x2D000 DT_SIZE_K(412)>; + }; + ota_tmp_partition: partition@94000 { + label = "ota-tmp-image"; + reg = <0x94000 DT_SIZE_K(416)>; }; storage_partition: partition@fc000 { label = "storage"; @@ -79,4 +84,8 @@ parity = "none"; stop-bits = "1"; data-bits = <8>; +}; + +&corewdt { + status = "okay"; }; \ No newline at end of file diff --git a/dts/arm/realtek/rtl87x2g.dtsi b/dts/arm/realtek/rtl87x2g.dtsi index fc8e770a197a6..41ca77aa50923 100644 --- a/dts/arm/realtek/rtl87x2g.dtsi +++ b/dts/arm/realtek/rtl87x2g.dtsi @@ -81,7 +81,6 @@ compatible = "soc-nv-flash"; write-block-size = <1>; erase-block-size = <4096>; - reg = <0x4000000 DT_SIZE_K(1024)>; }; }; diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/CMakeLists.txt b/samples/bluetooth/rtk_ota_sample_dual_bank/CMakeLists.txt new file mode 100644 index 0000000000000..83c538f490b18 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(rtk_ota_sample_dual_bank) + +target_sources(app PRIVATE + src/main.c + src/cts.c +) \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/README.md b/samples/bluetooth/rtk_ota_sample_dual_bank/README.md new file mode 100644 index 0000000000000..f90ff1cd14f8a --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/README.md @@ -0,0 +1,17 @@ +### 工程编译 + +该工程默认编译 `bank0 Image`。如果需要编译 `bank1 Image`,请将 `rtl8762gn_evb.overlay` 中的 `zephyr,code-partition` 修改为 `&app_partition_1`。 + +### 脚本运行 + +为了使得 Zephyr Image 能够兼容 Realtek 的 OTA 系统,在编译完后,请运行 `tools/run.bat`。该脚本会将生成的 `zephyr.bin` 加上 Realtek 的 MP header,并将sha256校验值、payload length 等写入 image header 中。 + +最终将生成两版 image,分别是 `zephyrImage_MP.bin` 和 `zephyrImage.bin`(不带 MP header)。 + +### 如何在蓝牙工程中打开RTK OTA? + +要开启OTA功能,需要在开启蓝牙的app中打开CONFIG_REALTEK_OTA。 + +另外如果需要对Zephyr Image进行OTA升级,请拷贝本工程路径下的tools目录到您的应用程序路径下,并使用tools/run.bat脚本对原始Zephyr Image进行处理。 + +OTA相关的source/header file放置在 `zephyr\soc\arm\realtek_bee\rtl87x2g\ota_src\` 目录下。 \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/boards/rtl8762gn_evb.overlay b/samples/bluetooth/rtk_ota_sample_dual_bank/boards/rtl8762gn_evb.overlay new file mode 100644 index 0000000000000..4c39d0cd7fab0 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/boards/rtl8762gn_evb.overlay @@ -0,0 +1,69 @@ +/ { + chosen { + zephyr,code-partition = &app_partition_0; + }; +}; + + +&flash { + reg = <0x4000000 DT_SIZE_K(1024)>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + reserved: partition@0 { + label = "reserved-image"; + reg = <0x0 DT_SIZE_K(4)>; + }; + config_file: partition@1000 { + label = "config-file-image"; + reg = <0x1000 DT_SIZE_K(4)>; + }; + boot_patch_0: partition@2000 { + label = "boot-patch-0-image"; + reg = <0x2000 DT_SIZE_K(32)>; + }; + boot_patch_1: partition@a000 { + label = "boot-patch-1-image"; + reg = <0xA000 DT_SIZE_K(32)>; + }; + /* Bank 0 */ + ota_header_0: partition@12000 { + label = "ota-header-0-image"; + reg = <0x12000 DT_SIZE_K(4)>; + }; + system_patch_0: partition@13000 { + label = "system-patch-0-image"; + reg = <0x13000 DT_SIZE_K(32)>; + }; + stack_patch_0: partition@1b000 { + label = "stack-patch-0-image"; + reg = <0x1B000 DT_SIZE_K(72)>; + }; + app_partition_0: partition@2d000 { + label = "app-image-0"; + reg = <0x2D000 DT_SIZE_K(360)>; + }; + /* Bank 1 */ + ota_header_1: partition@87000 { + label = "ota-header-1-image"; + reg = <0x87000 DT_SIZE_K(4)>; + }; + system_patch_1: partition@88000 { + label = "system-patch-1-image"; + reg = <0x88000 DT_SIZE_K(32)>; + }; + stack_patch_1: partition@90000 { + label = "stack-patch-1-image"; + reg = <0x90000 DT_SIZE_K(72)>; + }; + app_partition_1: partition@a2000 { + label = "app-image-1"; + reg = <0xA2000 DT_SIZE_K(360)>; + }; + storage_partition: partition@fc000 { + label = "storage"; + reg = <0xFC000 DT_SIZE_K(16)>; + }; + }; +}; \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/prj.conf b/samples/bluetooth/rtk_ota_sample_dual_bank/prj.conf new file mode 100644 index 0000000000000..5461e38cbd943 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/prj.conf @@ -0,0 +1,29 @@ +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_SMP=y +CONFIG_BT_SIGNING=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DIS=y +CONFIG_BT_ATT_PREPARE_COUNT=5 +CONFIG_BT_BAS=y +CONFIG_BT_HRS=y +CONFIG_BT_IAS=y +# CONFIG_BT_PRIVACY=y +CONFIG_BT_DEVICE_NAME="Zephyr Peripheral Sample Long Name" +CONFIG_BT_DEVICE_APPEARANCE=833 +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=65 + +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +CONFIG_REALTEK_OTA=y +CONFIG_LOG_BUFFER_SIZE=3072 diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/src/cts.c b/samples/bluetooth/rtk_ota_sample_dual_bank/src/cts.c new file mode 100644 index 0000000000000..20b53177d6d0f --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/src/cts.c @@ -0,0 +1,109 @@ +/** @file + * @brief CTS Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static uint8_t ct[10]; +static uint8_t ct_update; + +static void ct_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + /* TODO: Handle value */ +} + +static ssize_t read_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(ct)); +} + +static ssize_t write_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > sizeof(ct)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + ct_update = 1U; + + return len; +} + +/* Current Time Service Declaration */ +BT_GATT_SERVICE_DEFINE(cts_cvs, + BT_GATT_PRIMARY_SERVICE(BT_UUID_CTS), + BT_GATT_CHARACTERISTIC(BT_UUID_CTS_CURRENT_TIME, BT_GATT_CHRC_READ | + BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_ct, write_ct, ct), + BT_GATT_CCC(ct_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), +); + +static void generate_current_time(uint8_t *buf) +{ + uint16_t year; + + /* 'Exact Time 256' contains 'Day Date Time' which contains + * 'Date Time' - characteristic contains fields for: + * year, month, day, hours, minutes and seconds. + */ + + year = sys_cpu_to_le16(2015); + memcpy(buf, &year, 2); /* year */ + buf[2] = 5U; /* months starting from 1 */ + buf[3] = 30U; /* day */ + buf[4] = 12U; /* hours */ + buf[5] = 45U; /* minutes */ + buf[6] = 30U; /* seconds */ + + /* 'Day of Week' part of 'Day Date Time' */ + buf[7] = 1U; /* day of week starting from 1 */ + + /* 'Fractions 256 part of 'Exact Time 256' */ + buf[8] = 0U; + + /* Adjust reason */ + buf[9] = 0U; /* No update, change, etc */ +} + +void cts_init(void) +{ + /* Simulate current time for Current Time Service */ + generate_current_time(ct); +} + +void cts_notify(void) +{ /* Current Time Service updates only when time is changed */ + if (!ct_update) { + return; + } + + ct_update = 0U; + bt_gatt_notify(NULL, &cts_cvs.attrs[1], &ct, sizeof(ct)); +} diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/src/cts.h b/samples/bluetooth/rtk_ota_sample_dual_bank/src/cts.h new file mode 100644 index 0000000000000..6e3cca03a0b97 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/src/cts.h @@ -0,0 +1,20 @@ +/** @file + * @brief CTS Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void cts_init(void); +void cts_notify(void); + +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/src/main.c b/samples/bluetooth/rtk_ota_sample_dual_bank/src/main.c new file mode 100644 index 0000000000000..39690ed65100e --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/src/main.c @@ -0,0 +1,462 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cts.h" + +#include +#include + +#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#include +LOG_MODULE_REGISTER(main); + +/* Custom Service Variables */ +#define BT_UUID_CUSTOM_SERVICE_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) + +static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( + BT_UUID_CUSTOM_SERVICE_VAL); + +static struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); + +static struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); + +#define VND_MAX_LEN 20 + +static uint8_t vnd_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r'}; +static uint8_t vnd_auth_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r'}; +static uint8_t vnd_wwr_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r' }; + +static ssize_t read_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + strlen(value)); +} + +static ssize_t write_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > VND_MAX_LEN) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + value[offset + len] = 0; + + return len; +} + +static uint8_t simulate_vnd; +static uint8_t indicating; +static struct bt_gatt_indicate_params ind_params; + +static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + simulate_vnd = (value == BT_GATT_CCC_INDICATE) ? 1 : 0; +} + +static void indicate_cb(struct bt_conn *conn, + struct bt_gatt_indicate_params *params, uint8_t err) +{ + printk("Indication %s\n", err != 0U ? "fail" : "success"); +} + +static void indicate_destroy(struct bt_gatt_indicate_params *params) +{ + printk("Indication complete\n"); + indicating = 0U; +} + +#define VND_LONG_MAX_LEN 74 +static uint8_t vnd_long_value[VND_LONG_MAX_LEN + 1] = { + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '1', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '2', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '3', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '4', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '5', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '6', + '.', ' ' }; + +static ssize_t write_long_vnd(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (flags & BT_GATT_WRITE_FLAG_PREPARE) { + return 0; + } + + if (offset + len > VND_LONG_MAX_LEN) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + value[offset + len] = 0; + + return len; +} + +static const struct bt_uuid_128 vnd_long_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef3)); + +static struct bt_gatt_cep vnd_long_cep = { + .properties = BT_GATT_CEP_RELIABLE_WRITE, +}; + +static int signed_value; + +static ssize_t read_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(signed_value)); +} + +static ssize_t write_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > sizeof(signed_value)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + + return len; +} + +static const struct bt_uuid_128 vnd_signed_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x13345678, 0x1234, 0x5678, 0x1334, 0x56789abcdef3)); + +static const struct bt_uuid_128 vnd_write_cmd_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef4)); + +static ssize_t write_without_rsp_vnd(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (!(flags & BT_GATT_WRITE_FLAG_CMD)) { + /* Write Request received. Reject it since this Characteristic + * only accepts Write Without Response. + */ + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); + } + + if (offset + len > VND_MAX_LEN) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + value[offset + len] = 0; + + return len; +} + +/* Vendor Primary Service Declaration */ +BT_GATT_SERVICE_DEFINE(vnd_svc, + BT_GATT_PRIMARY_SERVICE(&vnd_uuid), + BT_GATT_CHARACTERISTIC(&vnd_enc_uuid.uuid, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | + BT_GATT_CHRC_INDICATE, + BT_GATT_PERM_READ_ENCRYPT | + BT_GATT_PERM_WRITE_ENCRYPT, + read_vnd, write_vnd, vnd_value), + BT_GATT_CCC(vnd_ccc_cfg_changed, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_CHARACTERISTIC(&vnd_auth_uuid.uuid, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ_AUTHEN | + BT_GATT_PERM_WRITE_AUTHEN, + read_vnd, write_vnd, vnd_auth_value), + BT_GATT_CHARACTERISTIC(&vnd_long_uuid.uuid, BT_GATT_CHRC_READ | + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_EXT_PROP, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE | + BT_GATT_PERM_PREPARE_WRITE, + read_vnd, write_long_vnd, &vnd_long_value), + BT_GATT_CEP(&vnd_long_cep), + BT_GATT_CHARACTERISTIC(&vnd_signed_uuid.uuid, BT_GATT_CHRC_READ | + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_AUTH, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_signed, write_signed, &signed_value), + BT_GATT_CHARACTERISTIC(&vnd_write_cmd_uuid.uuid, + BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, NULL, + write_without_rsp_vnd, &vnd_wwr_value), +); + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_HRS_VAL), + BT_UUID_16_ENCODE(BT_UUID_BAS_VAL), + BT_UUID_16_ENCODE(BT_UUID_CTS_VAL)), + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL), +}; + +void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) +{ + printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx); +} + +static struct bt_gatt_cb gatt_callbacks = { + .att_mtu_updated = mtu_updated +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + printk("Connection failed (err 0x%02x)\n", err); + } else { + printk("Connected\n"); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); +} + +static void alert_stop(void) +{ + printk("Alert stopped\n"); +} + +static void alert_start(void) +{ + printk("Mild alert started\n"); +} + +static void alert_high_start(void) +{ + printk("High alert started\n"); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +BT_IAS_CB_DEFINE(ias_callbacks) = { + .no_alert = alert_stop, + .mild_alert = alert_start, + .high_alert = alert_high_start, +}; + +static void bt_ready(void) +{ + int err; + + printk("Bluetooth initialized\n"); + + cts_init(); + + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); +} + +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Passkey for %s: %06u\n", addr, passkey); +} + +static void auth_cancel(struct bt_conn *conn) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Pairing cancelled: %s\n", addr); +} + +static struct bt_conn_auth_cb auth_cb_display = { + .passkey_display = auth_passkey_display, + .passkey_entry = NULL, + .cancel = auth_cancel, +}; + +static void bas_notify(void) +{ + uint8_t battery_level = bt_bas_get_battery_level(); + + battery_level--; + + if (!battery_level) { + battery_level = 100U; + } + + bt_bas_set_battery_level(battery_level); +} + +static void hrs_notify(void) +{ + static uint8_t heartrate = 90U; + + /* Heartrate measurements simulation */ + heartrate++; + if (heartrate == 160U) { + heartrate = 90U; + } + + bt_hrs_notify(heartrate); +} + + +/** +* @brief print all images version to check ota whether success. +* @return void +*/ +void print_all_images_version(void) +{ + IMG_ID image_id; + T_IMAGE_VERSION image_version; + + for (image_id = IMG_DFU_FIRST; image_id < IMG_DFU_MAX; image_id++) + { + if (image_id == IMG_OTA) + { + if (get_ota_bank_image_version(true, image_id, &image_version)) + { + LOG_INF("image:0x%x,version =0x%x, sub_version:%d.%d.%d.%d", image_id, + image_version.ver_info.version, + image_version.ver_info.header_sub_version._version_major, + image_version.ver_info.header_sub_version._version_minor, + image_version.ver_info.header_sub_version._version_revision, + image_version.ver_info.header_sub_version._version_reserve); + } + else + { + LOG_INF("image:0x%x get_active_bank_image_version fail!!!", image_id); + } + } + else + { + if (get_ota_bank_image_version(true, image_id, &image_version)) + { + LOG_INF("image:0x%x,version =0x%x, sub_version:%d.%d.%d.%d", image_id, + image_version.ver_info.version, + image_version.ver_info.img_sub_version._version_major, + image_version.ver_info.img_sub_version._version_minor, + image_version.ver_info.img_sub_version._version_revision, + image_version.ver_info.img_sub_version._version_reserve); + } + else + { + LOG_INF("image:0x%x get_active_bank_image_version fail!!!", image_id); + } + } + } +} + +int main(void) +{ + struct bt_gatt_attr *vnd_ind_attr; + char str[BT_UUID_STR_LEN]; + int err; + + printk("new version, bank1 image!"); + + print_all_images_version(); + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + bt_ready(); + + bt_gatt_cb_register(&gatt_callbacks); + bt_conn_auth_cb_register(&auth_cb_display); + + vnd_ind_attr = bt_gatt_find_by_uuid(vnd_svc.attrs, vnd_svc.attr_count, + &vnd_enc_uuid.uuid); + bt_uuid_to_str(&vnd_enc_uuid.uuid, str, sizeof(str)); + printk("Indicate VND attr %p (UUID %s)\n", vnd_ind_attr, str); + + /* Implement notification. At the moment there is no suitable way + * of starting delayed work so we do it here + */ + while (1) { + k_sleep(K_SECONDS(1)); + + /* Current Time Service updates only when time is changed */ + cts_notify(); + + /* Heartrate measurements simulation */ + hrs_notify(); + + /* Battery level simulation */ + bas_notify(); + + /* Vendor indication simulation */ + if (simulate_vnd && vnd_ind_attr) { + if (indicating) { + continue; + } + + ind_params.attr = vnd_ind_attr; + ind_params.func = indicate_cb; + ind_params.destroy = indicate_destroy; + ind_params.data = &indicating; + ind_params.len = sizeof(indicating); + + if (bt_gatt_indicate(NULL, &ind_params) == 0) { + indicating = 1U; + } + } + } + return 0; +} diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/README b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/README new file mode 100644 index 0000000000000..8cf6e142e5c6e --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/README @@ -0,0 +1,5 @@ +keys +====== + +key.json: OCEK and PASSWORD sample +rtk_ecdsa.xxx: ecdsa signature sample diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/key.json b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/key.json new file mode 100644 index 0000000000000..9a79400f7c5f6 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/key.json @@ -0,0 +1,4 @@ +{ + "OCEK": "a1a2a3a4a5a6a7a8a9aaabacadaeafb0", + "PASSWORD": "00112233445566778899aabbccddeeff" +} \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa.pem b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa.pem new file mode 100644 index 0000000000000..2fde99cc76989 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIHBvHQKJqQJ7Dc22oTMVJRa75ItJi4EQNa0xq4cLp19goAoGCCqGSM49 +AwEHoUQDQgAERxQjDI55qFayMeNklNQEOZfc9NhW7lvY/wUR3w6hn3kwFjXlZMlo +VCYNNM5eUP6WVMipL9kvZVuGCB3uEgXzaw== +-----END EC PRIVATE KEY----- diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa.pub b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa.pub new file mode 100644 index 0000000000000..08d131fef081f --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERxQjDI55qFayMeNklNQEOZfc9NhW +7lvY/wUR3w6hn3kwFjXlZMloVCYNNM5eUP6WVMipL9kvZVuGCB3uEgXzaw== +-----END PUBLIC KEY----- diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa_hash.bin b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa_hash.bin new file mode 100644 index 0000000000000..d785c7578e0cf Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/keys/rtk_ecdsa_hash.bin differ diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/md5/MD5 b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/md5/MD5 new file mode 100644 index 0000000000000..20ae344f20a9c Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/md5/MD5 differ diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/md5/MD5.exe b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/md5/MD5.exe new file mode 100644 index 0000000000000..a1ca9039bfb58 Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/md5/MD5.exe differ diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/mp.ini b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/mp.ini new file mode 100644 index 0000000000000..e54542b891b4c --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/mp.ini @@ -0,0 +1,5 @@ +[MandatoryInfo] +BinID=ID_APP +Version=1.0.1.1 +PartNumber= +DataLength= \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/prepend_header/prepend_header b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/prepend_header/prepend_header new file mode 100644 index 0000000000000..86d9916766663 Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/prepend_header/prepend_header differ diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/prepend_header/prepend_header.exe b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/prepend_header/prepend_header.exe new file mode 100644 index 0000000000000..3ac69c89368b9 Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/prepend_header/prepend_header.exe differ diff --git a/samples/bluetooth/rtk_ota_sample_dual_bank/tools/run.bat b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/run.bat new file mode 100644 index 0000000000000..8c4bc08b09875 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_dual_bank/tools/run.bat @@ -0,0 +1,10 @@ +del "zephyr*.bin" +cp ../build/zephyr/zephyr.bin . +@REM Prepend_header: 1. Calculate SHA256/crc by default. +@REM 2. Calculate signature/flash-sec by option. +@REM 3. Add mp header by default. +.\prepend_header\prepend_header.exe -t app_code -b 15 -p "./zephyr.bin" -m 1 -i "./mp.ini" +1>NUL ren zephyr.bin zephyrImage.bin +1>NUL ren zephyr_MP.bin zephyrImage_MP.bin +@REM MD5: Calculate MD5 and add it in the image file name. +.\md5\md5.exe "zephyrImage_MP.bin" \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/CMakeLists.txt b/samples/bluetooth/rtk_ota_sample_single_bank/CMakeLists.txt new file mode 100644 index 0000000000000..d8d55874ac26b --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(rtk_ota_sample_single_bank) + +target_sources(app PRIVATE + src/main.c + src/cts.c +) \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/prj.conf b/samples/bluetooth/rtk_ota_sample_single_bank/prj.conf new file mode 100644 index 0000000000000..b848bf1ee19eb --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/prj.conf @@ -0,0 +1,29 @@ +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_SMP=y +CONFIG_BT_SIGNING=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DIS=y +CONFIG_BT_ATT_PREPARE_COUNT=5 +CONFIG_BT_BAS=y +CONFIG_BT_HRS=y +CONFIG_BT_IAS=y +# CONFIG_BT_PRIVACY=y +CONFIG_BT_DEVICE_NAME="Zephyr Peripheral Sample Long Name" +CONFIG_BT_DEVICE_APPEARANCE=833 +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=65 + +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +CONFIG_REALTEK_OTA=y + diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/src/cts.c b/samples/bluetooth/rtk_ota_sample_single_bank/src/cts.c new file mode 100644 index 0000000000000..20b53177d6d0f --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/src/cts.c @@ -0,0 +1,109 @@ +/** @file + * @brief CTS Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static uint8_t ct[10]; +static uint8_t ct_update; + +static void ct_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + /* TODO: Handle value */ +} + +static ssize_t read_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(ct)); +} + +static ssize_t write_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > sizeof(ct)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + ct_update = 1U; + + return len; +} + +/* Current Time Service Declaration */ +BT_GATT_SERVICE_DEFINE(cts_cvs, + BT_GATT_PRIMARY_SERVICE(BT_UUID_CTS), + BT_GATT_CHARACTERISTIC(BT_UUID_CTS_CURRENT_TIME, BT_GATT_CHRC_READ | + BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_ct, write_ct, ct), + BT_GATT_CCC(ct_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), +); + +static void generate_current_time(uint8_t *buf) +{ + uint16_t year; + + /* 'Exact Time 256' contains 'Day Date Time' which contains + * 'Date Time' - characteristic contains fields for: + * year, month, day, hours, minutes and seconds. + */ + + year = sys_cpu_to_le16(2015); + memcpy(buf, &year, 2); /* year */ + buf[2] = 5U; /* months starting from 1 */ + buf[3] = 30U; /* day */ + buf[4] = 12U; /* hours */ + buf[5] = 45U; /* minutes */ + buf[6] = 30U; /* seconds */ + + /* 'Day of Week' part of 'Day Date Time' */ + buf[7] = 1U; /* day of week starting from 1 */ + + /* 'Fractions 256 part of 'Exact Time 256' */ + buf[8] = 0U; + + /* Adjust reason */ + buf[9] = 0U; /* No update, change, etc */ +} + +void cts_init(void) +{ + /* Simulate current time for Current Time Service */ + generate_current_time(ct); +} + +void cts_notify(void) +{ /* Current Time Service updates only when time is changed */ + if (!ct_update) { + return; + } + + ct_update = 0U; + bt_gatt_notify(NULL, &cts_cvs.attrs[1], &ct, sizeof(ct)); +} diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/src/cts.h b/samples/bluetooth/rtk_ota_sample_single_bank/src/cts.h new file mode 100644 index 0000000000000..6e3cca03a0b97 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/src/cts.h @@ -0,0 +1,20 @@ +/** @file + * @brief CTS Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void cts_init(void); +void cts_notify(void); + +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/src/main.c b/samples/bluetooth/rtk_ota_sample_single_bank/src/main.c new file mode 100644 index 0000000000000..64d98ad9225fc --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/src/main.c @@ -0,0 +1,460 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cts.h" + +#include +#include + +#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#include +LOG_MODULE_REGISTER(main); + +/* Custom Service Variables */ +#define BT_UUID_CUSTOM_SERVICE_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) + +static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( + BT_UUID_CUSTOM_SERVICE_VAL); + +static struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); + +static struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); + +#define VND_MAX_LEN 20 + +static uint8_t vnd_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r'}; +static uint8_t vnd_auth_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r'}; +static uint8_t vnd_wwr_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r' }; + +static ssize_t read_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + strlen(value)); +} + +static ssize_t write_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > VND_MAX_LEN) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + value[offset + len] = 0; + + return len; +} + +static uint8_t simulate_vnd; +static uint8_t indicating; +static struct bt_gatt_indicate_params ind_params; + +static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + simulate_vnd = (value == BT_GATT_CCC_INDICATE) ? 1 : 0; +} + +static void indicate_cb(struct bt_conn *conn, + struct bt_gatt_indicate_params *params, uint8_t err) +{ + printk("Indication %s\n", err != 0U ? "fail" : "success"); +} + +static void indicate_destroy(struct bt_gatt_indicate_params *params) +{ + printk("Indication complete\n"); + indicating = 0U; +} + +#define VND_LONG_MAX_LEN 74 +static uint8_t vnd_long_value[VND_LONG_MAX_LEN + 1] = { + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '1', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '2', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '3', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '4', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '5', + 'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '6', + '.', ' ' }; + +static ssize_t write_long_vnd(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (flags & BT_GATT_WRITE_FLAG_PREPARE) { + return 0; + } + + if (offset + len > VND_LONG_MAX_LEN) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + value[offset + len] = 0; + + return len; +} + +static const struct bt_uuid_128 vnd_long_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef3)); + +static struct bt_gatt_cep vnd_long_cep = { + .properties = BT_GATT_CEP_RELIABLE_WRITE, +}; + +static int signed_value; + +static ssize_t read_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(signed_value)); +} + +static ssize_t write_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > sizeof(signed_value)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + + return len; +} + +static const struct bt_uuid_128 vnd_signed_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x13345678, 0x1234, 0x5678, 0x1334, 0x56789abcdef3)); + +static const struct bt_uuid_128 vnd_write_cmd_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef4)); + +static ssize_t write_without_rsp_vnd(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (!(flags & BT_GATT_WRITE_FLAG_CMD)) { + /* Write Request received. Reject it since this Characteristic + * only accepts Write Without Response. + */ + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); + } + + if (offset + len > VND_MAX_LEN) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + value[offset + len] = 0; + + return len; +} + +/* Vendor Primary Service Declaration */ +BT_GATT_SERVICE_DEFINE(vnd_svc, + BT_GATT_PRIMARY_SERVICE(&vnd_uuid), + BT_GATT_CHARACTERISTIC(&vnd_enc_uuid.uuid, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | + BT_GATT_CHRC_INDICATE, + BT_GATT_PERM_READ_ENCRYPT | + BT_GATT_PERM_WRITE_ENCRYPT, + read_vnd, write_vnd, vnd_value), + BT_GATT_CCC(vnd_ccc_cfg_changed, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_CHARACTERISTIC(&vnd_auth_uuid.uuid, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ_AUTHEN | + BT_GATT_PERM_WRITE_AUTHEN, + read_vnd, write_vnd, vnd_auth_value), + BT_GATT_CHARACTERISTIC(&vnd_long_uuid.uuid, BT_GATT_CHRC_READ | + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_EXT_PROP, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE | + BT_GATT_PERM_PREPARE_WRITE, + read_vnd, write_long_vnd, &vnd_long_value), + BT_GATT_CEP(&vnd_long_cep), + BT_GATT_CHARACTERISTIC(&vnd_signed_uuid.uuid, BT_GATT_CHRC_READ | + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_AUTH, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_signed, write_signed, &signed_value), + BT_GATT_CHARACTERISTIC(&vnd_write_cmd_uuid.uuid, + BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, NULL, + write_without_rsp_vnd, &vnd_wwr_value), +); + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_HRS_VAL), + BT_UUID_16_ENCODE(BT_UUID_BAS_VAL), + BT_UUID_16_ENCODE(BT_UUID_CTS_VAL)), + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL), +}; + +void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) +{ + printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx); +} + +static struct bt_gatt_cb gatt_callbacks = { + .att_mtu_updated = mtu_updated +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + printk("Connection failed (err 0x%02x)\n", err); + } else { + printk("Connected\n"); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); +} + +static void alert_stop(void) +{ + printk("Alert stopped\n"); +} + +static void alert_start(void) +{ + printk("Mild alert started\n"); +} + +static void alert_high_start(void) +{ + printk("High alert started\n"); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +BT_IAS_CB_DEFINE(ias_callbacks) = { + .no_alert = alert_stop, + .mild_alert = alert_start, + .high_alert = alert_high_start, +}; + +static void bt_ready(void) +{ + int err; + + printk("Bluetooth initialized\n"); + + cts_init(); + + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); +} + +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Passkey for %s: %06u\n", addr, passkey); +} + +static void auth_cancel(struct bt_conn *conn) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Pairing cancelled: %s\n", addr); +} + +static struct bt_conn_auth_cb auth_cb_display = { + .passkey_display = auth_passkey_display, + .passkey_entry = NULL, + .cancel = auth_cancel, +}; + +static void bas_notify(void) +{ + uint8_t battery_level = bt_bas_get_battery_level(); + + battery_level--; + + if (!battery_level) { + battery_level = 100U; + } + + bt_bas_set_battery_level(battery_level); +} + +static void hrs_notify(void) +{ + static uint8_t heartrate = 90U; + + /* Heartrate measurements simulation */ + heartrate++; + if (heartrate == 160U) { + heartrate = 90U; + } + + bt_hrs_notify(heartrate); +} + + +/** +* @brief print all images version to check ota whether success. +* @return void +*/ +void print_all_images_version(void) +{ + IMG_ID image_id; + T_IMAGE_VERSION image_version; + + for (image_id = IMG_DFU_FIRST; image_id < IMG_DFU_MAX; image_id++) + { + if (image_id == IMG_OTA) + { + if (get_ota_bank_image_version(true, image_id, &image_version)) + { + LOG_INF("image:0x%x,version =0x%x, sub_version:%d.%d.%d.%d", image_id, + image_version.ver_info.version, + image_version.ver_info.header_sub_version._version_major, + image_version.ver_info.header_sub_version._version_minor, + image_version.ver_info.header_sub_version._version_revision, + image_version.ver_info.header_sub_version._version_reserve); + } + else + { + LOG_INF("image:0x%x get_active_bank_image_version fail!!!", image_id); + } + } + else + { + if (get_ota_bank_image_version(true, image_id, &image_version)) + { + LOG_INF("image:0x%x,version =0x%x, sub_version:%d.%d.%d.%d", image_id, + image_version.ver_info.version, + image_version.ver_info.img_sub_version._version_major, + image_version.ver_info.img_sub_version._version_minor, + image_version.ver_info.img_sub_version._version_revision, + image_version.ver_info.img_sub_version._version_reserve); + } + else + { + LOG_INF("image:0x%x get_active_bank_image_version fail!!!", image_id); + } + } + } +} + +int main(void) +{ + struct bt_gatt_attr *vnd_ind_attr; + char str[BT_UUID_STR_LEN]; + int err; + + print_all_images_version(); + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + bt_ready(); + + bt_gatt_cb_register(&gatt_callbacks); + bt_conn_auth_cb_register(&auth_cb_display); + + vnd_ind_attr = bt_gatt_find_by_uuid(vnd_svc.attrs, vnd_svc.attr_count, + &vnd_enc_uuid.uuid); + bt_uuid_to_str(&vnd_enc_uuid.uuid, str, sizeof(str)); + printk("Indicate VND attr %p (UUID %s)\n", vnd_ind_attr, str); + + /* Implement notification. At the moment there is no suitable way + * of starting delayed work so we do it here + */ + while (1) { + k_sleep(K_SECONDS(1)); + + /* Current Time Service updates only when time is changed */ + cts_notify(); + + /* Heartrate measurements simulation */ + hrs_notify(); + + /* Battery level simulation */ + bas_notify(); + + /* Vendor indication simulation */ + if (simulate_vnd && vnd_ind_attr) { + if (indicating) { + continue; + } + + ind_params.attr = vnd_ind_attr; + ind_params.func = indicate_cb; + ind_params.destroy = indicate_destroy; + ind_params.data = &indicating; + ind_params.len = sizeof(indicating); + + if (bt_gatt_indicate(NULL, &ind_params) == 0) { + indicating = 1U; + } + } + } + return 0; +} diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/README b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/README new file mode 100644 index 0000000000000..8cf6e142e5c6e --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/README @@ -0,0 +1,5 @@ +keys +====== + +key.json: OCEK and PASSWORD sample +rtk_ecdsa.xxx: ecdsa signature sample diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/key.json b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/key.json new file mode 100644 index 0000000000000..9a79400f7c5f6 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/key.json @@ -0,0 +1,4 @@ +{ + "OCEK": "a1a2a3a4a5a6a7a8a9aaabacadaeafb0", + "PASSWORD": "00112233445566778899aabbccddeeff" +} \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa.pem b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa.pem new file mode 100644 index 0000000000000..2fde99cc76989 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIHBvHQKJqQJ7Dc22oTMVJRa75ItJi4EQNa0xq4cLp19goAoGCCqGSM49 +AwEHoUQDQgAERxQjDI55qFayMeNklNQEOZfc9NhW7lvY/wUR3w6hn3kwFjXlZMlo +VCYNNM5eUP6WVMipL9kvZVuGCB3uEgXzaw== +-----END EC PRIVATE KEY----- diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa.pub b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa.pub new file mode 100644 index 0000000000000..08d131fef081f --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERxQjDI55qFayMeNklNQEOZfc9NhW +7lvY/wUR3w6hn3kwFjXlZMloVCYNNM5eUP6WVMipL9kvZVuGCB3uEgXzaw== +-----END PUBLIC KEY----- diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa_hash.bin b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa_hash.bin new file mode 100644 index 0000000000000..d785c7578e0cf Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_single_bank/tools/keys/rtk_ecdsa_hash.bin differ diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/md5/MD5 b/samples/bluetooth/rtk_ota_sample_single_bank/tools/md5/MD5 new file mode 100644 index 0000000000000..20ae344f20a9c Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_single_bank/tools/md5/MD5 differ diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/md5/MD5.exe b/samples/bluetooth/rtk_ota_sample_single_bank/tools/md5/MD5.exe new file mode 100644 index 0000000000000..a1ca9039bfb58 Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_single_bank/tools/md5/MD5.exe differ diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/mp.ini b/samples/bluetooth/rtk_ota_sample_single_bank/tools/mp.ini new file mode 100644 index 0000000000000..e54542b891b4c --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/tools/mp.ini @@ -0,0 +1,5 @@ +[MandatoryInfo] +BinID=ID_APP +Version=1.0.1.1 +PartNumber= +DataLength= \ No newline at end of file diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/prepend_header/prepend_header b/samples/bluetooth/rtk_ota_sample_single_bank/tools/prepend_header/prepend_header new file mode 100644 index 0000000000000..86d9916766663 Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_single_bank/tools/prepend_header/prepend_header differ diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/prepend_header/prepend_header.exe b/samples/bluetooth/rtk_ota_sample_single_bank/tools/prepend_header/prepend_header.exe new file mode 100644 index 0000000000000..3ac69c89368b9 Binary files /dev/null and b/samples/bluetooth/rtk_ota_sample_single_bank/tools/prepend_header/prepend_header.exe differ diff --git a/samples/bluetooth/rtk_ota_sample_single_bank/tools/run.bat b/samples/bluetooth/rtk_ota_sample_single_bank/tools/run.bat new file mode 100644 index 0000000000000..8c4bc08b09875 --- /dev/null +++ b/samples/bluetooth/rtk_ota_sample_single_bank/tools/run.bat @@ -0,0 +1,10 @@ +del "zephyr*.bin" +cp ../build/zephyr/zephyr.bin . +@REM Prepend_header: 1. Calculate SHA256/crc by default. +@REM 2. Calculate signature/flash-sec by option. +@REM 3. Add mp header by default. +.\prepend_header\prepend_header.exe -t app_code -b 15 -p "./zephyr.bin" -m 1 -i "./mp.ini" +1>NUL ren zephyr.bin zephyrImage.bin +1>NUL ren zephyr_MP.bin zephyrImage_MP.bin +@REM MD5: Calculate MD5 and add it in the image file name. +.\md5\md5.exe "zephyrImage_MP.bin" \ No newline at end of file diff --git a/soc/arm/realtek_bee/Kconfig b/soc/arm/realtek_bee/Kconfig index 5fe2b918d285d..285587230a63f 100644 --- a/soc/arm/realtek_bee/Kconfig +++ b/soc/arm/realtek_bee/Kconfig @@ -21,5 +21,13 @@ config REALTEK_IMAGE_HEADER default y help This config will prepend realtek_image_header on the zephyr binary. + +config REALTEK_OTA + bool 'support realtek ota' + depends on BT + select WATCHDOG + select REALTEK_USING_SDK_LIB + help + This config will enable realtek's OTA feature. endif # SOC_FAMILY_REALTEK_BEE \ No newline at end of file diff --git a/soc/arm/realtek_bee/Kconfig.defconfig b/soc/arm/realtek_bee/Kconfig.defconfig index 2022f268d3fca..74b2733328e21 100644 --- a/soc/arm/realtek_bee/Kconfig.defconfig +++ b/soc/arm/realtek_bee/Kconfig.defconfig @@ -1,5 +1,10 @@ if SOC_FAMILY_REALTEK_BEE +if REALTEK_OTA +config COMMON_LIBC_MALLOC_ARENA_SIZE + default 8192 +endif + rsource "*/Kconfig.defconfig.series" endif diff --git a/soc/arm/realtek_bee/rtl87x2g/CMakeLists.txt b/soc/arm/realtek_bee/rtl87x2g/CMakeLists.txt index 28009c19f3696..81e81e196ad4c 100644 --- a/soc/arm/realtek_bee/rtl87x2g/CMakeLists.txt +++ b/soc/arm/realtek_bee/rtl87x2g/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory_ifdef(CONFIG_REALTEK_OTA ota_src) + zephyr_compile_definitions(STACK_ROM_ADDRESS=0x36000) zephyr_library_sources(soc.c) diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/CMakeLists.txt b/soc/arm/realtek_bee/rtl87x2g/ota_src/CMakeLists.txt new file mode 100644 index 0000000000000..2e31230ffb4d9 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/CMakeLists.txt @@ -0,0 +1,12 @@ +zephyr_library() +zephyr_compile_definitions(SUPPORT_NORMAL_OTA=0) +zephyr_include_directories(.) + +zephyr_library_sources( + ble_dfu_transport.c + rtk_ota_service.c + rtk_dfu_service.c + dfu_common.c + rtk_ota_app_layer.c + rtk_ota_bt.c +) diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/ble_dfu_transport.c b/soc/arm/realtek_bee/rtl87x2g/ota_src/ble_dfu_transport.c new file mode 100644 index 0000000000000..4bc626b19fa94 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/ble_dfu_transport.c @@ -0,0 +1,1759 @@ +/** +***************************************************************************************** +* Copyright(c) 2023, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file ble_dfu_transport.c + * @brief Source file for using ble dfu transport + * @author Grace + * @date 2023-12-06 + * @version v1.1 + ************************************************************************************** + * @attention + *

© COPYRIGHT 2023 Realtek Semiconductor Corporation

+ ************************************************************************************** + */ + +/*============================================================================* + * Header Files + *============================================================================*/ + +#include +#include +#include "ble_dfu_transport.h" +#include "rtk_dfu_service.h" +#include "dfu_common.h" +#include "os_mem.h" +#include "os_sync.h" +#include "os_timer.h" +#include "fmc_api.h" +#include "fmc_platform.h" +#include "trace.h" +#if (SUPPORT_NORMAL_OTA == 1) +#include "dfu_main.h" +#endif +#include "rtl876x_lib_platform.h" +#include "patch_header_check.h" + +#include +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(ble_dfu_transport); + +/*if enable transfer encrypted air data packet by aes. disable: 0*/ +#define ENABLE_OTA_AES 1 + +/*============================================================================* + * Variables + *============================================================================*/ +static OTA_FUNCTION_STRUCT ota_struct; +static uint8_t temp_image_total_num = 0; + +bool dfu_active_reset_pending = false; +bool dfu_active_reset_to_ota_mode = false; +bool dfu_switch_to_ota_mode_pending = false; + + +/*============================================================================* + * Private Functions + *============================================================================*/ +/** + * @brief get current active bank + * @param void + * @return 0x01:bank0, 0x02:bank1, 0x00:not support bank switch + */ +static uint8_t ble_ota_service_get_active_bank(void) +{ + uint8_t active_bank; + uint32_t ota_bank0_addr; + + if (is_ota_support_bank_switch()) + { + ota_bank0_addr = flash_partition_addr_get(PARTITION_FLASH_OTA_BANK_0); + + if (ota_bank0_addr == get_active_ota_bank_addr()) + { + active_bank = IMAGE_LOCATION_BANK0; + } + else + { + active_bank = IMAGE_LOCATION_BANK1; + } + } + else + { + active_bank = NOT_SUPPORT_BANK_SWITCH; + } + + return active_bank; +} + +static uint8_t ble_ota_service_get_bootpatch_active_bank(void) +{ + uint8_t active_bank; + uint32_t boot_patch0_addr; + + boot_patch0_addr = flash_partition_addr_get(PARTITION_FLASH_BOOT_PATCH0); + + if (boot_patch0_addr == get_header_addr_by_img_id(IMG_BOOTPATCH)) + { + active_bank = IMAGE_LOCATION_BANK0; + } + else + { + active_bank = IMAGE_LOCATION_BANK1; + } + + return active_bank; +} + +static uint8_t ble_ota_service_get_secureapp_active_bank(void) +{ + uint8_t active_bank; + uint32_t secure_app0_addr; + + if (is_ota_support_bank_switch()) + { + secure_app0_addr = flash_partition_addr_get(PARTITION_FLASH_SECURE_APP0); + + if (secure_app0_addr == get_header_addr_by_img_id(IMG_SECUREMCUAPP)) + { + active_bank = IMAGE_LOCATION_BANK0; + } + else + { + active_bank = IMAGE_LOCATION_BANK1; + } + } + else + { + active_bank = NOT_SUPPORT_BANK_SWITCH; + } + + return active_bank; +} + + +/** + * @brief Wrapper function to send notification to peer + * @note + * @param conn ID to identify the connection + * @param opcode Notification on the specified opcode + * @param len Notification data length + * @param data Additional notification data + * @return void + */ +static void ble_dfu_service_prepare_send_notify(struct bt_conn *conn, uint8_t opcode, uint16_t len, + uint8_t *data) +{ + uint8_t *p_buffer = NULL; + uint16_t mtu_size; + uint16_t remain_size = len; + uint8_t *p_data = data; + uint16_t send_len; + + if ((data == NULL) || (len == 0)) + { + return; + } + + //le_get_conn_param(GAP_PARAM_CONN_MTU_SIZE, &mtu_size, conn); + mtu_size = bt_gatt_get_mtu(conn); + + LOG_INF("mtu_size:%d",mtu_size); + + p_buffer = malloc(mtu_size); + + if (p_buffer == NULL) + { + return; + } + + if (len < mtu_size - 2) + { + p_buffer[0] = DFU_OPCODE_NOTIF; + p_buffer[1] = opcode; + memcpy(&p_buffer[2], data, len); + + dfu_service_send_notification(conn, p_buffer, len + 2); + + free(p_buffer); + + return; + } + + while (remain_size) + { + if (remain_size == len) + { + p_buffer[0] = DFU_OPCODE_NOTIF; + p_buffer[1] = opcode; + memcpy(&p_buffer[2], p_data, mtu_size - 2); + dfu_service_send_notification(conn, p_buffer, mtu_size); + + p_data += (mtu_size - 2); + remain_size -= (mtu_size - 2); + continue; + } + + send_len = (remain_size > mtu_size) ? mtu_size : remain_size; + memcpy(p_buffer, p_data, send_len); + dfu_service_send_notification(conn, p_buffer, send_len); + + p_data += send_len; + remain_size -= send_len; + } + + free(p_buffer); +} + +/** + * @brief check section size before ota + * @param void + * @return true: check success; false: check fail + */ +static bool dfu_check_section_size(void) +{ + uint32_t section_size = dfu_get_temp_ota_bank_img_size_by_img_id((IMG_ID)ota_struct.image_id); + + if (ota_struct.image_total_length > section_size) + { + LOG_ERR("dfu_check_section_size: total size 0x%x, section size 0x%x", + ota_struct.image_total_length, section_size); + return false; + } + + return true; +} + +/** + * @brief Reset local variables + * @return void + */ +static void ble_dfu_clear_local(T_OTA_CLEAR_LOCAL_CAUSE cause) +{ + APP_PRINT_TRACE1("app_ota_clear_local cause: %d", cause); + temp_image_total_num = 0; + ota_struct.image_total_length = 0; + ota_struct.image_id = 0; + ota_struct.cur_offset = 0; + ota_struct.next_subimage_offset = 0; + ota_struct.ota_flag.value = 0; + ota_struct.ota_temp_buf_used_size = 0; + if (cause) + { + ota_struct.test.value = 0; + } + + memset(ota_struct.bd_addr, 0, sizeof(ota_struct.bd_addr)); + if (ota_struct.force_temp_mode) + { + //force_enable_ota_temp(false); + ota_struct.force_temp_mode = 0; + } + + if (ota_struct.p_ota_temp_buf_head != NULL) + { + free(ota_struct.p_ota_temp_buf_head); + ota_struct.p_ota_temp_buf_head = NULL; + ota_struct.buffer_size = 0; + } + + if (ota_struct.bp_level) + { + uint32_t s; + s = os_lock(); + fmc_flash_nor_set_bp_lv(FMC_MAIN0_ADDR, ota_struct.bp_level); + os_unlock(s); + ota_struct.bp_level = 0; + } +} + +/** + * @brief timeout callback for ota + * @param timer_id timer id + * @param timer_chann time channel + * @return void + */ +static void ble_dfu_timeout_cb(void *p_xtimer) +{ + uint32_t timer_id = 0; + + os_timer_id_get(&p_xtimer, &timer_id); + LOG_INF("ble_dfu_timeout_cb: timer id 0x%02X", timer_id); + + switch (timer_id) + { + case TIMER_ID_DFU_IMAGE_TRANS: + { + os_timer_stop(&ota_struct.timer_handle_ota_transfer); + ble_dfu_clear_local(OTA_IMAGE_TRANS_TIMEOUT); + } + break; + default: + break; + } +} + +static bool dfu_get_enc_setting(void) +{ + if (ENABLE_OTA_AES) + { + return true; + } + else + { + return false; + } + +} + +/** + * @brief Handle the start dfu control point + * @param p_data data to be written + * @return handle result 0x01:success other:fail + */ +static uint8_t ble_dfu_cp_start_dfu_handle(uint8_t *p_data) //0x01 +{ + uint8_t results = DFU_ARV_SUCCESS; + + if (p_data == NULL) + { + results = DFU_ARV_FAIL_INVALID_PARAMETER; + return results; + } + + if (dfu_get_enc_setting()) + { + //LOG_INF("start dfu before decrypted: %b", TRACE_BINARY(16, p_data)); + LOG_HEXDUMP_INF(p_data, 16, "start dfu before decrypted:"); + dfu_aes256_decrypt_16byte(p_data); + //LOG_INF("start dfu after decrypted: %b", TRACE_BINARY(16, p_data)); + LOG_HEXDUMP_INF(p_data, 16, "start dfu after decrypted:"); + } + + T_IMG_CTRL_HEADER_FORMAT *start_dfu_para = (T_IMG_CTRL_HEADER_FORMAT *)p_data; + ota_struct.force_temp_mode = *(uint8_t *)((T_IMG_CTRL_HEADER_FORMAT *)p_data + 1); + ota_struct.image_total_length = start_dfu_para->payload_len + DEFAULT_HEADER_SIZE; + ota_struct.image_id = start_dfu_para->image_id; + LOG_INF("ble_dfu_cp_start_dfu_handle: force_temp_mode=0x%x", ota_struct.force_temp_mode); + /* zephyr build not work ,todo */ + LOG_INF("ble_dfu_cp_start_dfu_handle: ic_type=0x%x, CtrlFlag=0x%x, img_id=0x%x ,CRC16=0x%x, Total Length=0x%x", + start_dfu_para->ic_type, + start_dfu_para->ctrl_flag.value, + start_dfu_para->image_id, + start_dfu_para->crc16, + ota_struct.image_total_length + ); + + if (dfu_check_section_size() == false) + { + LOG_INF("ble_dfu_cp_start_dfu_handle: Image is oversize"); + results = DFU_ARV_FAIL_INVALID_PARAMETER; + return results; + } + + if (ota_struct.force_temp_mode) + { + //force_enable_ota_temp(true); + } + + if ((!is_ota_support_bank_switch() && ota_struct.image_id == IMG_OTA) + || ota_struct.image_id < IMG_DFU_FIRST + || ((ota_struct.image_id >= IMG_DFU_MAX) && + (ota_struct.image_id < IMG_USER_DATA_FIRST))) + { + results = DFU_ARV_FAIL_INVALID_PARAMETER; + return results; + } + +#if (SUPPORT_BL_COPY_SECURE_IMAGE == 1) + if (is_ota_support_bank_switch()) + { + if ((ota_struct.image_id >= IMG_BANK_FIRST && ota_struct.image_id < IMG_DFU_MAX) || + ota_struct.image_id == IMG_OTA) + { + /*only the images located in OTA Bank need set to 0 when dual bank*/ + ota_struct.next_subimage_offset = 0; + } + else + { + /*restore next image offset*/ + ota_struct.next_subimage_offset = ota_struct.tmp_next_subimage_offset; + } + } +#else + if (is_ota_support_bank_switch()) + { + ota_struct.next_subimage_offset = 0; + } + else + { + if (ota_struct.image_id == IMG_BOOTPATCH || + (ota_struct.image_id >= IMG_USER_DATA_FIRST && ota_struct.image_id < IMG_USER_DATA_MAX)) + { + /*bootpatch always dual bank*/ + ota_struct.next_subimage_offset = 0; + } + else + { + /*restore next image offset*/ + ota_struct.next_subimage_offset = ota_struct.tmp_next_subimage_offset; + } + } +#endif + + ota_struct.ota_flag.is_ota_process = true; + ota_struct.ota_temp_buf_used_size = 0; + ota_struct.cur_offset = 0; +#if (SUPPORT_NORMAL_OTA == 1) + if (is_normal_ota_mode) + { + uint32_t restart_ms = (ota_struct.image_total_length + 0x19000 - 1) / 0x19000 * + NORMAL_OTA_TIMEOUT_TOTAL * 1000; + os_timer_restart(&normal_ota_total_timer_handle, restart_ms); + LOG_INF("ble_dfu_cp_start_dfu_handle: restart total timer %d ms", restart_ms); + } +#endif + + uint32_t s; + s = os_lock(); + fmc_flash_nor_set_bp_lv(FMC_MAIN0_ADDR, 0); + os_unlock(s); + + return results; +} + +/** + * @brief Valid the image + * @param p_date point of input data + * @return valid result + */ +static uint8_t ble_dfu_cp_valid_handle(uint8_t *p_data) //0x03 +{ + uint8_t results = DFU_ARV_SUCCESS; + uint16_t image_id; + + if (!ota_struct.ota_flag.skip_flag + && ota_struct.test.t_skip_fail) + { + ota_struct.test.t_skip_fail = 0; + results = DFU_ARV_FAIL_CRC_ERROR; + return results; + } + + ota_struct.ota_flag.skip_flag = 0; + + if (p_data == NULL) + { + results = DFU_ARV_FAIL_INVALID_PARAMETER; + return results; + } + + LE_ARRAY_TO_UINT16(image_id, p_data); + LE_ARRAY_TO_UINT8(ota_struct.is_last_image, p_data + 2); + LOG_INF("==>ble_dfu_cp_valid_handle: img_id=0x%x, ota_struct.image_id=0x%x, is_last_image=%d", + image_id, ota_struct.image_id, ota_struct.is_last_image); + + if (image_id == ota_struct.image_id) + { + if (!dfu_checksum((IMG_ID)image_id, ota_struct.next_subimage_offset)) + { + results = DFU_ARV_FAIL_CRC_ERROR; + } + else + { + //user data image needn't record into temp info + if (ota_struct.image_id >= IMG_DFU_FIRST && ota_struct.image_id < IMG_DFU_MAX) + { + bool bank_switch = is_ota_support_bank_switch(); +#if (SUPPORT_BL_COPY_SECURE_IMAGE == 1) + bool is_ota_bank_image = (ota_struct.image_id == IMG_OTA) || + (ota_struct.image_id >= IMG_BANK_FIRST && ota_struct.image_id < IMG_DFU_MAX); + if ((bank_switch && !is_ota_bank_image) + || !bank_switch) +#else + if (!bank_switch && ota_struct.image_id != IMG_BOOTPATCH) +#endif + { + ota_struct.tmp_next_subimage_offset += ota_struct.cur_offset; + ota_struct.next_subimage_offset = ota_struct.tmp_next_subimage_offset; + + ota_struct.temp_image_info[temp_image_total_num].image_offset = + ota_struct.next_subimage_offset - ota_struct.image_total_length; + + LOG_INF("==>ble_dfu_cp_valid_handle:temp info idx %d, image_id 0x%x, image_offset 0x%x in temp bank", + temp_image_total_num, ota_struct.image_id, + ota_struct.temp_image_info[temp_image_total_num].image_offset); + temp_image_total_num ++; + } + + ota_struct.cur_offset = 0; + /* set updated images valid */ + SET_VALID_BITMAP(image_id); + + LOG_INF("==>ble_dfu_cp_valid_handle: valid_bitmap= 0x%x", valid_bitmap); + } + + if (ota_struct.image_id >= IMG_USER_DATA_FIRST && ota_struct.image_id < IMG_USER_DATA_MAX) + { + SET_USER_DATA_VALID_BITMAP(image_id); + } + + LOG_INF("==>ble_dfu_cp_valid_handle: checksum Success! temp bank next_subimage_offset= 0x%x", + ota_struct.next_subimage_offset); + } + } + else + { + results = DFU_ARV_FAIL_INVALID_PARAMETER; + } + + return results; +} + +static void ble_dfu_bootpatch_always_bank_switch(void) +{ + if (ota_struct.test.t_stress_test && GET_VALID_BITMAP(IMG_BOOTPATCH)) + { + LOG_INF("<==ble_dfu_bootpatch_always_bank_switch"); + uint32_t image_addr = get_header_addr_by_img_id(IMG_BOOTPATCH); + fmc_flash_nor_erase(image_addr, FMC_FLASH_NOR_ERASE_SECTOR); + } +} + +static void dfu_set_ota_temp_image_ready(void) +{ + uint32_t base_addr = 0; + T_IMG_HEADER_FORMAT *p_header = NULL; + base_addr = flash_partition_addr_get(PARTITION_FLASH_OTA_TMP); + + LOG_INF("<==dfu_set_ota_temp_image_ready: ota_temp_addr =0x%x, temp_image_total_num %d", + base_addr, temp_image_total_num); + + for (int i = temp_image_total_num - 1; i >= 0; i--) + { + p_header = (T_IMG_HEADER_FORMAT *)(base_addr + ota_struct.temp_image_info[i].image_offset); + if (p_header) + { + dfu_set_ready(p_header); + } + } +} + +static void ble_dfu_cp_active_reset_handle(struct bt_conn *conn, bool is_enter_dfu_mode) +{ + T_IMG_HEADER_FORMAT *p_header = NULL; + uint16_t img_id = IMG_DFU_MAX; + + if (!is_ota_support_bank_switch()) + { + dfu_set_ota_temp_image_ready(); + +#if (SUPPORT_BL_COPY_SECURE_IMAGE == 0) + img_id = IMG_BOOTPATCH; + if (GET_VALID_BITMAP(img_id)) + { + p_header = (T_IMG_HEADER_FORMAT *)dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)img_id); + if (p_header) + { + dfu_set_ready(p_header); + } + } +#endif + } + else + { +#if (SUPPORT_BL_COPY_SECURE_IMAGE == 1) + /* support bank switch */ + img_id = IMG_DFU_MAX - 1; + + for (; img_id >= IMG_BANK_FIRST; img_id--) + { + if (GET_VALID_BITMAP(img_id)) + { + p_header = (T_IMG_HEADER_FORMAT *)dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)img_id); + if (p_header) + { + dfu_set_ready(p_header); + } + } + } + + img_id = IMG_OTA; + if (GET_VALID_BITMAP(img_id)) + { + p_header = (T_IMG_HEADER_FORMAT *)dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)img_id); + if (p_header) + { + dfu_set_ready(p_header); + } + } + + dfu_set_ota_temp_image_ready(); +#else + /* support bank switch */ + img_id = IMG_DFU_MAX - 1; + + /*include boot patch and secure app or data*/ + for (; img_id >= IMG_DFU_FIRST; img_id--) + { + if (GET_VALID_BITMAP(img_id)) + { + p_header = (T_IMG_HEADER_FORMAT *)dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)img_id); + if (p_header) + { + dfu_set_ready(p_header); + } + } + } +#endif + } + + /*set user data image ready*/ + img_id = IMG_USER_DATA_FIRST; + for (; img_id < IMG_USER_DATA_MAX; img_id++) + { + if (GET_USER_DATA_VALID_BITMAP(img_id)) + { + p_header = (T_IMG_HEADER_FORMAT *)dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)img_id); + if (p_header) + { + dfu_set_ready(p_header); + } + } + } + +#if (SUPPORT_NORMAL_OTA == 1) + LOG_INF("==>ble_dfu_cp_active_reset_handle: is_enter_dfu_mode=%d, is_normal_ota_mode=%d", + is_enter_dfu_mode, is_normal_ota_mode); + if (is_enter_dfu_mode && is_normal_ota_mode) + { + //need reset to ota mode + dfu_active_reset_to_ota_mode = true; + } +#endif + + ble_dfu_bootpatch_always_bank_switch(); + + //le_disconnect(conn); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + dfu_active_reset_pending = true; + + ble_dfu_clear_local(OTA_SUCCESS_REBOOT); + +} + +/** + * @brief get image info for ota + * @param *p_data point of input data + * @param *data point of output data + * @return void + */ +static void ble_dfu_cp_report_img_info_handle(uint8_t *p_data, uint8_t *p_notify_data) //0x06 +{ + uint16_t image_id; + uint32_t dfu_base_addr; + uint32_t s; + + if ((p_notify_data == NULL) || (p_data == NULL)) + { + return; + } + + LE_ARRAY_TO_UINT16(image_id, p_data); + LOG_INF("ble_dfu_cp_report_img_info_handle: received img_id 0x%x, ota_struct.image_id=0x%x", + image_id, ota_struct.image_id); + + if (image_id != ota_struct.image_id) + { + ota_struct.cur_offset = 0; + ota_struct.ota_temp_buf_used_size = 0; + ota_struct.image_id = image_id; + } + + if (image_id < IMG_DFU_FIRST || + ((image_id >= IMG_DFU_MAX) && (image_id < IMG_USER_DATA_FIRST))) + { + LOG_ERR("ble_dfu_cp_report_img_info_handle: received img_id 0x%x invalid!", image_id); + + p_notify_data[0] = DFU_ARV_FAIL_INVALID_PARAMETER; + return; + } + + dfu_base_addr = dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)image_id); + if ((dfu_base_addr % FLASH_SECTOR_SIZE) == 0) + { + ota_struct.buffer_check_offset = 0; + } + else + { + ota_struct.buffer_check_offset = dfu_base_addr % FLASH_SECTOR_SIZE; + s = os_lock(); + fmc_flash_nor_read(dfu_base_addr - ota_struct.buffer_check_offset, + ota_struct.p_ota_temp_buf_head, + ota_struct.buffer_check_offset); + os_unlock(s); + } + + p_notify_data[0] = DFU_ARV_SUCCESS; + LE_UINT32_TO_ARRAY(&p_notify_data[1], 0); + LE_UINT32_TO_ARRAY(&p_notify_data[5], ota_struct.cur_offset); + LE_UINT16_TO_ARRAY(&p_notify_data[9], ota_struct.buffer_check_offset); + + LOG_INF("ble_dfu_cp_report_img_info_handle: Notify cur_offset=0x%x, buffer_check_offset=0x%x", + ota_struct.cur_offset, ota_struct.buffer_check_offset); +} + + +static void ble_dfu_cp_conn_para_update_handle(struct bt_conn *conn, uint8_t *p_data, uint8_t *p_notify_data) //0x06 +{ + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t superv_tout; + + if ((p_notify_data == NULL) || (p_data == NULL)) + { + return; + } + + p_notify_data[0] = DFU_ARV_SUCCESS; + + LE_ARRAY_TO_UINT16(conn_interval_min, p_data); + LE_ARRAY_TO_UINT16(conn_interval_max, p_data + 2); + LE_ARRAY_TO_UINT16(conn_latency, p_data + 4); + LE_ARRAY_TO_UINT16(superv_tout, p_data + 6); + LOG_INF("==>le_dfu_cp_conn_para_update_handle: conn_min=0x%x, conn_max=0x%x, latcy=0x%x, timeout=0x%x", + conn_interval_min, conn_interval_max, conn_latency, superv_tout); + + + if (ota_struct.dfu_conn_para_update_in_progress) + { + p_notify_data[0] = DFU_ARV_FAIL_OPERATION; + LOG_INF("==>le_dfu_cp_conn_para_update_handle: OTA ConnParaUpdInProgress!"); + } + else + { + /* Change to zephyr host API. Note!!! Zephyr doesnot have min_ce_length & max_ce_length */ + struct bt_le_conn_param param; + param.interval_max = conn_interval_max; + param.interval_min = conn_interval_min; + param.latency = conn_latency; + param.timeout = superv_tout; + + if (bt_conn_le_param_update(conn, ¶m) == 0) { + /* Connection Parameter Update Request sent successfully, means this procedure is in progress. */ + ota_struct.dfu_conn_para_update_in_progress = true; + LOG_INF("==>le_dfu_cp_conn_para_update_handle: updating"); + } else { + p_notify_data[0] = DFU_ARV_FAIL_OPERATION; + return; + } + } + LOG_INF("ble_dfu_cp_report_img_info_handle: cur_offset=0x%x, buffer_check_offset=0x%x", + ota_struct.cur_offset, ota_struct.buffer_check_offset); +} +/** + * @brief Handle buffer check enable cmd + * @param p_data point of output data + * @param max_buffer_size set max buffer size + * @return void + */ +static void ble_dfu_cp_buffer_check_en_handle(uint8_t *p_notify_data, + uint16_t max_buffer_size) //0x09 +{ + uint8_t size_factor = 0; + + if (p_notify_data == NULL) + { + return; + } + + ota_struct.ota_flag.buffer_check_en = true; + + while (ota_struct.p_ota_temp_buf_head == NULL) + { + ota_struct.buffer_size = max_buffer_size >> size_factor; + ota_struct.p_ota_temp_buf_head = (uint8_t *)malloc(ota_struct.buffer_size); + //ota_struct.p_ota_temp_buf_head = (uint8_t *)os_mem_alloc(0, ota_struct.buffer_size); + size_factor ++; + if (ota_struct.buffer_size <= 0) + { + break; + } + } + + if (ota_struct.p_ota_temp_buf_head == NULL + || ota_struct.buffer_size == 0) + { + ota_struct.ota_flag.buffer_check_en = false; + } + p_notify_data[0] = ota_struct.ota_flag.buffer_check_en; + LE_UINT16_TO_ARRAY(&p_notify_data[1], ota_struct.buffer_size); + //LE_UINT16_TO_ARRAY(&p_notify_data[3], ota_struct.mtu_size); //ota verion =4, is rsvd val + + LOG_INF("ble_dfu_cp_buffer_check_en: buffer_check_en=%d, buffer_size=%d", + ota_struct.ota_flag.buffer_check_en, ota_struct.buffer_size); +} + +/** + * @brief Handle written request on DFU packet + * @param p_data point of input data + * @param data point of output data + * @return void + */ +static void ble_dfu_cp_buffer_check_handle(uint8_t *p_data, uint8_t *data) //0x0a +{ + uint16_t data_size; + uint16_t crc; + + T_DFU_CALLBACK_DATA callback_data; + //callback_data.conn_id = conn_id; + callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE; + callback_data.msg_data.write.write_attrib_index = INDEX_DFU_CHAR_DFU_CONTROL_POINT_INDEX; + + if ((p_data == NULL) || (ota_struct.ota_flag.is_ota_process == false)) + { + ota_struct.ota_temp_buf_used_size = 0; + data[0] = DFU_ARV_FAIL_OPERATION; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + return; + } + + LE_ARRAY_TO_UINT16(data_size, p_data); + LE_ARRAY_TO_UINT16(crc, p_data + 2); + + LOG_INF("===>ble_dfu_cp_buffer_check_handle: data_size=%d, crc=0x%x, ota_temp_buf_used_size=%d, buffer_check_offset=%d", + data_size, crc, ota_struct.ota_temp_buf_used_size, ota_struct.buffer_check_offset); + + if (data_size != ota_struct.ota_temp_buf_used_size) + { + ota_struct.ota_temp_buf_used_size = 0; + data[0] = DFU_ARV_FAIL_DATA_LENGTH_ERROR; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + return; + } + + if (dfu_check_bufcrc(ota_struct.p_ota_temp_buf_head + ota_struct.buffer_check_offset, + ota_struct.ota_temp_buf_used_size, crc)) + { + ota_struct.ota_temp_buf_used_size = 0; + ota_struct.buffer_check_offset = 0; + data[0] = DFU_ARV_FAIL_CRC_ERROR; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + LOG_INF("ble_dfu_cp_buffer_check_handle: buffer check fail!"); + } + else + { + LOG_INF("ble_dfu_cp_buffer_check_handle: write flash, offset=0x%x", ota_struct.cur_offset); + if (dfu_get_enc_setting()) + { + uint16_t offset = 0; + while ((ota_struct.ota_temp_buf_used_size - offset) >= 16) + { + dfu_aes256_decrypt_16byte(ota_struct.p_ota_temp_buf_head + offset); + offset += 16; + } + } + + uint32_t flash_write_result = dfu_write_data_to_flash(ota_struct.image_id, + ota_struct.cur_offset, + ota_struct.next_subimage_offset, + ota_struct.ota_temp_buf_used_size + ota_struct.buffer_check_offset, + ota_struct.p_ota_temp_buf_head); + + LOG_INF("ble_dfu_cp_buffer_check_handle: write ret %d", flash_write_result); + + if (flash_write_result == 0) + { + uint32_t updated_success_len = ota_struct.ota_temp_buf_used_size; + callback_data.msg_data.write.opcode = DFU_WRITE_DOING; + callback_data.msg_data.write.length = 4; + callback_data.msg_data.write.p_value = (uint8_t *)&updated_success_len; + + T_APP_RESULT cause = app_dfu_srv_cb((void *)&callback_data); + + if (cause != APP_RESULT_SUCCESS) + { + return; + } + + ota_struct.cur_offset += ota_struct.ota_temp_buf_used_size; + ota_struct.ota_temp_buf_used_size = 0; + ota_struct.buffer_check_offset = 0; + data[0] = DFU_ARV_SUCCESS; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + } + else + { + uint32_t erase_time = 0; + uint32_t resend_offset = (ota_struct.next_subimage_offset + ota_struct.cur_offset) / + FLASH_SECTOR_SIZE * FLASH_SECTOR_SIZE; + + if (resend_offset < ota_struct.next_subimage_offset) + { + ota_struct.ota_temp_buf_used_size = 0; + data[0] = DFU_ARV_FAIL_FLASH_ERASE_ERROR; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + return; + } + + ota_struct.cur_offset = resend_offset - ota_struct.next_subimage_offset; + LOG_INF("ble_dfu_cp_buffer_check_handle: write fail! cur_offset=0x%x, resend_offset=0x%x, next_subimage_offset=0x%x", + ota_struct.cur_offset, resend_offset, ota_struct.next_subimage_offset); + + while (erase_time < 3) + { + if (dfu_flash_erase((IMG_ID)ota_struct.image_id, resend_offset) == true) + { + ota_struct.ota_temp_buf_used_size = 0; + data[0] = DFU_ARV_FAIL_FLASH_WRITE_ERROR; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + break; + } + else + { + erase_time++; + } + } + if (erase_time >= 3) + { + ota_struct.ota_temp_buf_used_size = 0; + data[0] = DFU_ARV_FAIL_FLASH_ERASE_ERROR; + LE_UINT32_TO_ARRAY(&data[1], ota_struct.cur_offset); + LOG_INF("ble_dfu_cp_buffer_check_handle: erase fail more than three times!"); + + T_DFU_FAIL_REASON dfu_fail_reason = DFU_FAIL_UPDATE_FLASH; + callback_data.msg_data.write.opcode = DFU_WRITE_FAIL; + callback_data.msg_data.write.length = sizeof(T_DFU_FAIL_REASON); + callback_data.msg_data.write.p_value = (uint8_t *)&dfu_fail_reason; + + T_APP_RESULT cause = app_dfu_srv_cb((void *)&callback_data); + + if (cause != APP_RESULT_SUCCESS) { + return; + } + + } + } + } +} + +/** + * @brief copy image to the other bank + * @param p_data point of input data + * @return 1: success other: fail + */ +static uint8_t ble_dfu_cp_copy_img_handle(uint8_t *p_data) //0x0c +{ + uint32_t source_base_addr; + T_IMG_CTRL_HEADER_FORMAT ctrl_header; + uint32_t offset = 0; + uint8_t ret = DFU_ARV_SUCCESS; + uint16_t img_id; + uint8_t *buffer_addr = ota_struct.p_ota_temp_buf_head; + uint32_t buffer_size = MAX_BUFFER_SIZE; + uint8_t *p_copy_buffer = NULL; + uint8_t bp_lv; + uint8_t size_factor = 0; + uint32_t s; + + ota_struct.ota_flag.skip_flag = 1; + + if (ota_struct.test.t_copy_fail) + { + ota_struct.test.t_copy_fail = 0; + ret = DFU_ARV_FAIL_OPERATION; + return ret; + } + + if (p_data == NULL) + { + ret = DFU_ARV_FAIL_OPERATION; + return ret; + } + + LE_ARRAY_TO_UINT16(img_id, p_data); + + if ((img_id < IMG_MCUAPPDATA1) || (img_id >= IMG_DFU_MAX)) + { + ret = DFU_ARV_FAIL_INVALID_PARAMETER; + return ret; + } + + source_base_addr = get_header_addr_by_img_id((IMG_ID)img_id); + + if ((source_base_addr % FLASH_SECTOR_SIZE) || (source_base_addr == 0)) + { + ret = DFU_ARV_FAIL_OPERATION; + return ret; + } + + T_IMG_HEADER_FORMAT *p_data_header = (T_IMG_HEADER_FORMAT *)source_base_addr; + s = os_lock(); + fmc_flash_nor_read((uint32_t)&p_data_header->ctrl_header, &ctrl_header, sizeof(ctrl_header)); + os_unlock(s); + if (ctrl_header.image_id != img_id) + { + ret = DFU_ARV_FAIL_OPERATION; + return ret; + } + + uint32_t remain_size = ctrl_header.payload_len + DEFAULT_HEADER_SIZE; + + if (ota_struct.p_ota_temp_buf_head != NULL) + { + buffer_size = ota_struct.buffer_size; + } + else + { + while (p_copy_buffer == NULL && buffer_size) + { + buffer_size >>= size_factor; + p_copy_buffer = (uint8_t *)malloc(buffer_size); + size_factor ++; + } + + buffer_addr = p_copy_buffer; + } + + if (buffer_addr == NULL) + { + ret = DFU_ARV_FAIL_OPERATION; + return ret; + } + + s = os_lock(); + fmc_flash_nor_get_bp_lv(FMC_MAIN0_ADDR, &bp_lv); //use dest addr is more actually + os_unlock(s); + + uint32_t copy_len; + while (remain_size > 0) + { + copy_len = (remain_size > buffer_size) ? buffer_size : remain_size; + + s = os_lock(); + fmc_flash_nor_read(source_base_addr + offset, buffer_addr, copy_len); + os_unlock(s); + if (dfu_write_data_to_flash(img_id, offset, 0, copy_len, buffer_addr) != 0) //check grace + { + ret = DFU_ARV_FAIL_FLASH_WRITE_ERROR; + return ret; + } + remain_size -= copy_len; + offset += copy_len; + } + + if (dfu_checksum((IMG_ID)img_id, 0) == false) + { + ret = DFU_ARV_FAIL_CRC_ERROR; + } + + if (p_copy_buffer != NULL) + { + free(p_copy_buffer); + } + + s = os_lock(); + fmc_flash_nor_set_bp_lv(FMC_MAIN0_ADDR, bp_lv); + os_unlock(s); + + LOG_INF("ble_dfu_cp_copy_img_handle: ret=%d image_id=0x%x", ret, img_id); + + return ret; +} + +/** + * @brief compare sha256 or crc value with the image in dest addr + * @param p_dest address of the image + * @param p_data sha256 or crc value receive from controler + * @param img_id image id + * @return true: same false: different + */ +static bool ble_dfu_cmp_checksum(uint8_t *p_dest, uint8_t *p_data, IMG_ID img_id) +{ + uint8_t buffer[SHA256_LEN]; + uint32_t offset = SHA256_OFFSET; + uint32_t len = SHA256_LEN; + uint32_t s; + + if (img_id >= IMG_DFU_MAX || img_id < IMG_DFU_FIRST) + { + return false; + } + + s = os_lock(); + fmc_flash_nor_read((uint32_t)(p_dest + offset), buffer, len); + os_unlock(s); + + return (memcmp(p_data, buffer, len) == 0); +} + +/** + * @brief To check if the image in device is same with image needed to update + * @param p_data point of input data + * @param data point of output data + * @return void + */ +static void ble_dfu_cp_check_sha256_handle(uint8_t *p_data, uint8_t *p_notify_data) //0x0f +{ + T_IMG_HEADER_FORMAT *img_addr[2]; + uint16_t num = *(uint16_t *)p_data; + uint8_t buffer[DFU_NOTIFY_LEN_CHECK_SHA256] = {0}; + + if (p_notify_data == NULL) + { + return; + } + + SHA256_CHECK *p_src = (SHA256_CHECK *)(p_data + 2); + LOG_INF("===>ble_dfu_cp_check_sha256_handle: img_id=0x%x", p_src->img_id); + + if (p_src->img_id >= IMG_DFU_MAX || p_src->img_id < IMG_DFU_FIRST) + { + return; + } + + for (uint16_t i = 0; i < num; i++) + { + memset(buffer, 0, sizeof(buffer)); + *(uint16_t *)buffer = p_src->img_id; + + img_addr[0] = (T_IMG_HEADER_FORMAT *)dfu_get_temp_ota_bank_img_addr_by_img_id(p_src->img_id); + img_addr[1] = (T_IMG_HEADER_FORMAT *)get_header_addr_by_img_id(p_src->img_id); + + for (uint8_t j = 0; j < 2; j++) + { + if (img_addr[j] && img_addr[j]->ctrl_header.image_id == p_src->img_id + && ble_dfu_cmp_checksum((uint8_t *)img_addr[j], p_src->sha256, p_src->img_id)) + { + buffer[2] += (j + 1); + } + } + LOG_INF("<===ble_dfu_cp_check_sha256_handle: img_id=0x%x, check resut=%x", + *(uint16_t *)buffer, buffer[2]); + + memcpy(p_notify_data, buffer, sizeof(buffer)); + p_notify_data += sizeof(buffer); + p_src++; + } +} + +/** + * @brief Handle written request on DFU packet + * @param p_data data to be written + * @param length Length of value to be written + * @return handle result 0x01:success other:fail + */ +static uint8_t ble_dfu_packet_handle(uint8_t *p_data, uint16_t length) +{ + uint8_t results = DFU_ARV_SUCCESS; + + LOG_INF("===>ble_dfu_packet_handle: length=%d, nCurOffSet=%d, buffer_check_offset=%d, nImageTotalLength=%d", + length, ota_struct.cur_offset, ota_struct.buffer_check_offset, ota_struct.image_total_length); + + ota_struct.ota_flag.skip_flag = 1; + + if ((p_data == NULL) || (ota_struct.ota_flag.is_ota_process == false)) + { + results = DFU_ARV_FAIL_OPERATION; + return results; + } + + if (ota_struct.cur_offset + length + ota_struct.ota_temp_buf_used_size > + ota_struct.image_total_length) + { + results = DFU_ARV_FAIL_INVALID_PARAMETER; + } + else + { + if (!ota_struct.ota_flag.buffer_check_en) + { + if (dfu_get_enc_setting()) + { + uint16_t offset = 0; + while ((length - offset) >= 16) + { + dfu_aes256_decrypt_16byte(p_data + offset); + offset += 16; + } + } + + if (dfu_write_data_to_flash(ota_struct.image_id, + ota_struct.cur_offset, + ota_struct.next_subimage_offset, + length, + p_data) != 0) + { + results = DFU_ARV_FAIL_OPERATION; + } + else + { + ota_struct.cur_offset += length; + } + } + else + { + LOG_INF("===>ble_dfu_packet_handle: bufcheck Enable! ota_temp_buf_used_size=0x%x, buffer_size=0x%x", + ota_struct.ota_temp_buf_used_size, ota_struct.buffer_size); + if (ota_struct.ota_temp_buf_used_size + ota_struct.buffer_check_offset + length <= + ota_struct.buffer_size) + { + memcpy(ota_struct.p_ota_temp_buf_head + ota_struct.buffer_check_offset + + ota_struct.ota_temp_buf_used_size, p_data, length); + ota_struct.ota_temp_buf_used_size += length; + } + else + { + results = DFU_ARV_FAIL_OPERATION; + } + } + } + + return results; +} + +/*============================================================================* + * Public Functions + *============================================================================*/ +/** + * @brief Used to get device information + * @param p_data point of device info data + * @param ota_mode spp ota or ble ota + * @return void + */ +void ble_dfu_get_device_info(struct bt_conn *conn, DEVICE_INFO *p_deviceinfo) +{ + if (p_deviceinfo == NULL) + { + return; + } + + memset(p_deviceinfo, 0, sizeof(DEVICE_INFO)); + p_deviceinfo->ic_type = dfu_get_ic_type(); + p_deviceinfo->spec_ver = BLE_OTA_VERSION; + + p_deviceinfo->mode.buffercheck_en = 1; //ota_struct.test.t_buffercheck_disable ? 0 : 1; + p_deviceinfo->mode.aes_en = dfu_get_enc_setting(); + p_deviceinfo->mode.aes_mode = 1; + p_deviceinfo->mode.support_multiimage = 1; + p_deviceinfo->mode.is_support_normal_ota = SUPPORT_NORMAL_OTA; //means support normal ota + p_deviceinfo->mode.is_ota_support_dual_bank_merge = is_ota_support_dual_bank_merge(); + p_deviceinfo->ota_temp_size = flash_partition_size_get(PARTITION_FLASH_OTA_TMP) / + FLASH_SECTOR_SIZE; //uint 4KB + p_deviceinfo->active_banknum = ble_ota_service_get_active_bank(); + p_deviceinfo->bootpatch_active_banknum = ble_ota_service_get_bootpatch_active_bank(); + p_deviceinfo->secureapp_active_banknum = ble_ota_service_get_secureapp_active_bank(); + p_deviceinfo->ctrl_header_offset = MEMBER_OFFSET(T_IMG_HEADER_FORMAT, ctrl_header); + + // le_get_conn_param(GAP_PARAM_CONN_MTU_SIZE, &ota_struct.mtu_size, conn);//RTK UPPERSTACK VERSION + ota_struct.mtu_size = bt_gatt_get_mtu(conn);//ZEPHYR host VERSION + + ota_struct.ota_flag.is_devinfo = 1; + ota_struct.ota_flag.is_support_mutil_image = p_deviceinfo->mode.support_multiimage; + + uint32_t s; + s = os_lock(); + fmc_flash_nor_get_bp_lv(FMC_MAIN0_ADDR, &ota_struct.bp_level); + os_unlock(s); + LOG_INF("<===ble_dfu_get_device_info: aes_en=%d,bufcheck_en=%d, active_banknum(OTA BANK%d,BOOTPATCH%d,SECUREAPP%d)", + p_deviceinfo->mode.aes_en, p_deviceinfo->mode.buffercheck_en, + p_deviceinfo->active_banknum, p_deviceinfo->bootpatch_active_banknum, + p_deviceinfo->secureapp_active_banknum); + LOG_INF("p_deviceinfo->mode.is_ota_support_dual_bank_merge %d", + p_deviceinfo->mode.is_ota_support_dual_bank_merge); + LOG_INF("<===ble_dfu_get_device_info: ota_temp_size=%d,mtu_size=%d,bp_lv=%d", + p_deviceinfo->ota_temp_size, ota_struct.mtu_size, ota_struct.bp_level); +} + +/** + * @brief Used to get image version + * @param *p_data point of image version + * @param bank 0:active bank 1:inactive bank + * @return void + */ +void ble_dfu_get_img_version(uint8_t *p_data, uint8_t bank) +{ + uint8_t num = 0; + IMG_ID img_id; + uint8_t buffer[6] = {0}; + uint8_t *p_temp = p_data + 1; + uint32_t addr = 0; + uint32_t size = 0; + T_IMAGE_VERSION image_version; + + //is_ota_support_bank_switch() + for (img_id = IMG_DFU_FIRST; img_id < IMG_DFU_MAX; img_id++) + { + if (bank == ACTIVE_BANK) + { + size = get_active_bank_image_size_by_img_id(img_id); + get_ota_bank_image_version(true, img_id, (T_IMAGE_VERSION *)&image_version); + } + else + { + if (is_ota_support_bank_switch()) + { + size = get_temp_ota_bank_img_size_by_img_id(img_id); + get_ota_bank_image_version(false, img_id, (T_IMAGE_VERSION *)&image_version); + } + } + + if (size == 0 || size == 0xffffffff) + { + continue; + } + + *(uint16_t *)buffer = img_id; + *(uint32_t *)&buffer[2] = image_version.ver_info.version; + + LOG_INF("img_id:%x",img_id); + + num ++; + memcpy(p_temp, buffer, sizeof(buffer)); + p_temp += sizeof(buffer); + } + + for (img_id = IMG_USER_DATA_FIRST; img_id < IMG_USER_DATA_MAX; img_id++) + { + dfu_get_user_data_info(img_id, &size, false); + + if (size == 0 || size == 0xffffffff) + { + continue; + } + + dfu_get_user_data_info(img_id, &addr, true); + fmc_flash_nor_read(addr + offsetof(T_IMG_HEADER_FORMAT, git_ver), &image_version, + sizeof(T_IMAGE_VERSION)); + + *(uint16_t *)buffer = img_id; + *(uint32_t *)&buffer[2] = image_version.ver_info.version; + + num ++; + memcpy(p_temp, buffer, sizeof(buffer)); + p_temp += sizeof(buffer); + } + + *p_data = num; + LOG_INF("<===ble_dfu_get_img_version, bank_num:%x img_num:%x", bank, num); +} + +/** + * @brief Used to get image section size + * @param p_data point of the section size + * @return void + */ +void ble_dfu_get_section_size(uint8_t *p_data) +{ + uint8_t num = 0; + IMG_ID img_id; + uint8_t buffer[6] = {0}; + uint8_t *p_temp = NULL; + uint32_t size; + //cppcheck-suppress ctuPointerArith + p_temp = p_data + 1; + + for (img_id = IMG_DFU_FIRST; img_id < IMG_DFU_MAX; img_id++) + { + size = get_active_bank_image_size_by_img_id(img_id); + + if (size == 0 || size == 0xffffffff) + { + continue; + } + + *(uint16_t *)buffer = img_id; + *(uint32_t *)&buffer[2] = size; + + num ++; + memcpy(p_temp, buffer, sizeof(buffer)); + p_temp += sizeof(buffer); + } + + for (img_id = IMG_USER_DATA_FIRST; img_id < IMG_USER_DATA_MAX; img_id++) + { + dfu_get_user_data_info(img_id, &size, false); + + if (size == 0 || size == 0xffffffff) + { + continue; + } + + *(uint16_t *)buffer = img_id; + *(uint32_t *)&buffer[2] = size; + + num ++; + memcpy(p_temp, buffer, sizeof(buffer)); + p_temp += sizeof(buffer); + } + + *p_data = num; + + LOG_INF("<===ble_dfu_get_section_size, img_num:%x in active bank", num); +} + +void dfu_notify_conn_para_update_req(struct bt_conn *conn, uint8_t error_code) +{ + if (ota_struct.dfu_conn_para_update_in_progress == true) + { + uint8_t notif_data[DFU_NOTIFY_LEN_CONN_PARA_UPDATE_REQ] = {0}; + ota_struct.dfu_conn_para_update_in_progress = false; + + notif_data[0] = error_code; + LOG_INF("<==dfu_notify_conn_para_update_req error_code=0x%x", error_code); + if (error_code == DFU_ARV_SUCCESS) + { + uint16_t conn_interval; + uint16_t conn_slave_latency; + uint16_t conn_supervision_timeout; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + LOG_INF("Failed to get conn info: %d", err); + return; + } + + conn_interval = info.le.interval; + conn_slave_latency = info.le.latency; + conn_supervision_timeout = info.le.timeout; + + LE_UINT16_TO_ARRAY(notif_data + 1, conn_interval); + LE_UINT16_TO_ARRAY(notif_data + 3, conn_slave_latency); + LE_UINT16_TO_ARRAY(notif_data + 5, conn_supervision_timeout); + } + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_CONN_PARA_UPDATE_REQ, + DFU_NOTIFY_LEN_CONN_PARA_UPDATE_REQ, + notif_data); + } +} + + +/** + * @brief Handle written request on DFU control point characteristic + * @param conn ID to identify the connection + * @param length Length of value to be written + * @param p_value Value to be written + * @return T_APP_RESULT + * @retval Handle result of this request + */ +T_APP_RESULT ble_dfu_service_handle_cp_req(struct bt_conn *conn, uint16_t length, uint8_t *p_value) +{ + T_APP_RESULT cause = APP_RESULT_INVALID_PDU; + uint8_t results = DFU_ARV_SUCCESS; + uint8_t opcode = *p_value; + uint8_t *p = p_value + 1; + bool error_flag = false; + + T_DFU_CALLBACK_DATA callback_data; + //callback_data.conn_id = conn->id; + callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE; + callback_data.msg_data.write.write_attrib_index = INDEX_DFU_CHAR_DFU_CONTROL_POINT_INDEX; + + printk("===>ble_dfu_service_handle_cp_req: opcode=0x%x, length=%d\n", opcode, length); + + if (opcode > DFU_OPCODE_MIN && opcode <= DFU_OPCODE_TEST_EN + && ota_struct.ota_flag.is_ota_process) + { + // os_timer_create(&ota_struct.timer_handle_ota_transfer, "ota_dimage_transfer", + // TIMER_ID_DFU_IMAGE_TRANS, 30 * 1000, false, ble_dfu_timeout_cb); + //printk("&ota_struct.timer_handle_ota_transfer:%x",&ota_struct.timer_handle_ota_transfer); + //os_timer_start(&ota_struct.timer_handle_ota_transfer); + } + + switch (opcode) + { + case DFU_OPCODE_START_DFU: + { + if (length == DFU_LENGTH_CP_START_DFU) /* 4 bytes is pending for encrypt */ + { + LOG_HEXDUMP_INF(p_value, length, "===>ble_dfu_service_handle_cp_req: start dfu data:"); + cause = APP_RESULT_SUCCESS; + results = ble_dfu_cp_start_dfu_handle(p); + + uint32_t callback_data_value[2]; + callback_data_value[0] = ota_struct.image_id; + callback_data_value[1] = ota_struct.image_total_length; + + callback_data.msg_data.write.opcode = DFU_WRITE_START; + callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE; + callback_data.msg_data.write.p_value = (uint8_t *)&callback_data_value; + + cause = app_dfu_srv_cb((void *)&callback_data); + + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_START_DFU, sizeof(results), &results); + + LOG_INF("DFU_OPCODE_START_DFU done!"); + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_RECEIVE_FW_IMAGE_INFO: + { + if (length == DFU_LENGTH_CP_RECEIVE_FW_IMAGE_INFO) + { + uint16_t image_id; + + LE_ARRAY_TO_UINT16(image_id, p); + cause = APP_RESULT_SUCCESS; + if (image_id == ota_struct.image_id) + { + LE_ARRAY_TO_UINT32(ota_struct.cur_offset, p + 2); + LOG_INF("===>ble_dfu_service_handle_cp_req: image_id=0x%x, cur_offset=%d", + image_id, ota_struct.cur_offset); + } + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_VALID_FW: + { + if (length == DFU_LENGTH_CP_VALID_FW) + { + cause = APP_RESULT_SUCCESS; + results = ble_dfu_cp_valid_handle(p); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_VALID_FW, sizeof(results), &results); + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_ACTIVE_IMAGE_RESET: + { + printk("in DFU_OPCODE_ACTIVE_IMAGE_RESET\n"); + if (length == DFU_LENGTH_CP_ACTIVE_IMAGE_RESET) + { + bool is_enter_dfu_mode = *p; + cause = APP_RESULT_SUCCESS; + ble_dfu_cp_active_reset_handle(conn, is_enter_dfu_mode); + ota_struct.ota_flag.is_ota_process = false; + os_timer_stop(&ota_struct.timer_handle_ota_transfer); + + callback_data.msg_data.write.opcode = DFU_WRITE_END; + cause = app_dfu_srv_cb((void *)&callback_data); + printk("done DFU_OPCODE_ACTIVE_IMAGE_RESET?\n"); + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_SYSTEM_RESET: + { + cause = APP_RESULT_SUCCESS; + ble_dfu_clear_local(OTA_RESET_CMD); + + T_DFU_FAIL_REASON dfu_fail_reason = DFU_FAIL_SYSTEM_RESET_CMD; + callback_data.msg_data.write.length = sizeof(T_DFU_FAIL_REASON); + callback_data.msg_data.write.p_value = (uint8_t *)&dfu_fail_reason; + callback_data.msg_data.write.opcode = DFU_WRITE_FAIL; + + cause = app_dfu_srv_cb((void *)&callback_data); + + bt_conn_disconnect(conn,BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + break; + case DFU_OPCODE_REPORT_TARGET_INFO: + { + if (length == DFU_LENGTH_CP_REPORT_TARGET_INFO) + { + uint8_t notif_data[DFU_NOTIFY_LEN_TARGET_INFO] = {0}; + + cause = APP_RESULT_SUCCESS; + ble_dfu_cp_report_img_info_handle(p, notif_data); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_REPORT_TARGET_INFO, + DFU_NOTIFY_LEN_TARGET_INFO, + notif_data); + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_CONN_PARA_UPDATE_REQ: + { + if (length == DFU_LENGTH_CP_CONN_PARA_UPDATE_REQ) + { + uint8_t notif_data[DFU_NOTIFY_LEN_CONN_PARA_UPDATE_REQ] = {0}; + + cause = APP_RESULT_SUCCESS; + ble_dfu_cp_conn_para_update_handle(conn, p, notif_data); + if (notif_data[0] != DFU_ARV_SUCCESS) + { + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_CONN_PARA_UPDATE_REQ, + DFU_NOTIFY_LEN_CONN_PARA_UPDATE_REQ, + notif_data); + } + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_BUFFER_CHECK_EN: + { + if (length == DFU_LENGTH_CP_BUFFER_CHECK_EN) + { + uint8_t notif_data[DFU_NOTIFY_LEN_BUFFER_CHECK_EN] = {0}; + + cause = APP_RESULT_SUCCESS; + ble_dfu_cp_buffer_check_en_handle(notif_data, MAX_BUFFER_SIZE); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_BUFFER_CHECK_EN, + DFU_NOTIFY_LEN_BUFFER_CHECK_EN, + notif_data); + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_REPORT_BUFFER_CRC: + { + if (length == DFU_LENGTH_CP_REPORT_BUFFER_CRC) + { + uint8_t notif_data[DFU_NOTIFY_LEN_BUFFER_CHECK] = {0}; + + cause = APP_RESULT_SUCCESS; + ble_dfu_cp_buffer_check_handle(p, notif_data); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_REPORT_BUFFER_CRC, + DFU_NOTIFY_LEN_BUFFER_CHECK, + notif_data); + } + else + { + error_flag = true; + } + } + break; + case DFU_OPCODE_COPY_IMG: + { + cause = APP_RESULT_SUCCESS; + results = ble_dfu_cp_copy_img_handle(p); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_COPY_IMG, sizeof(results), &results); + } + break; + case DFU_OPCODE_GET_IMAGE_VER: + { + uint8_t notif_data[DFU_NOTIFY_LEN_IMG_INFO] = {0}; + + cause = APP_RESULT_SUCCESS; + notif_data[0] = *p; //bank_num, 0: active, 1: inactive + ble_dfu_get_img_version(¬if_data[1], notif_data[0]); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_GET_IMAGE_VER, + 2 + 6 * notif_data[1]/*DFU_NOTIFY_LEN_IMG_INFO*/, notif_data); + } + break; + case DFU_OPCODE_GET_SECTION_SIZE: + { + uint8_t notif_data[DFU_NOTIFY_LEN_SECTION_SIZE] = {0}; + + cause = APP_RESULT_SUCCESS; + ble_dfu_get_section_size(notif_data); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_GET_SECTION_SIZE, + 1 + 6 * notif_data[0]/*DFU_NOTIFY_LEN_SECTION_SIZE*/, notif_data); + } + break; + case DFU_OPCODE_CHECK_SHA256: + { + uint8_t notif_data[DFU_NOTIFY_LEN_CHECK_SHA256] = {0}; + uint16_t num = *(uint16_t *)p; + LOG_INF("ble_dfu_service_handle_cp_req: CHECK SHA2556 num=%d", num); + + cause = APP_RESULT_SUCCESS; + ble_dfu_cp_check_sha256_handle(p, notif_data); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_CHECK_SHA256, DFU_NOTIFY_LEN_CHECK_SHA256, + notif_data); //check grace, send all img sha256 or not? + } + break; + case DFU_OPCODE_GET_RELEASE_VER: + { + uint8_t notif_data[DFU_NOTIFY_LEN_RELEASE_VER] = {0}; + uint32_t p_imgheader = get_header_addr_by_img_id(IMG_MCUAPP); + + cause = APP_RESULT_SUCCESS; + memcpy(notif_data, (uint8_t *)(p_imgheader + RELEASE_VER_OFFSET), DFU_NOTIFY_LEN_RELEASE_VER); + ble_dfu_service_prepare_send_notify(conn, DFU_OPCODE_GET_RELEASE_VER, DFU_NOTIFY_LEN_RELEASE_VER, + notif_data); + } + break; + case DFU_OPCODE_TEST_EN: + { + cause = APP_RESULT_SUCCESS; + memcpy(&ota_struct.test.value, p, sizeof(ota_struct.test.value)); + } + break; + case DFU_OPCODE_REPORT_IMAGE_NUM: + { + uint16_t image_id; + uint8_t cur_num; + uint8_t total_num; + + LE_ARRAY_TO_UINT16(image_id, p); + cur_num = *(p + 2); + total_num = *(p + 3); + LOG_INF("ble_dfu_service_handle_cp_req: REPORT IMAGE NUM image_id = 0x%x, cur_num = %d, total_num = %d", + image_id, cur_num, total_num); + + cause = APP_RESULT_SUCCESS; + } + break; + default: + LOG_ERR("ble_dfu_service_handle_cp_req, opcode %d not expected", opcode); + break; + } + + if (error_flag) + { + LOG_ERR("ble_dfu_service_handle_cp_req: invalid length"); + } + + return cause; +} + +/** + * @brief Handle written request on DFU packet characteristic + * @param conn ID to identify the connection + * @param length Length of value to be written + * @param p_value Value to be written + * @return T_APP_RESULT + * @retval Handle result of this request + */ +T_APP_RESULT ble_dfu_service_handle_packet(struct bt_conn *conn, uint16_t length, uint8_t *p_value) +{ + uint8_t result; + + result = ble_dfu_packet_handle(p_value, length); + + if (result == DFU_ARV_FAIL_INVALID_PARAMETER) + { + return APP_RESULT_INVALID_PDU; + } + else if (result == DFU_ARV_FAIL_OPERATION) + { + return APP_RESULT_APP_ERR; + } + + return APP_RESULT_SUCCESS; +} + diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/ble_dfu_transport.h b/soc/arm/realtek_bee/rtl87x2g/ota_src/ble_dfu_transport.h new file mode 100644 index 0000000000000..b7fcf2edba0e0 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/ble_dfu_transport.h @@ -0,0 +1,352 @@ +/** +***************************************************************************************** +* Copyright(c) 2023, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file ble_dfu_transport.h + * @brief Header file for using ble dfu transport + * @author Grace + * @date 2023-12-06 + * @version v1.1 + ************************************************************************************** + * @attention + *

© COPYRIGHT 2023 Realtek Semiconductor Corporation

+ ************************************************************************************** + */ + +/*============================================================================* + * Define to prevent recursive inclusion + *============================================================================*/ +#ifndef _BLE_DFU_TRANSPORT_H_ +#define _BLE_DFU_TRANSPORT_H_ + +#include "patch_header_check.h" + +#include + +#include + +extern bool dfu_switch_to_ota_mode_pending; +extern bool dfu_active_reset_pending; +extern bool dfu_active_reset_to_ota_mode; + +/** @defgroup BLE_DFU_TRANSPORT BLE DFU Transport + * @brief + * @{ + */ + +/*============================================================================* + * Macros + *============================================================================*/ +/** @defgroup BLE_DFU_TRANSPORT_Exported_Macros BLE DFU Transport Exported Macros + * @brief + * @{ + */ +#define MEMBER_OFFSET(struct_type, member) ((uint32_t)&((struct_type *)0)->member) + +#define SPP_PROTOCOL_INFO 0x0011 +#define BLE_PROTOCOL_INFO 0x0015 + +/*ota version num*/ +#define BLE_OTA_VERSION 0x1 +#define SPP_OTA_VERSION 0x7 + + +/** @brief image exit indicator. */ +#define NOT_SUPPORT_BANK_SWITCH 0 +#define IMAGE_LOCATION_BANK0 1 +#define IMAGE_LOCATION_BANK1 2 + + +/*bit set of device info data2*/ +#define OTA_DEVICE_FEATURE_SUPPORT_BUFFER_CHECK (1 << 0) +#define OTA_DEVICE_FEATURE_ENABLE_AES_ENCRYPT (1 << 1) +#define OTA_DEVICE_FEATURE_ENCRYPT_MODE_16N (1 << 2) +#define OTA_DEVICE_FEATURE_SUPPORT_MULTIIMAGE (1 << 3) + +/** @brief index for DFU implementation*/ +#define DFU_ARV_SUCCESS 0x01 +#define DFU_ARV_FAIL_INVALID_PARAMETER 0x02 +#define DFU_ARV_FAIL_OPERATION 0x03 +#define DFU_ARV_FAIL_DATA_SIZE_EXCEEDS_LIMIT 0x04 +#define DFU_ARV_FAIL_CRC_ERROR 0x05 +#define DFU_ARV_FAIL_DATA_LENGTH_ERROR 0x06 +#define DFU_ARV_FAIL_FLASH_WRITE_ERROR 0x07 +#define DFU_ARV_FAIL_FLASH_ERASE_ERROR 0x08 + +/** @brief opcode code for DFU service*/ +#define DFU_OPCODE_MIN 0x00 +#define DFU_OPCODE_START_DFU 0x01 +#define DFU_OPCODE_RECEIVE_FW_IMAGE_INFO 0x02 +#define DFU_OPCODE_VALID_FW 0x03 +#define DFU_OPCODE_ACTIVE_IMAGE_RESET 0x04 +#define DFU_OPCODE_SYSTEM_RESET 0x05 +#define DFU_OPCODE_REPORT_TARGET_INFO 0x06 +#define DFU_OPCODE_CONN_PARA_UPDATE_REQ 0x07 +#define DFU_OPCODE_BUFFER_CHECK_EN 0x09 +#define DFU_OPCODE_REPORT_BUFFER_CRC 0x0a +#define DFU_OPCODE_COPY_IMG 0x0c +#define DFU_OPCODE_GET_IMAGE_VER 0x0d +#define DFU_OPCODE_GET_SECTION_SIZE 0x0e +#define DFU_OPCODE_CHECK_SHA256 0x0f +#define DFU_OPCODE_GET_RELEASE_VER 0x10 +#define DFU_OPCODE_TEST_EN 0x11 +#define DFU_OPCODE_REPORT_IMAGE_NUM 0x12 +#define DFU_OPCODE_NOTIF 0x10 + +/** @brief length of each control point procedure*/ +#define DFU_LENGTH_CP_START_DFU (1+12+4) //12bytes ctrl header + 4bytes padding for encrypt +#define DFU_LENGTH_CP_RECEIVE_FW_IMAGE_INFO (1+2+4) +#define DFU_LENGTH_CP_VALID_FW (1+2+1) +#define DFU_LENGTH_CP_ACTIVE_IMAGE_RESET (1+1) //is_enter_dfu_mode +#define DFU_LENGTH_CP_SYSTEM_RESET 0x01 +#define DFU_LENGTH_CP_REPORT_TARGET_INFO (1+2) +#define DFU_LENGTH_CP_CONN_PARA_UPDATE_REQ (1+2+2+2+2) //conn_interval_min,conn_interval_max,conn_latency,superv_tout +#define DFU_LENGTH_CP_PKT_RX_NOTIF_REQ (1+2) +#define DFU_LENGTH_CP_CONN_PARA_TO_UPDATE_REQ (1+2+2+2+2) +#define DFU_LENGTH_CP_BUFFER_CHECK_EN 0x01 +#define DFU_LENGTH_CP_REPORT_BUFFER_CRC (1+2+2) + +#define MAX_IMG_NUM (IMG_DFU_MAX - IMG_DFU_FIRST + IMG_USER_DATA_MAX - IMG_USER_DATA_FIRST) //0x16 + 8 + +/** @brief length of each control point notification*/ +#define DFU_NOTIFY_LEN_TARGET_INFO (1+4+4+2) //error_code, rsvd, cur_offset, buffer_check_offset +#define DFU_NOTIFY_LEN_CONN_PARA_UPDATE_REQ (1+2+2+2) //connInterval, latency, supervisionTimeout +#define DFU_NOTIFY_LEN_BUFFER_CHECK_EN (1+2+2) //error_code, bufcheck_en, max_buf_size, rsvd +#define DFU_NOTIFY_LEN_BUFFER_CHECK (1+4) //error_code, cur_offset +#define DFU_NOTIFY_LEN_CHECK_SHA256 (2+1) //img_id, check_ret(0:fail, 1: same as inactive, 2: same as active, 3: same as inactive and active) +#define DFU_NOTIFY_LEN_RELEASE_VER 6 //release version of app data bin +#define DFU_NOTIFY_LEN_IMG_INFO (1+1+(2+4)*MAX_IMG_NUM) //bank_num, img_num, img_id1, img_ver1, .... +#define DFU_NOTIFY_LEN_SECTION_SIZE (1+(2+4)*MAX_IMG_NUM) //img_num, img_id1, img_size1, .... + +#define IMG_INFO_LEN DFU_NOTIFY_LEN_IMG_INFO +#define SECTION_SIZE_LEN DFU_NOTIFY_LEN_SECTION_SIZE + + +#define UINT_4K 4096 +#define MAX_BUFFER_SIZE 4096 + +#define SHA256_OFFSET (MEMBER_OFFSET(T_AUTH_HEADER_FORMAT, image_hash)) //372 +#define SHA256_LEN 32 +#define RELEASE_VER_OFFSET (SHA256_OFFSET + SHA256_LEN) + + +#define BTAON_FAST_AON_GPR_15 0x1a2 + +/** End of BLE_DFU_TRANSPORT_Exported_Macros + * @} + */ + + +/*============================================================================* + * Types + *============================================================================*/ +/** @defgroup BLE_DFU_TRANSPORT_Exported_Types BLE DFU Transport Exported Types + * @brief + * @{ + */ +typedef enum +{ + OTA_SUCCESS_REBOOT, + OTA_BLE_DISC, + OTA_IMAGE_TRANS_TIMEOUT, + OTA_IMAGE_TOTAL_TIMEOUT, + OTA_RESET_CMD, +} T_OTA_CLEAR_LOCAL_CAUSE; + +typedef enum +{ + ACTIVE_BANK = 0, + INACTIVE_BANK = 1, +} T_OTA_BANK; + +typedef enum +{ + TIMER_ID_DFU_IMAGE_TRANS, +} T_OTA_TIMER_ID; + +typedef union +{ + uint8_t value; + struct + { + uint8_t buffer_check_en: 1; + uint8_t is_ota_process: 1; + uint8_t is_support_mutil_image: 1; + uint8_t is_devinfo: 1; + uint8_t skip_flag: 1; + uint8_t ota_mode: 1; + uint8_t RSVD: 2; + }; +} OTA_FLAG; + +typedef union +{ + uint8_t value; + struct + { + uint8_t t_aes_en: 1; + uint8_t t_stress_test: 1; + uint8_t t_copy_fail: 1; + uint8_t t_skip_fail: 1; + uint8_t t_buffercheck_disable: 1; + uint8_t rsvd: 3; + }; +} TEST_ENABLE; + +typedef struct +{ + uint32_t image_offset; +} T_TEMP_IMAGE_INFO; + +/** @brief Table used to store Extended Device Information */ +typedef struct +{ + void *timer_handle_ota_transfer; + uint8_t *p_ota_temp_buf_head; + uint32_t image_indicator; + uint32_t image_total_length; + uint32_t cur_offset; + uint32_t buffer_check_offset; + uint32_t next_subimage_offset; + uint32_t tmp_next_subimage_offset; + uint16_t image_id; + uint16_t ota_temp_buf_used_size; + uint16_t buffer_size; + uint16_t mtu_size; + T_TEMP_IMAGE_INFO temp_image_info[IMG_DFU_MAX - IMG_BANK_FIRST]; + uint8_t force_temp_mode; + uint8_t bd_addr[6]; + uint8_t bp_level; + bool dfu_conn_para_update_in_progress; + bool is_last_image; + OTA_FLAG ota_flag; + TEST_ENABLE test; +} OTA_FUNCTION_STRUCT; + +typedef struct +{ + IMG_ID img_id; + uint8_t sha256[32]; +} SHA256_CHECK; + +typedef struct +{ + uint16_t img_id; + uint8_t data[4]; +} IMG_INFO; + +typedef union +{ + uint8_t value; + struct + { + uint8_t buffercheck_en: 1; + uint8_t aes_en: 1; + uint8_t aes_mode: 1; /*1:16*N bytes, 0:first 16byte*/ + uint8_t support_multiimage: 1; + uint8_t is_support_normal_ota: 1; //valid only when spec_ver>=4 + uint8_t is_ota_support_dual_bank_merge: 1; + uint8_t rsvd: 2; + }; +} DEVICE_INFO_MODE; + + +typedef struct +{ + uint8_t ic_type; + uint8_t spec_ver; + DEVICE_INFO_MODE mode; + uint8_t rsvd0; + uint16_t ota_temp_size; //for watch + uint8_t active_banknum; //0: not support dual bank + uint8_t bootpatch_active_banknum; //0: not support dual bank + uint8_t secureapp_active_banknum; //0: not support dual bank + uint16_t ctrl_header_offset; + uint8_t rsvd1; +} __attribute__((packed)) DEVICE_INFO; + + +typedef union +{ + uint32_t value; + struct + { + uint32_t enc_en: 1; + uint32_t sha256_en: 1; + uint32_t link_loss_stop: 1; + uint32_t rsvd: 28; + }; +} OTA_SETTING; + +/** End of BLE_DFU_TRANSPORT_Exported_Types + * @} + */ + +/*============================================================================* + * Functions + *============================================================================*/ +/** @defgroup BLE_DFU_TRANSPORT_Exported_Functions BLE DFU Transport Functions + * @brief + * @{ + */ +/** + * @brief Used to get device information + * @param conn_id connection id + * @param p_deviceinfo point of the device info + * @return void + */ +void ble_dfu_get_device_info(struct bt_conn *conn, DEVICE_INFO *p_deviceinfo); + +/** + * @brief Used to get image version + * @param *p_data point of image version + * @param bank 0:active bank 1:inactive bank + * @return void + */ +void ble_dfu_get_img_version(uint8_t *p_data, uint8_t bank); + +/** + * @brief Used to get image section size + * @param p_data point of the section size + * @return void + */ +void ble_dfu_get_section_size(uint8_t *p_data); + +/** + * @brief dfu notify connection parameter update request + * @param conn_id ID to identify the connection + * @param error_code error code of conn para update req + * @return void + */ +void dfu_notify_conn_para_update_req(struct bt_conn *conn, uint8_t error_code); + +/** + * @brief Handle written request on DFU packet characteristic + * @param conn_id ID to identify the connection + * @param length Length of value to be written + * @param p_value Value to be written + * @return T_APP_RESULT + * @retval Handle result of this request + */ +T_APP_RESULT ble_dfu_service_handle_packet(struct bt_conn *conn, uint16_t length, uint8_t *p_value); + +/** + * @brief Handle written request on DFU control point characteristic + * @param conn_id ID to identify the connection + * @param length Length of value to be written + * @param p_value Value to be written + * @return T_APP_RESULT + * @retval Handle result of this request + */ +T_APP_RESULT ble_dfu_service_handle_cp_req(struct bt_conn *conn, uint16_t length, uint8_t *p_value); + + +/** End of BLE_DFU_TRANSPORT_Exported_Functions + * @} + */ + +/** End of BLE_DFU_TRANSPORT + * @} + */ + +#endif diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/dfu_common.c b/soc/arm/realtek_bee/rtl87x2g/ota_src/dfu_common.c new file mode 100644 index 0000000000000..e5ef1a7c6822f --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/dfu_common.c @@ -0,0 +1,704 @@ +/** +********************************************************************************************************** +* Copyright(c) 2023, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file dfu_common.c +* @brief supply dfu common APIs to application +* @details +* @author Grace +* @date 2023-12-06 +* @version v1.1 + ************************************************************************************** + * @attention + *

© COPYRIGHT 2023 Realtek Semiconductor Corporation

+ ************************************************************************************** + */ + +/*============================================================================* + * Header Files + *============================================================================*/ + +#include +#include +#include "aes_api.h" +#include "ble_dfu_transport.h" +#include "crypto_engine_nsc.h" +#include "dfu_common.h" +#include "fmc_api.h" +#include "os_sync.h" +#include "rtl876x.h" +#include "aon_reg.h" +#include "rtl_wdt.h" +#include "trace.h" +#include "utils.h" +#include "flash_map.h" + +#include +LOG_MODULE_REGISTER(dfu_common); + + + +/*============================================================================* + * Macros + *============================================================================*/ +#define SHA256_LENGTH 32 +#define SHA256_BUFFER_SIZE 128 +#define READ_BACK_BUFFER_SIZE 64 + +/*============================================================================* + * Variables + *============================================================================*/ +/*max img num = 32, BIT0: OTA, BIT1: SecureBoot, ..., */ +uint32_t valid_bitmap = 0; +PLATFORM_STATIC_ASSERT((IMG_DFU_MAX - IMG_DFU_FIRST + 1) < (sizeof(valid_bitmap) << 3), + valid_bitmap); + +uint32_t user_data_valid_bitmap = 0; + +/*============================================================================* + * Private Functions + *============================================================================*/ +/** + * @brief get 16bit data swapped. + * + * @param val 16bit data to be swapped. + * @return value after being swapped. +*/ +static uint16_t swap_16(uint16_t val) +{ + uint16_t result; + + /* Idiom Recognition for REV16 */ + result = ((val & 0xff) << 8) | ((val & 0xff00) >> 8); + + return result; +} + +/** + * @brief Get aes256 key swapped + * @param val aes256 key to be swapped + * @return None + */ +static void aes256_key_swap(uint8_t key[32]) +{ + uint32_t tmp[4]; + + memcpy(tmp, key, 16); + memcpy(key, key + 16, 16); + memcpy(key + 16, tmp, 16); +} + +/** + * @brief Check image sha256 + * @param[in] p_header pointer to dfu check image header + * @return Check result + * @retval true check pass + * @retval false check fail + */ +static bool dfu_check_sha256(T_IMG_HEADER_FORMAT *p_header) +{ + uint32_t sha256sum[SHA256_LENGTH / 4] = {0}; + uint8_t sha256img[SHA256_LENGTH] = {0}; + uint8_t buf[SHA256_BUFFER_SIZE] = {0}; + uint32_t len; + uint16_t i; + uint16_t loop_cnt, remain_size; + uint32_t pdata = (uint32_t)&p_header->ctrl_header; + uint32_t s; + + s = os_lock(); + fmc_flash_nor_read((uint32_t)(pdata + MEMBER_OFFSET(T_IMG_CTRL_HEADER_FORMAT, payload_len)), + &len, 4); + os_unlock(s); + len += sizeof(T_IMG_HEADER_FORMAT) - sizeof(T_AUTH_HEADER_FORMAT); + + loop_cnt = len / SHA256_BUFFER_SIZE; + remain_size = len % SHA256_BUFFER_SIZE; + + HW_SHA256_CTX ctx = {0}; + + hw_sha256_init(); + hw_sha256_start(&ctx, NULL); + + for (i = 0; i < loop_cnt; ++i) + { + s = os_lock(); + fmc_flash_nor_read(pdata, buf, SHA256_BUFFER_SIZE); + os_unlock(s); + if (i == 0) + { + //because not_ready is included when calculate image sha256 + ((T_IMG_CTRL_HEADER_FORMAT *)buf)->ctrl_flag.not_ready = 0; + } + + hw_sha256_cpu_update(&ctx, buf, SHA256_BUFFER_SIZE); + pdata += SHA256_BUFFER_SIZE; + } + if (remain_size) + { + s = os_lock(); + fmc_flash_nor_read(pdata, buf, remain_size); + os_unlock(s); + if (loop_cnt == 0) + { + ((T_IMG_CTRL_HEADER_FORMAT *)buf)->ctrl_flag.not_ready = 0; + } + + hw_sha256_cpu_update(&ctx, buf, remain_size); + } + + hw_sha256_finish(&ctx, sha256sum); + s = os_lock(); + fmc_flash_nor_read((uint32_t)&p_header->auth.image_hash, sha256img, SHA256_LENGTH); + os_unlock(s); + + return (memcmp(sha256img, sha256sum, SHA256_LENGTH) == 0); +} + +/*============================================================================* + * Public Functions + *============================================================================*/ +/** + * @brief AES256 decrypt + * @param input pointer to input data + * @return None + */ +void dfu_aes256_decrypt_16byte(uint8_t *input) +{ + static const uint8_t SECRET_KEY_DEFAULT[32] = + { + 0x4E, 0x46, 0xF8, 0xC5, 0x09, 0x2B, 0x29, 0xE2, + 0x9A, 0x97, 0x1A, 0x0C, 0xD1, 0xF6, 0x10, 0xFB, + 0x1F, 0x67, 0x63, 0xDF, 0x80, 0x7A, 0x7E, 0x70, + 0x96, 0x0D, 0x4C, 0xD3, 0x11, 0x8E, 0x60, 0x1A + }; + uint8_t key_tmp[32]; + + memcpy(key_tmp, SECRET_KEY_DEFAULT, 32); + aes256_key_swap(key_tmp); + + aes256_ecb_decrypt(input, key_tmp, input); +} + +/** + * @brief Get image size of bank area + * @param image_id image ID + * @return bank size + */ +uint32_t get_bank_size_by_img_id(IMG_ID image_id) +{ + uint32_t bank_size; + + T_IMG_HEADER_FORMAT *ota_header = (T_IMG_HEADER_FORMAT *)get_active_ota_bank_addr(); + bank_size = ota_header->image_info[(image_id - IMG_OTA - 1) * 2 + 1];; + + return bank_size; +} + +/** + * @brief Chip reset for dfu + * @param reset_mode reset mode + * @param reason reset reason + * @return None + */ +void dfu_fw_reboot(WDTMode_TypeDef reset_mode, T_SW_RESET_REASON reason) +{ + DBG_DIRECT("dfu_fw_reboot: reset_mode %x, reason 0x%x", reset_mode, reason); + chip_reset(reset_mode); +} + +/** + * @brief Check ota mode flag, if image need update + * @param None + * @return Result: true: image need update, false: image don't need update + */ +bool dfu_check_ota_mode_flag(void) +{ + AON_NS_REG8X_FW_GENERAL_NS_TYPE aon_0x1D10 = {.d32 = AON_REG_READ(AON_NS_REG8X_FW_GENERAL_NS)}; + return aon_0x1D10.ota_mode; +} + +/** + * @brief Set ota mode flag + * @param enable ota mode flag + * @return None + */ +void dfu_set_ota_mode_flag(bool enable) +{ + AON_NS_REG8X_FW_GENERAL_NS_TYPE aon_0x1D10 = {.d32 = AON_REG_READ(AON_NS_REG8X_FW_GENERAL_NS)}; + if (enable) + { + aon_0x1D10.ota_mode = 1; + } + else + { + aon_0x1D10.ota_mode = 0; + } + AON_REG_WRITE(AON_NS_REG8X_FW_GENERAL_NS, aon_0x1D10.d32); +} + +/** + * @brief Switch to the OTA mode, if support normal ota app need call it. + * @param None + * @return None + */ +void dfu_switch_to_ota_mode(void) +{ + DFU_PRINT_INFO0("==>dfu_switch_to_ota_mode"); + dfu_set_ota_mode_flag(true); + + dfu_fw_reboot(RESET_ALL_EXCEPT_AON, DFU_SWITCH_TO_OTA_MODE); +} + +/** + * @brief Get the ic type of current firmware + * @param None + * @return IC type + */ +uint8_t dfu_get_ic_type(void) +{ + uint8_t ic_type = IMG_IC_TYPE; + uint32_t image_addr = get_header_addr_by_img_id(IMG_MCUAPP); + + ic_type = ((T_IMG_HEADER_FORMAT *)image_addr)->ctrl_header.ic_type; + + return ic_type; +} + +/** + * @brief Get active bank number + * @param None + * @return Active bank number + */ +T_ACTIVE_BANK_NUM get_active_bank_num(void) +{ + T_ACTIVE_BANK_NUM bank_num = OTA_BANK_MAX; + + uint32_t ota_bank0_addr = flash_partition_addr_get(PARTITION_FLASH_OTA_BANK_0); + uint32_t ota_bank1_addr = flash_partition_addr_get(PARTITION_FLASH_OTA_BANK_1); + uint32_t ota_header_addr = get_active_ota_bank_addr(); + if (ota_bank0_addr == ota_header_addr) + { + bank_num = OTA_BANK0; + } + else if (ota_bank1_addr == ota_header_addr) + { + bank_num = OTA_BANK1; + } + else + { + /* invalid case */ + //bank_num = OTA_BANK_MAX; + } + + return bank_num; +} + +/** + * @brief Get template ota bank image address by images id + * @param image_id image ID + * @return Image address + */ +uint32_t dfu_get_temp_ota_bank_img_addr_by_img_id(IMG_ID image_id) +{ + uint32_t image_addr = 0; + + /*not support image id*/ + if (image_id < IMG_DFU_FIRST || + ((image_id >= IMG_DFU_MAX) && (image_id < IMG_USER_DATA_FIRST))) + { + return image_addr; + } + + if (image_id < IMG_USER_DATA_MAX && image_id >= IMG_USER_DATA_FIRST) + { + dfu_get_user_data_info(image_id, &image_addr, true); + return image_addr; + } + +#if (SUPPORT_BL_COPY_SECURE_IMAGE == 1) + if (image_id == IMG_OTA || (image_id >= IMG_BANK_FIRST && image_id < IMG_DFU_MAX)) + { + image_addr = get_temp_ota_bank_img_addr_by_img_id(image_id); + } + else + { + image_addr = flash_nor_get_bank_addr(FLASH_OTA_TMP); + } +#else + if (!is_ota_support_bank_switch()) + { + if (image_id == IMG_SECUREMCUAPP || image_id == IMG_SECUREMCUAPPDATA) + { + image_addr = flash_partition_addr_get(PARTITION_FLASH_OTA_TMP); + } + else + { + image_addr = get_temp_ota_bank_img_addr_by_img_id(image_id); + } + } + else + { + image_addr = get_temp_ota_bank_img_addr_by_img_id(image_id); + } +#endif + + return image_addr; +} + +/** + * @brief Get template ota bank image size by images id + * @param image_id image ID + * @return Image size + */ +uint32_t dfu_get_temp_ota_bank_img_size_by_img_id(IMG_ID image_id) +{ + uint32_t image_size = 0; + + /*not support image id*/ + if (image_id < IMG_DFU_FIRST || + ((image_id >= IMG_DFU_MAX) && (image_id < IMG_USER_DATA_FIRST))) + { + //invalid image id + return image_size; + } + + if (image_id >= IMG_USER_DATA_FIRST && image_id < IMG_USER_DATA_MAX) + { + dfu_get_user_data_info(image_id, &image_size, false); + return image_size; + } + +#if (SUPPORT_BL_COPY_SECURE_IMAGE == 1) + if (image_id == IMG_OTA || (image_id >= IMG_BANK_FIRST && image_id < IMG_DFU_MAX)) + { + image_size = get_temp_ota_bank_img_size_by_img_id(image_id); + } + else + { + image_size = flash_nor_get_bank_size(FLASH_OTA_TMP); + } +#else + if (!is_ota_support_bank_switch()) + { + if (image_id == IMG_SECUREMCUAPP || image_id == IMG_SECUREMCUAPPDATA) + { + image_size = flash_partition_size_get(PARTITION_FLASH_OTA_TMP); + } + else + { + image_size = get_temp_ota_bank_img_size_by_img_id(image_id); + } + } + else + { + image_size = get_temp_ota_bank_img_size_by_img_id(image_id); + } + +#endif + + return image_size; +} + +/** +* @brief calculate checksum of lenth of buffer in flash. +* +* @param signature signature to identify FW. +* @param offset offset of the image. +* @param length length of data. +* @param crcValue ret crc value point. +* @return 0 if buffer checksum calcs successfully, error line number otherwise +*/ + +uint32_t dfu_check_bufcrc(uint8_t *buf, uint32_t length, uint16_t mCrcVal) +{ + uint32_t ret = 0; + uint16_t checksum16 = 0; + uint32_t i; + uint16_t *p16; + + p16 = (uint16_t *)buf; + for (i = 0; i < length / 2; ++i) + { + checksum16 = checksum16 ^ (*p16); + ++p16; + } + + checksum16 = swap_16(checksum16); + if (checksum16 != mCrcVal) + { + ret = __LINE__; + } + + DFU_PRINT_TRACE2("<==dfu_check_bufcrc: checksum16=0x%x, mCrcVal=%x", checksum16, mCrcVal); + + return ret; +} + +/** + * @brief Erase a sector of the flash + * @param image_id image ID + * @param offset flash address offset + * @return Result 0: success, others: fail + */ +uint32_t dfu_flash_erase(IMG_ID image_id, uint32_t offset) +{ + uint32_t result = 0; + uint32_t dfu_base_addr; + + dfu_base_addr = dfu_get_temp_ota_bank_img_addr_by_img_id(image_id); + + if (dfu_base_addr == 0) + { + return __LINE__; + } + + result = fmc_flash_nor_erase(dfu_base_addr + offset, FMC_FLASH_NOR_ERASE_SECTOR); + + DFU_PRINT_TRACE1("<==dfu_flash_erase: result=%d", result); + + return result; +} + +/** + * @brief write data to flash + * @param img_id image id + * @param offset image offset + * @param total_offset total offset when ota temp mode + * @param p_void point of data + * @return 0: success; other: fail + */ +uint32_t dfu_write_data_to_flash(uint16_t img_id, uint32_t offset, uint32_t total_offset, + uint32_t length, void *p_void) +{ + uint32_t ret = 0; + uint32_t dfu_base_addr; + uint8_t readback_buffer[READ_BACK_BUFFER_SIZE]; + uint32_t read_back_len; + uint32_t dest_addr; + uint8_t *p_src = (uint8_t *)p_void; + uint32_t remain_size = length; + uint32_t s; + + DFU_PRINT_TRACE3("==>dfu_write_data_to_flash: total_offset=0x%x, offset=%d, length=%d", + total_offset, offset, length); + + if (p_void == 0) + { + ret = __LINE__; + goto L_EXIT; + } + + dfu_base_addr = dfu_get_temp_ota_bank_img_addr_by_img_id((IMG_ID)img_id); + + if (dfu_base_addr == 0) + { + ret = __LINE__; + goto L_EXIT; + } + + if (img_id >= IMG_DFU_FIRST && img_id < IMG_DFU_MAX) + { + dfu_base_addr += total_offset; + } + if (offset == 0) + { + T_IMG_HEADER_FORMAT *p_header = (T_IMG_HEADER_FORMAT *)p_void; + + p_header->ctrl_header.ctrl_flag.not_ready = 0x1; + } + + dest_addr = dfu_base_addr + offset; + DFU_PRINT_TRACE2("==>dfu_write_data_to_flash:dfu_base_addr=0x%x, dest_addr=0x%x", dfu_base_addr, + dest_addr); + if ((dest_addr % FLASH_SECTOR_SIZE) == 0) + { + s = os_lock(); + fmc_flash_nor_erase(dest_addr, FMC_FLASH_NOR_ERASE_SECTOR); + os_unlock(s); + } + else + { + if ((dest_addr / FLASH_SECTOR_SIZE) != ((dest_addr + length) / FLASH_SECTOR_SIZE)) + { + if ((dest_addr + length) % FLASH_SECTOR_SIZE) + { + s = os_lock(); + fmc_flash_nor_erase((dest_addr + length) & ~(FLASH_SECTOR_SIZE - 1), + FMC_FLASH_NOR_ERASE_SECTOR); + os_unlock(s); + } + } + } + + s = os_lock(); + fmc_flash_nor_write(dest_addr, p_void, length); + os_unlock(s); + + SCB_InvalidateDCache_by_Addr((uint32_t *)dest_addr, length); + + while (remain_size) + { + read_back_len = (remain_size >= READ_BACK_BUFFER_SIZE) ? READ_BACK_BUFFER_SIZE : remain_size; + s = os_lock(); + fmc_flash_nor_read(dest_addr, readback_buffer, read_back_len); + os_unlock(s); + if (memcmp(readback_buffer, p_src, read_back_len) != 0) + { + ret = __LINE__; + goto L_EXIT; + } + + dest_addr += read_back_len; + p_src += read_back_len; + remain_size -= read_back_len; + } + +L_EXIT: + DFU_PRINT_TRACE1("<==dfu_write_data_to_flash: ret=%d", ret); + return ret; +} + +/** + * @brief check the integrity of the image + * @param img_id image id + * @param offset address offset + * @return ture:success ; false: fail + */ +bool dfu_checksum(IMG_ID img_id, uint32_t offset) +{ + uint32_t base_addr = 0; + uint32_t image_total_length = 0; + bool ret = false; + DFU_PRINT_TRACE2("==>dfu_checksum: image_id=0x%x, offset=%d", img_id, offset); + + base_addr = dfu_get_temp_ota_bank_img_addr_by_img_id(img_id); + + if (base_addr == 0) + { + return false; + } + + if (img_id >= IMG_DFU_FIRST && img_id < IMG_DFU_MAX) + { + base_addr += offset; + } + + fmc_flash_nor_read(base_addr + offsetof(T_IMG_HEADER_FORMAT, ctrl_header) + + offsetof(T_IMG_CTRL_HEADER_FORMAT, payload_len), + &image_total_length, 4); + image_total_length += sizeof(T_IMG_HEADER_FORMAT); + + /*store wdg config and check wdg enable*/ + bool wdt_en = WDT_IsEnable(); + WDTMode_TypeDef wdt_mode = WDT_GetMode(); + uint32_t wdt_timeout = WDT_GetTimeoutMs(); + + /*if ota large img, need modify wdg timeout period*/ + if (wdt_en && image_total_length > 0x100000) + { + /*1M and less---4s, 2M and less---8s,..., 8M and less---32s*/ + uint32_t img_align_len = ((image_total_length + (0x100000 - 1)) & (~(0x100000 - 1))); + uint32_t wdt_period = 4000 * (img_align_len / 0x100000); + DFU_PRINT_TRACE2("<==dfu_checksum: Change WDG Period to %d ms, image_total_length 0x%x", + wdt_period, image_total_length); + WDT_Start(wdt_period, RESET_ALL); + } + + ret = dfu_check_sha256((T_IMG_HEADER_FORMAT *)base_addr); + + if (wdt_en && image_total_length > 0x100000) + { + /* restore wdg config */ + WDT_Start(wdt_timeout, wdt_mode); + } + + DFU_PRINT_TRACE2("<==dfu_checksum: base_addr=0x%x, ret=%d", base_addr, ret); + + return ret; +} + +/** + * @brief clear not ready flag of specific image + * @param addr address of the image + * @return void + */ +void dfu_set_ready(T_IMG_HEADER_FORMAT *p_header) +{ + T_IMG_CTRL_HEADER_FORMAT ctrl_header; + uint16_t ctrl_flag; + uint32_t s; + + s = os_lock(); + fmc_flash_nor_read((uint32_t) & (p_header->ctrl_header.ctrl_flag), &ctrl_flag, sizeof(ctrl_flag)); + os_unlock(s); + DFU_PRINT_TRACE2("==>dfu_set_ready: p_header 0x%x, ctrl_flag 0x%x", p_header, ctrl_flag); + + ctrl_flag &= ~0x80; + s = os_lock(); + fmc_flash_nor_write((uint32_t) & (p_header->ctrl_header.ctrl_flag), &ctrl_flag, sizeof(ctrl_flag)); + fmc_flash_nor_read((uint32_t)&p_header->ctrl_header, &ctrl_header, sizeof(ctrl_header)); + os_unlock(s); + DFU_PRINT_TRACE2("<==dfu_set_ready:img_id 0x%x, after ctrl_flag 0x%x", ctrl_header.image_id, + ctrl_header.ctrl_flag); +} + +/** + * @brief Clear not obsolete flag of specific image + * @param p_header pointer to image header + * @return None + */ +void dfu_set_obsolete(T_IMG_HEADER_FORMAT *p_header) +{ + uint16_t ctrl_flag; + uint32_t s; + s = os_lock(); + fmc_flash_nor_read((uint32_t) & (p_header->ctrl_header.ctrl_flag), &ctrl_flag, sizeof(ctrl_flag)); + ctrl_flag &= ~0x0100; + fmc_flash_nor_write((uint32_t) & (p_header->ctrl_header.ctrl_flag), &ctrl_flag, sizeof(ctrl_flag)); + os_unlock(s); +} + + +T_USER_DATA_ERROR_TYPE dfu_get_user_data_info(IMG_ID image_id, + uint32_t *img_info, bool is_addr) +{ + T_USER_DATA_ERROR_TYPE err_code = USER_DATA_SUCCESS; + + switch (image_id) + { + case IMG_USER_DATA1: + *img_info = is_addr ? USER_DATA1_ADDR : USER_DATA1_SIZE; + break; + case IMG_USER_DATA2: + *img_info = is_addr ? USER_DATA2_ADDR : USER_DATA2_SIZE; + break; + case IMG_USER_DATA3: + *img_info = is_addr ? USER_DATA3_ADDR : USER_DATA3_SIZE; + break; + case IMG_USER_DATA4: + *img_info = is_addr ? USER_DATA4_ADDR : USER_DATA4_SIZE; + break; + case IMG_USER_DATA5: + *img_info = is_addr ? USER_DATA5_ADDR : USER_DATA5_SIZE; + break; + case IMG_USER_DATA6: + *img_info = is_addr ? USER_DATA6_ADDR : USER_DATA6_SIZE; + break; + case IMG_USER_DATA7: + *img_info = is_addr ? USER_DATA7_ADDR : USER_DATA7_SIZE; + break; + case IMG_USER_DATA8: + *img_info = is_addr ? USER_DATA8_ADDR : USER_DATA8_SIZE; + break; + default: + APP_PRINT_ERROR1("error user data image_id 0x%x", image_id); + err_code = USER_DATA_TYPE_ERROR; + *img_info = 0; + break; + } + + return err_code; +} + +/******************* (C) COPYRIGHT 2023 Realtek Semiconductor Corporation *****END OF FILE****/ diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/dfu_common.h b/soc/arm/realtek_bee/rtl87x2g/ota_src/dfu_common.h new file mode 100644 index 0000000000000..03817ac368720 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/dfu_common.h @@ -0,0 +1,230 @@ +/** +***************************************************************************************** +* Copyright(c) 2023, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file dfu_common.h + * @brief Header file for using dfu common + * @author Grace + * @date 2023-12-06 + * @version v1.1 + ************************************************************************************** + * @attention + *

© COPYRIGHT 2023 Realtek Semiconductor Corporation

+ ************************************************************************************** + */ + +/*============================================================================* + * Define to prevent recursive inclusion + *============================================================================*/ +#ifndef _DFU_COMMON_H_ +#define _DFU_COMMON_H_ + +#include "patch_header_check.h" +#include "rtl876x.h" +#include "wdt.h" + +/** @defgroup DFU_COMMON DFU Common + * @brief + * @{ + */ +/*============================================================================* + * Macros + *============================================================================*/ +/** @defgroup DFU_COMMON_Exported_Macros DFU Common Exported Macros + * @brief + * @{ + */ +#define FLASH_SECTOR_SIZE 0x1000 + + +#define PLATFORM_STATIC_ASSERT(condition, identifier) typedef char PALStaticAssert_##identifier[(condition) ? 1 : -1] + +#define SET_VALID_BITMAP(image_id) (valid_bitmap |= BIT(image_id - IMG_DFU_FIRST)) +#define GET_VALID_BITMAP(image_id) (valid_bitmap >> (image_id - IMG_DFU_FIRST) & BIT0) + +#define SET_USER_DATA_VALID_BITMAP(image_id) (user_data_valid_bitmap |= BIT(image_id - IMG_USER_DATA_FIRST)) +#define GET_USER_DATA_VALID_BITMAP(image_id) (user_data_valid_bitmap >> (image_id - IMG_USER_DATA_FIRST) & BIT0) + + +/** End of DFU_COMMON_Exported_Macros + * @} + */ + + +/*============================================================================* + * Types + *============================================================================*/ +/** @defgroup DFU_COMMON_Exported_Types DFU Common Exported Types + * @brief + * @{ + */ +typedef enum +{ + OTA_BANK0, + OTA_BANK1, + OTA_BANK_MAX, +} T_ACTIVE_BANK_NUM; + +typedef enum +{ + USER_DATA_SUCCESS = 0, + USER_DATA_NOT_SUPPORT_OTA, + USER_DATA_TYPE_ERROR, +} T_USER_DATA_ERROR_TYPE; + +/** End of DFU_COMMON_Exported_Types + * @} + */ +extern uint32_t valid_bitmap; +extern uint32_t user_data_valid_bitmap; +/*============================================================================* + * Functions + *============================================================================*/ +/** @defgroup DFU_COMMON_Exported_Functions DFU Common Exported Functions + * @brief + * @{ + */ +/** + * @brief AES256 decrypt + * @param input pointer to input data + * @return None + */ +void dfu_aes256_decrypt_16byte(uint8_t *input); + +/** + * @brief Get image size of bank area + * @param image_id image ID + * @return bank size + */ +uint32_t get_bank_size_by_img_id(IMG_ID image_id); + +/** + * @brief Chip reset for dfu + * @param reset_mode reset mode + * @param reason reset reason + * @return None + */ +void dfu_fw_reboot(WDTMode_TypeDef reset_mode, T_SW_RESET_REASON reason); + +/** + * @brief Check ota mode flag, if image need update + * @param None + * @return Result: true: image need update, false: image don't need update + */ +bool dfu_check_ota_mode_flag(void); + +/** + * @brief Set ota mode flag + * @param enable ota mode flag + * @return None + */ +void dfu_set_ota_mode_flag(bool enable); + +/** + * @brief Switch to the OTA mode, if support normal ota app need call it. + * @param None + * @return None + */ +void dfu_switch_to_ota_mode(void); + +/** + * @brief get the ic type of current fw + * @param void + * @return ic type + */ +uint8_t dfu_get_ic_type(void); + +/** + * @brief get active bank num + * @param + * @return bank num value + */ +T_ACTIVE_BANK_NUM get_active_bank_num(void); + +/** + * @brief get inactive bank's image address + * @param image_id image id + * @return image address + */ +uint32_t dfu_get_temp_ota_bank_img_addr_by_img_id(IMG_ID image_id); + +/** + * @brief get inactive bank's image size + * @param image_id image id + * @return image size + */ +uint32_t dfu_get_temp_ota_bank_img_size_by_img_id(IMG_ID image_id); + +/** +* @brief calculate checksum of lenth of buffer in flash. +* +* @param signature signature to identify FW. +* @param offset offset of the image. +* @param length length of data. +* @param crcValue ret crc value point. +* @return 0 if buffer checksum calcs successfully, error line number otherwise +*/ + +uint32_t dfu_check_bufcrc(uint8_t *buf, uint32_t length, uint16_t mCrcVal); + +/** + * @brief erase a sector of the flash. + * + * @param signature signature to identify FW. + * @param offset offset of the image. + * @return 0 if erase successfully, error line number otherwise +*/ +uint32_t dfu_flash_erase(IMG_ID image_id, uint32_t offset); + +/** + * @brief write data to flash + * @param img_id image id + * @param offset image offset + * @param total_offset total offset when ota temp mode + * @param p_void point of data + * @return 0: success; other: fail + */ +uint32_t dfu_write_data_to_flash(uint16_t img_id, uint32_t offset, uint32_t total_offset, + uint32_t length, void *p_void); + +/** + * @brief check the integrity of the image + * @param image_id image id + * @param offset address offset + * @return ture:success ; false: fail + */ +bool dfu_checksum(IMG_ID image_id, uint32_t offset); + +/** + * @brief clear not ready flag of specific image + * @param p_header point of p_header + * @return void + */ +void dfu_set_ready(T_IMG_HEADER_FORMAT *p_header); + +/** + * @brief clear not obsolete flag of specific image + * @param p_header point of p_header + * @return void + */ +void dfu_set_obsolete(T_IMG_HEADER_FORMAT *p_header); + +/** + * @brief get user data infomation + * @param image_id image id + * @param img_info point of img_info + * @param is_addr addr + * @return A T_USER_DATA_ERROR_TYPE type value + */ +T_USER_DATA_ERROR_TYPE dfu_get_user_data_info(IMG_ID image_id, + uint32_t *img_info, bool is_addr); + +/** End of DFU_COMMON_Exported_Functions + * @} + */ + +/** End of DFU_COMMON + * @} + */ + +#endif diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_bt_types.h b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_bt_types.h new file mode 100644 index 0000000000000..77923bcdee48e --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_bt_types.h @@ -0,0 +1,391 @@ +#include +#include + +#define APP_ERR 0x0D00 + +#define APP_SUCCESS 0x00 +#define APP_ERR_PENDING 0x01 +#define APP_ERR_ACCEPT 0x03 +#define APP_ERR_REJECT 0x04 +#define APP_ERR_NOT_RELEASE 0x05 + +/* Manufacturer specific error codes that are "missing" in GATT spec. >= 0xC0: */ +#define ATT_ERR_INVALID_CCC_BITS 0xC0 /**< Invalid client characteristic config bits. */ +#define ATT_ERR_INVALID_SIGNED_COUNT 0xC1 /**< Invalid sign count. */ +#define ATT_ERR_INVALID_SIGNED_MAC_FAILED 0xC2 /**< Invalid sign mac value. */ +#define ATT_ERR_MIN_APPLIC_CODE 0xC3 + +#define ATT_ERR 0x0400 + + +/** @brief APP Return Result List */ +typedef enum +{ + APP_RESULT_SUCCESS = (APP_SUCCESS), + APP_RESULT_PENDING = (APP_ERR | APP_ERR_PENDING), + APP_RESULT_ACCEPT = (APP_ERR | APP_ERR_ACCEPT), + APP_RESULT_REJECT = (APP_ERR | APP_ERR_REJECT), + APP_RESULT_NOT_RELEASE = (APP_ERR | APP_ERR_NOT_RELEASE), + + APP_RESULT_PREP_QUEUE_FULL = (ATT_ERR | BT_ATT_ERR_PREPARE_QUEUE_FULL), + APP_RESULT_INVALID_OFFSET = (ATT_ERR | BT_ATT_ERR_INVALID_OFFSET), + APP_RESULT_INVALID_VALUE_SIZE = (ATT_ERR | BT_ATT_ERR_INVALID_ATTRIBUTE_LEN), + APP_RESULT_INVALID_PDU = (ATT_ERR | BT_ATT_ERR_INVALID_PDU), + APP_RESULT_ATTR_NOT_FOUND = (ATT_ERR | BT_ATT_ERR_ATTRIBUTE_NOT_FOUND), + APP_RESULT_ATTR_NOT_LONG = (ATT_ERR | BT_ATT_ERR_ATTRIBUTE_NOT_LONG), + APP_RESULT_INSUFFICIENT_RESOURCES = (ATT_ERR | BT_ATT_ERR_INSUFFICIENT_RESOURCES), + APP_RESULT_VALUE_NOT_ALLOWED = (ATT_ERR | BT_ATT_ERR_VALUE_NOT_ALLOWED), + APP_RESULT_APP_ERR = (ATT_ERR | ATT_ERR_MIN_APPLIC_CODE), + APP_RESULT_CCCD_IMPROPERLY_CONFIGURED = (ATT_ERR | BT_ATT_ERR_CCC_IMPROPER_CONF), + APP_RESULT_PROC_ALREADY_IN_PROGRESS = (ATT_ERR | BT_ATT_ERR_PROCEDURE_IN_PROGRESS), +} T_APP_RESULT; + + +typedef uint8_t T_SERVER_ID; //!< Service ID + +/** Calculate integer bit count of b'1 */ +#define INT_BIT_COUNT(integer, count) { \ + count = 0; \ + while (integer) \ + { \ + count++; \ + integer &= integer - 1; \ + } \ + } + +/** Stream skip len */ +#define STREAM_SKIP_LEN(s, len) { \ + s += len; \ + } + +/** Stream to array */ +#define STREAM_TO_ARRAY(a, s, len) { \ + uint32_t ii; \ + for (ii = 0; ii < len; ii++) \ + { \ + *((uint8_t *)(a) + ii) = *s++; \ + } \ + } + +/** Array to stream */ +#define ARRAY_TO_STREAM(s, a, len) { \ + uint32_t ii; \ + for (ii = 0; ii < len; ii++) \ + { \ + *s++ = *((uint8_t *)(a) + ii); \ + } \ + } + +/** Little Endian stream to uint8 */ +#define LE_STREAM_TO_UINT8(u8, s) { \ + u8 = (uint8_t)(*s); \ + s += 1; \ + } + +/** Little Endian stream to uint16 */ +#define LE_STREAM_TO_UINT16(u16, s) { \ + u16 = ((uint16_t)(*(s + 0)) << 0) + \ + ((uint16_t)(*(s + 1)) << 8); \ + s += 2; \ + } + +/** Little Endian stream to uint24 */ +#define LE_STREAM_TO_UINT24(u24, s) { \ + u24 = ((uint32_t)(*(s + 0)) << 0) + \ + ((uint32_t)(*(s + 1)) << 8) + \ + ((uint32_t)(*(s + 2)) << 16); \ + s += 3; \ + } + +/** Little Endian stream to uint32 */ +#define LE_STREAM_TO_UINT32(u32, s) { \ + u32 = ((uint32_t)(*(s + 0)) << 0) + \ + ((uint32_t)(*(s + 1)) << 8) + \ + ((uint32_t)(*(s + 2)) << 16) + \ + ((uint32_t)(*(s + 3)) << 24); \ + s += 4; \ + } + +/** Little Endian stream to uint64 */ +#define LE_STREAM_TO_UINT64(u64, s) { \ + u64 = ((uint64_t)(*(s + 0)) << 0) + \ + ((uint64_t)(*(s + 1)) << 8) + \ + ((uint64_t)(*(s + 2)) << 16) + \ + ((uint64_t)(*(s + 3)) << 24) + \ + ((uint64_t)(*(s + 4)) << 32) + \ + ((uint64_t)(*(s + 5)) << 40) + \ + ((uint64_t)(*(s + 6)) << 48) + \ + ((uint64_t)(*(s + 7)) << 56); \ + s += 8; \ + } + +/** Little Endian uint8 to stream */ +#define LE_UINT8_TO_STREAM(s, u8) { \ + *s++ = (uint8_t)(u8); \ + } + +/** Little Endian uint16 to stream */ +#define LE_UINT16_TO_STREAM(s, u16) { \ + *s++ = (uint8_t)((u16) >> 0); \ + *s++ = (uint8_t)((u16) >> 8); \ + } + +/** Little Endian uint24 to stream */ +#define LE_UINT24_TO_STREAM(s, u24) { \ + *s++ = (uint8_t)((u24) >> 0); \ + *s++ = (uint8_t)((u24) >> 8); \ + *s++ = (uint8_t)((u24) >> 16); \ + } + +/** Little Endian uint32 to stream */ +#define LE_UINT32_TO_STREAM(s, u32) { \ + *s++ = (uint8_t)((u32) >> 0); \ + *s++ = (uint8_t)((u32) >> 8); \ + *s++ = (uint8_t)((u32) >> 16); \ + *s++ = (uint8_t)((u32) >> 24); \ + } + +/** Little Endian uint64 to stream */ +#define LE_UINT64_TO_STREAM(s, u64) { \ + *s++ = (uint8_t)((u64) >> 0); \ + *s++ = (uint8_t)((u64) >> 8); \ + *s++ = (uint8_t)((u64) >> 16); \ + *s++ = (uint8_t)((u64) >> 24); \ + *s++ = (uint8_t)((u64) >> 32); \ + *s++ = (uint8_t)((u64) >> 40); \ + *s++ = (uint8_t)((u64) >> 48); \ + *s++ = (uint8_t)((u64) >> 56); \ + } + +/** Little Endian array to uint8 */ +#define LE_ARRAY_TO_UINT8(u8, a) { \ + u8 = (uint8_t)(*(a + 0)); \ + } + +/** Little Endian array to uint16 */ +#define LE_ARRAY_TO_UINT16(u16, a) { \ + u16 = ((uint16_t)(*(a + 0)) << 0) + \ + ((uint16_t)(*(a + 1)) << 8); \ + } + +/** Little Endian array to uint24 */ +#define LE_ARRAY_TO_UINT24(u24, a) { \ + u24 = ((uint32_t)(*(a + 0)) << 0) + \ + ((uint32_t)(*(a + 1)) << 8) + \ + ((uint32_t)(*(a + 2)) << 16); \ + } + +/** Little Endian array to uint32 */ +#define LE_ARRAY_TO_UINT32(u32, a) { \ + u32 = ((uint32_t)(*(a + 0)) << 0) + \ + ((uint32_t)(*(a + 1)) << 8) + \ + ((uint32_t)(*(a + 2)) << 16) + \ + ((uint32_t)(*(a + 3)) << 24); \ + } + +/** Little Endian array to uint64 */ +#define LE_ARRAY_TO_UINT64(u64, a) { \ + u64 = ((uint64_t)(*(a + 0)) << 0) + \ + ((uint64_t)(*(a + 1)) << 8) + \ + ((uint64_t)(*(a + 2)) << 16) + \ + ((uint64_t)(*(a + 3)) << 24) + \ + ((uint64_t)(*(a + 4)) << 32) + \ + ((uint64_t)(*(a + 5)) << 40) + \ + ((uint64_t)(*(a + 6)) << 48) + \ + ((uint64_t)(*(a + 7)) << 56); \ + } + +/** Little Endian uint8 to array */ +#define LE_UINT8_TO_ARRAY(a, u8) { \ + *((uint8_t *)(a) + 0) = (uint8_t)(u8); \ + } + +/** Little Endian uint16 to array */ +#define LE_UINT16_TO_ARRAY(a, u16) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u16) >> 0); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u16) >> 8); \ + } + +/** Little Endian uint24 to array */ +#define LE_UINT24_TO_ARRAY(a, u24) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u24) >> 0); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u24) >> 8); \ + *((uint8_t *)(a) + 2) = (uint8_t)((u24) >> 16); \ + } + +/** Little Endian uint32 to array */ +#define LE_UINT32_TO_ARRAY(a, u32) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u32) >> 0); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u32) >> 8); \ + *((uint8_t *)(a) + 2) = (uint8_t)((u32) >> 16); \ + *((uint8_t *)(a) + 3) = (uint8_t)((u32) >> 24); \ + } + +/** Little Endian uint64 to array */ +#define LE_UINT64_TO_ARRAY(a, u64) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u64) >> 0); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u64) >> 8); \ + *((uint8_t *)(a) + 2) = (uint8_t)((u64) >> 16); \ + *((uint8_t *)(a) + 3) = (uint8_t)((u64) >> 24); \ + *((uint8_t *)(a) + 4) = (uint8_t)((u64) >> 32); \ + *((uint8_t *)(a) + 5) = (uint8_t)((u64) >> 40); \ + *((uint8_t *)(a) + 6) = (uint8_t)((u64) >> 48); \ + *((uint8_t *)(a) + 7) = (uint8_t)((u64) >> 56); \ + } + +/** Big Endian stream to uint8 */ +#define BE_STREAM_TO_UINT8(u8, s) { \ + u8 = (uint8_t)(*(s + 0)); \ + s += 1; \ + } + +/** Big Endian stream to uint16 */ +#define BE_STREAM_TO_UINT16(u16, s) { \ + u16 = ((uint16_t)(*(s + 0)) << 8) + \ + ((uint16_t)(*(s + 1)) << 0); \ + s += 2; \ + } + +/** Big Endian stream to uint24 */ +#define BE_STREAM_TO_UINT24(u24, s) { \ + u24 = ((uint32_t)(*(s + 0)) << 16) + \ + ((uint32_t)(*(s + 1)) << 8) + \ + ((uint32_t)(*(s + 2)) << 0); \ + s += 3; \ + } + +/** Big Endian stream to uint32 */ +#define BE_STREAM_TO_UINT32(u32, s) { \ + u32 = ((uint32_t)(*(s + 0)) << 24) + \ + ((uint32_t)(*(s + 1)) << 16) + \ + ((uint32_t)(*(s + 2)) << 8) + \ + ((uint32_t)(*(s + 3)) << 0); \ + s += 4; \ + } + +/** Big Endian stream to uint64 */ +#define BE_STREAM_TO_UINT64(u64, s) { \ + u64 = ((uint64_t)(*(s + 0)) << 56) + \ + ((uint64_t)(*(s + 1)) << 48) + \ + ((uint64_t)(*(s + 2)) << 40) + \ + ((uint64_t)(*(s + 3)) << 32) + \ + ((uint64_t)(*(s + 4)) << 24) + \ + ((uint64_t)(*(s + 5)) << 16) + \ + ((uint64_t)(*(s + 6)) << 8) + \ + ((uint64_t)(*(s + 7)) << 0); \ + s += 8; \ + } + +/** Big Endian uint8 to stream */ +#define BE_UINT8_TO_STREAM(s, u8) { \ + *s++ = (uint8_t)(u8); \ + } + +/** Big Endian uint16 to stream */ +#define BE_UINT16_TO_STREAM(s, u16) { \ + *s++ = (uint8_t)((u16) >> 8); \ + *s++ = (uint8_t)((u16) >> 0); \ + } + +/** Big Endian uint24 to stream */ +#define BE_UINT24_TO_STREAM(s, u24) { \ + *s++ = (uint8_t)((u24) >> 16); \ + *s++ = (uint8_t)((u24) >> 8); \ + *s++ = (uint8_t)((u24) >> 0); \ + } + +/** Big Endian uint32 to stream */ +#define BE_UINT32_TO_STREAM(s, u32) { \ + *s++ = (uint8_t)((u32) >> 24); \ + *s++ = (uint8_t)((u32) >> 16); \ + *s++ = (uint8_t)((u32) >> 8); \ + *s++ = (uint8_t)((u32) >> 0); \ + } + +/** Big Endian uint64 to stream */ +#define BE_UINT64_TO_STREAM(s, u64) { \ + *s++ = (uint8_t)((u64) >> 56); \ + *s++ = (uint8_t)((u64) >> 48); \ + *s++ = (uint8_t)((u64) >> 40); \ + *s++ = (uint8_t)((u64) >> 32); \ + *s++ = (uint8_t)((u64) >> 24); \ + *s++ = (uint8_t)((u64) >> 16); \ + *s++ = (uint8_t)((u64) >> 8); \ + *s++ = (uint8_t)((u64) >> 0); \ + } + +/** Big Endian array to uint8 */ +#define BE_ARRAY_TO_UINT8(u8, a) { \ + u8 = (uint8_t)(*(a + 0)); \ + } + +/** Big Endian array to uint16 */ +#define BE_ARRAY_TO_UINT16(u16, a) { \ + u16 = ((uint16_t)(*(a + 0)) << 8) + \ + ((uint16_t)(*(a + 1)) << 0); \ + } + +/** Big Endian array to uint24 */ +#define BE_ARRAY_TO_UINT24(u24, a) { \ + u24 = ((uint32_t)(*(a + 0)) << 16) + \ + ((uint32_t)(*(a + 1)) << 8) + \ + ((uint32_t)(*(a + 2)) << 0); \ + } + +/** Big Endian array to uint32 */ +#define BE_ARRAY_TO_UINT32(u32, a) { \ + u32 = ((uint32_t)(*(a + 0)) << 24) + \ + ((uint32_t)(*(a + 1)) << 16) + \ + ((uint32_t)(*(a + 2)) << 8) + \ + ((uint32_t)(*(a + 3)) << 0); \ + } + +/** Big Endian array to uint64 */ +#define BE_ARRAY_TO_UINT64(u64, a) { \ + u64 = ((uint64_t)(*(a + 0)) << 56) + \ + ((uint64_t)(*(a + 1)) << 48) + \ + ((uint64_t)(*(a + 2)) << 40) + \ + ((uint64_t)(*(a + 3)) << 32) + \ + ((uint64_t)(*(a + 4)) << 24) + \ + ((uint64_t)(*(a + 5)) << 16) + \ + ((uint64_t)(*(a + 6)) << 8) + \ + ((uint64_t)(*(a + 7)) << 0); \ + } + +/** Big Endian uint8 to array */ +#define BE_UINT8_TO_ARRAY(a, u8) { \ + *((uint8_t *)(a) + 0) = (uint8_t)(u8); \ + } + +/** Big Endian uint16 to array */ +#define BE_UINT16_TO_ARRAY(a, u16) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u16) >> 8); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u16) >> 0); \ + } + +/** Big Endian uint24 to array */ +#define BE_UINT24_TO_ARRAY(a, u24) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u24) >> 16); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u24) >> 8); \ + *((uint8_t *)(a) + 2) = (uint8_t)((u24) >> 0); \ + } + +/** Big Endian uint32 to array */ +#define BE_UINT32_TO_ARRAY(a, u32) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u32) >> 24); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u32) >> 16); \ + *((uint8_t *)(a) + 2) = (uint8_t)((u32) >> 8); \ + *((uint8_t *)(a) + 3) = (uint8_t)((u32) >> 0); \ + } + +/** Big Endian uint64 to array */ +#define BE_UINT64_TO_ARRAY(a, u64) { \ + *((uint8_t *)(a) + 0) = (uint8_t)((u64) >> 56); \ + *((uint8_t *)(a) + 1) = (uint8_t)((u64) >> 48); \ + *((uint8_t *)(a) + 2) = (uint8_t)((u64) >> 40); \ + *((uint8_t *)(a) + 3) = (uint8_t)((u64) >> 32); \ + *((uint8_t *)(a) + 4) = (uint8_t)((u64) >> 24); \ + *((uint8_t *)(a) + 5) = (uint8_t)((u64) >> 16); \ + *((uint8_t *)(a) + 6) = (uint8_t)((u64) >> 8); \ + *((uint8_t *)(a) + 7) = (uint8_t)((u64) >> 0); \ + } diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_dfu_service.c b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_dfu_service.c new file mode 100644 index 0000000000000..092c2dfb931fe --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_dfu_service.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + + +static void dfu_service_cccd_update_cb(const struct bt_gatt_attr *attr, + uint16_t value) +{ + ARG_UNUSED(attr); + + bool notif_enabled = (value & BT_GATT_CCC_NOTIFY); + + printk("dfu_cccd_update_cb Notifications %s\n", notif_enabled ? "enabled" : "disabled"); +} + +static ssize_t dfu_srv_write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + struct bt_uuid_128 *uuid = (struct bt_uuid_128 *) attr->uuid; + + T_APP_RESULT cause = APP_RESULT_SUCCESS; + T_DFU_CALLBACK_DATA callback_data; + + callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE; + if (uuid->val[13] == 0x63) { + callback_data.msg_data.write.write_attrib_index = INDEX_DFU_CHAR_DFU_PACKET_INDEX; + } else if (uuid->val[13] == 0x64) { + callback_data.msg_data.write.write_attrib_index = INDEX_DFU_CHAR_DFU_CONTROL_POINT_INDEX; + } + callback_data.msg_data.write.length = len; + callback_data.msg_data.write.p_value = (uint8_t *)buf; + + /* Notify Application. */ + callback_data.msg_data.write.opcode = DFU_WRITE_ATTR_ENTER; + + cause = app_dfu_srv_cb((void *)&callback_data); + + if (cause != APP_RESULT_SUCCESS) + { + return cause; + } + + if (uuid->val[13] == 0x63) { + ble_dfu_service_handle_packet(conn, len, (uint8_t *)buf); + } else if (uuid->val[13] == 0x64) { + ble_dfu_service_handle_cp_req(conn, len, (uint8_t *)buf); + } + + /* Notify Application. */ + callback_data.msg_data.write.opcode = DFU_WRITE_ATTR_EXIT; + + cause = app_dfu_srv_cb((void *)&callback_data); + + if (cause != APP_RESULT_SUCCESS) + { + return cause; + } + + return len; +} + +#define BT_UUID_RTK_DFU_SERVICE_VAL \ + BT_UUID_128_ENCODE(0x00006287, 0x3c17, 0xd293, 0x8e48, 0x14fe2e4da212) + +static struct bt_uuid_128 rtk_dfu_srv_uuid = BT_UUID_INIT_128( + BT_UUID_RTK_DFU_SERVICE_VAL); + +BT_GATT_SERVICE_DEFINE(rtk_dfu_service, + BT_GATT_PRIMARY_SERVICE(&rtk_dfu_srv_uuid), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_DFU_PACKET, BT_GATT_CHRC_WRITE_WITHOUT_RESP,BT_GATT_PERM_WRITE, NULL, dfu_srv_write_cb, NULL), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_DFU_CONTROL_POINT, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_WRITE, NULL, dfu_srv_write_cb, NULL), + BT_GATT_CCC(dfu_service_cccd_update_cb, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), +); + +void dfu_service_send_notification(struct bt_conn *conn, uint8_t *p_data, uint16_t data_len) +{ + bt_gatt_notify(conn, &rtk_dfu_service.attrs[4], p_data, data_len); +} \ No newline at end of file diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_dfu_service.h b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_dfu_service.h new file mode 100644 index 0000000000000..15462fa56efc4 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_dfu_service.h @@ -0,0 +1,165 @@ +/** +***************************************************************************************** +* Copyright(c) 2023, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file dfu_service.h + * @brief Head file for using OTA service + * @author Grace + * @date 2023-12-06 + * @version v1.1 + ************************************************************************************** + * @attention + *

© COPYRIGHT 2023 Realtek Semiconductor Corporation

+ ************************************************************************************** + */ + +/*============================================================================* + * Define to prevent recursive inclusion + *============================================================================*/ +#ifndef _DFU_SERVICE_H_ +#define _DFU_SERVICE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================* + * Header Files + *============================================================================*/ +//#include "app_msg.h" + +/** @defgroup DFU_SERVICE DFU Service + * @brief DFU Service to implement DFU feature + * @{ + */ +/*============================================================================* + * Macros + *============================================================================*/ +/** @defgroup DFU_SERVICE_Exported_Macros DFU service Exported Macros + * @brief + * @{ + */ +#define BLE_GATT_UUID128_DFU_SERVICE 0x12, 0xA2, 0x4D, 0x2E, 0xFE, 0x14, 0x48, 0x8e, 0x93, 0xD2, 0x17, 0x3C, 0x87, 0x62, 0x00, 0x00 +#define BLE_GATT_UUID128_DFU_PACKET 0x12, 0xA2, 0x4D, 0x2E, 0xFE, 0x14, 0x48, 0x8e, 0x93, 0xD2, 0x17, 0x3C, 0x87, 0x63, 0x00, 0x00 +#define BLE_GATT_UUID128_DFU_CONTROL_POINT 0x12, 0xA2, 0x4D, 0x2E, 0xFE, 0x14, 0x48, 0x8e, 0x93, 0xD2, 0x17, 0x3C, 0x87, 0x64, 0x00, 0x00 + +#define BT_UUID_CHAR_DFU_PACKET BT_UUID_DECLARE_128(BLE_GATT_UUID128_DFU_PACKET) +#define BT_UUID_CHAR_DFU_CONTROL_POINT BT_UUID_DECLARE_128(BLE_GATT_UUID128_DFU_CONTROL_POINT) + + +#define INDEX_DFU_CHAR_DFU_PACKET_INDEX 0x2 +#define INDEX_DFU_CHAR_DFU_CONTROL_POINT_INDEX 0x4 +#define INDEX_DFU_CHAR_DFU_CP_CCCD_INDEX 0x5 + + +#define DFU_CP_NOTIFY_ENABLE 0x1 +#define DFU_CP_NOTIFY_DISABLE 0x2 + +/** End of DFU_SERVICE_Exported_Macros + * @} + */ + +/*============================================================================* + * Types + *============================================================================*/ +/** @defgroup DFU_SERVICE_Exported_Types DFU Service Exported Types + * @brief + * @{ + */ + +typedef enum +{ + DFU_FAIL_UPDATE_FLASH, + DFU_FAIL_SYSTEM_RESET_CMD, + DFU_FAIL_EXCEED_MAX_BUFFER_SIZE, + DFU_FAIL_EXCEED_IMG_TOTAL_LEN, +} T_DFU_FAIL_REASON; + + +typedef enum +{ + DFU_WRITE_ATTR_ENTER, + DFU_WRITE_ATTR_EXIT, + DFU_WRITE_START, + DFU_WRITE_DOING, + DFU_WRITE_END, + DFU_WRITE_FAIL, +} T_DFU_WRITE_OPCODE; + + +typedef struct +{ + uint8_t opcode; + uint8_t write_attrib_index; + uint16_t length; + uint8_t *p_value; +} T_DFU_WRITE_MSG; + +/** @brief OTA upstream message data */ +typedef union +{ + uint8_t notification_indification_index; + T_DFU_WRITE_MSG write; +} T_DFU_UPSTREAM_MSG_DATA; + +/** @brief Event type to inform app*/ +typedef enum +{ + SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION = 1, /**< CCCD update event. */ + SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE = 2, /**< client read event. */ + SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE = 3, /**< client write event. */ +} T_SERVICE_CALLBACK_TYPE; + +/** Dfu service data to inform application */ +typedef struct +{ + T_SERVICE_CALLBACK_TYPE msg_type; + uint8_t conn_id; +#if F_APP_GATT_SERVER_EXT_API_SUPPORT + uint16_t conn_handle;//gatt extend api? conn_handle?cid + uint16_t cid; +#endif + T_DFU_UPSTREAM_MSG_DATA msg_data; +} T_DFU_CALLBACK_DATA; + +/** End of DFU_SERVICE_Exported_Types + * @} + */ + +/*============================================================================* + * Functions + *============================================================================*/ +/** @defgroup DFU_SERVICE_Exported_Functions DFU service Exported Functions + * @brief + * @{ + */ + +/** + * @brief Add DFU BLE service to application + * @param p_func Pointer of APP callback function called by profile + * @return A T_SERVER_ID type value, Service ID auto generated by profile layer + */ +// T_SERVER_ID dfu_add_service(void *p_func); + +/** + * @brief Send notification to peer side + * @param conn_id PID to identify the connection + * @param p_data value to be send to peer + * @param data_len data length of the value to be send + * @return void + */ +void dfu_service_send_notification(struct bt_conn *conn, uint8_t *p_data, uint16_t data_len); + +/** End of DFU_SERVICE_Exported_Functions + * @} + */ + +/** End of DFU_SERVICE + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_app_layer.c b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_app_layer.c new file mode 100644 index 0000000000000..44cf273eb3087 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_app_layer.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include + +#include +#include + +T_APP_RESULT app_dfu_srv_cb(T_DFU_CALLBACK_DATA *p_data) +{ + T_APP_RESULT app_result = APP_RESULT_SUCCESS; + switch (p_data->msg_type) + { + case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION: + { + if (p_data->msg_data.notification_indification_index == DFU_CP_NOTIFY_ENABLE) + { + printk("dfu notification enable"); + } + else if (p_data->msg_data.notification_indification_index == + DFU_CP_NOTIFY_DISABLE) + { + printk("dfu notification disable"); + } + } + break; + case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE: + { + uint8_t dfu_write_opcode = p_data->msg_data.write.opcode; + if (dfu_write_opcode == DFU_WRITE_ATTR_EXIT) + { + if (p_data->msg_data.write.write_attrib_index == INDEX_DFU_CHAR_DFU_CONTROL_POINT_INDEX) + { + uint8_t control_point_opcode = *p_data->msg_data.write.p_value; + switch (control_point_opcode) + { + case DFU_OPCODE_VALID_FW: + { +// T_IO_MSG dfu_valid_fw_msg; +// dfu_valid_fw_msg.type = IO_MSG_TYPE_DFU_VALID_FW; +// dfu_valid_fw_msg.u.param = p_data->conn_id; +// if (app_send_msg_to_apptask(&dfu_valid_fw_msg) == false) +// { +// DBG_DIRECT("DFU send Valid FW msg fail!"); +// } + } + break; + case DFU_OPCODE_ACTIVE_IMAGE_RESET: + { +#if (ENABLE_AUTO_BANK_SWITCH == 1) +// if (is_ota_support_bank_switch()) +// { +// uint32_t ota_addr; +// ota_addr = get_header_addr_by_img_id(IMG_OTA); +// DFU_PRINT_INFO1("DFU_OPCODE_ACTIVE_IMAGE_RESET: Bank switch erase ota_addr=0x%x", ota_addr); +// unlock_flash_bp_all(); +// flash_nor_erase_locked(ota_addr, FLASH_NOR_ERASE_SECTOR); +// lock_flash_bp(); +// } +#endif +// le_disconnect(0); +// app_dfu_active_rst_pending = true; + } + break; + default: + break; + } + } + } + else if (dfu_write_opcode == DFU_WRITE_FAIL) + { + printk("DFU FAIL!\n"); + } + else if (dfu_write_opcode == DFU_WRITE_ATTR_ENTER) + { + // application can add check conditions before start dfu procefure + //if check fail, return some error code except APP_RESULT_SUCCESS to exit dfu procedure + //app_result = APP_RESULT_REJECT; + //APP_PRINT_INFO0("exit dfu procedure"); + } + else + { + } + } + break; + default: + break; + } + + return app_result; +} \ No newline at end of file diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_app_layer.h b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_app_layer.h new file mode 100644 index 0000000000000..94062e559e52c --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_app_layer.h @@ -0,0 +1,4 @@ +#include +#include + +T_APP_RESULT app_dfu_srv_cb(T_DFU_CALLBACK_DATA *p_data); \ No newline at end of file diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_bt.c b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_bt.c new file mode 100644 index 0000000000000..79ba62b1f2471 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_bt.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "rtk_ota_service.h" +#include "wdt.h" +#include "ble_dfu_transport.h" +#include "dfu_common.h" + +#include +LOG_MODULE_REGISTER(rtk_ota_bt); + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("In rtk_ota_bt, Disconnected (reason 0x%02x)\n", reason); + + if ((reason != BT_HCI_ERR_LOCALHOST_TERM_CONN) && reason != BT_HCI_ERR_REMOTE_USER_TERM_CONN) { + LOG_ERR("connection lost: cause 0x%x", reason); + } + + if (dfu_switch_to_ota_mode_pending) { +#if (SUPPORT_NORMAL_OTA == 1) + dfu_switch_to_ota_mode_pending = false; + dfu_switch_to_ota_mode(); +#endif + } else { + if (dfu_active_reset_pending) { + printk("OTA APP Active reset...."); + dfu_active_reset_pending = false; + +#if (ENABLE_AUTO_BANK_SWITCH == 1) + if (is_ota_support_bank_switch()) { + uint32_t ota_addr; + ota_addr = get_header_addr_by_img_id(IMG_OTA); + DBG_DIRECT("FOR QC Test: Bank switch Erase OTA Header=0x%x", ota_addr); + fmc_flash_nor_erase(ota_addr, FMC_FLASH_NOR_ERASE_SECTOR); + } +#endif + //unlock_flash_bp_all(); //GRACE TO CHECK + dfu_fw_reboot(RESET_ALL, DFU_ACTIVE_RESET); + } else { + /* do nothing. BT would start adv automatically.*/ + } + } +} + +BT_CONN_CB_DEFINE(rtk_ota_bt_callbacks) = { + .disconnected = disconnected, +}; + diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_service.c b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_service.c new file mode 100644 index 0000000000000..d7155d273b1bf --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_service.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(ota_service); + +static uint8_t mac_addr[12]={0}; +static DEVICE_INFO device_info; +static uint8_t img_ver[IMG_INFO_LEN]; +static uint16_t protocol_info = BLE_PROTOCOL_INFO; +static uint8_t section_size[SECTION_SIZE_LEN]; + +static ssize_t enter_ota_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + struct bt_uuid_16 *uuid = (struct bt_uuid_16 *) attr->uuid; + LOG_INF("OTA SERVICE, UUID: 0x%x",uuid->val); + + if ((len != sizeof(uint8_t)) || (buf == NULL)) + { + return APP_RESULT_INVALID_VALUE_SIZE; + } + + uint8_t *value = (uint8_t *)buf; + + /* Notify Application. */ + if (OTA_VALUE_ENTER == value[0]) + { + /*battery level is above 60 percent*/ + printk("Preparing switch into OTA mode"); + /*prepare to enter OTA mode, before switch action, we should disconnect first.*/ + dfu_switch_to_ota_mode_pending = true; + //le_disconnect(p_data->conn_id);//replace with zephyr + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);//will connect automatically after disconnecting. + } + + return len; +} + +static ssize_t mac_address_read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + struct bt_uuid_16 *uuid = (struct bt_uuid_16 *) attr->uuid; + LOG_INF("OTA SERVICE, UUID: 0x%x",uuid->val); + + bt_addr_le_t addr = {0}; + size_t count = 1; + + bt_id_get(&addr, &count); + + for (int i = 0; i < 6; i++) { + mac_addr[i] = addr.a.val[5-i]; + mac_addr[i+6] = addr.a.val[5-i]; + } + + const uint8_t *value = attr->user_data; + + LOG_HEXDUMP_INF(value, sizeof(mac_addr), "Read Results:"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(mac_addr)); +} + +static ssize_t device_info_read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + struct bt_uuid_16 *uuid = (struct bt_uuid_16 *) attr->uuid; + LOG_INF("OTA SERVICE, UUID: 0x%x",uuid->val); + + ble_dfu_get_device_info(conn, &device_info); + + const DEVICE_INFO *value = attr->user_data; + + LOG_HEXDUMP_INF(value, sizeof(DEVICE_INFO), "Read Results:"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(DEVICE_INFO)); +} + +static ssize_t image_version_first_read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + struct bt_uuid_16 *uuid = (struct bt_uuid_16 *) attr->uuid; + LOG_INF("OTA SERVICE, UUID: 0x%x",uuid->val); + + img_ver[0] = ACTIVE_BANK; + ble_dfu_get_img_version(&img_ver[1], img_ver[0]); + + const uint8_t *value = attr->user_data; + + LOG_INF("version length=%d", img_ver[1] * 6 + 2); + + LOG_HEXDUMP_INF(value, img_ver[1] * 6 + 2, "Read Results:"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + img_ver[1] * 6 + 2); +} + +static ssize_t protocol_info_read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + struct bt_uuid_16 *uuid = (struct bt_uuid_16 *) attr->uuid; + LOG_INF("OTA SERVICE: UUID: 0x%x",uuid->val); + + const uint8_t *value = attr->user_data; + + LOG_HEXDUMP_INF(value, sizeof(uint16_t), "Read Results:"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(uint16_t)); +} + +static ssize_t section_size_read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + struct bt_uuid_16 *uuid = (struct bt_uuid_16 *) attr->uuid; + LOG_INF("OTA SERVICE: UUID: 0x%x",uuid->val); + + ble_dfu_get_section_size(section_size); + + const uint8_t *value = attr->user_data; + + LOG_HEXDUMP_INF(value, section_size[0] * 6 +1, "Read Results:"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + section_size[0] * 6 +1); +} + + +#define BT_UUID_RTK_OTA_SERVICE_VAL \ + BT_UUID_128_ENCODE(0x0000d0ff, 0x3c17, 0xd293, 0x8e48, 0x14fe2e4da212) + +static struct bt_uuid_128 rtk_ota_srv_uuid = BT_UUID_INIT_128( + BT_UUID_RTK_OTA_SERVICE_VAL); + +BT_GATT_SERVICE_DEFINE(rtk_ota_service, + BT_GATT_PRIMARY_SERVICE(&rtk_ota_srv_uuid), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_OTA, BT_GATT_CHRC_WRITE_WITHOUT_RESP,BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, enter_ota_cb, NULL), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_MAC, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, mac_address_read_cb, NULL, mac_addr), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_DEVICE_INFO, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, device_info_read_cb, NULL, &device_info), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_IMAGE_VERSION_FIRST, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, image_version_first_read_cb, NULL, img_ver), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_PROTOCOL_INFO, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, protocol_info_read_cb, NULL, &protocol_info), + BT_GATT_CHARACTERISTIC(BT_UUID_CHAR_SECTION_SIZE_FIRST, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, section_size_read_cb, NULL, section_size), +); diff --git a/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_service.h b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_service.h new file mode 100644 index 0000000000000..486b25430fe25 --- /dev/null +++ b/soc/arm/realtek_bee/rtl87x2g/ota_src/rtk_ota_service.h @@ -0,0 +1,55 @@ +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief OTA Write callback data type definition. */ +#define OTA_WRITE_CHAR_VAL 0x01 +#define OTA_VALUE_ENTER 0x01 + +/** @brief Demo Profile service related UUIDs. */ +#define GATT_UUID_CHAR_OTA 0xFFD1 +#define GATT_UUID_CHAR_MAC 0xFFD2 +#define GATT_UUID_CHAR_PATCH_VERSION 0xFFD3 +#define GATT_UUID_CHAR_APP_VERSION 0xFFD4 +#define GATT_UUID_CHAR_IMAGE_VERSION_FIRST 0xFFE0 +#define GATT_UUID_CHAR_IMAGE_VERSION_SECOND 0xFFE1 +#define GATT_UUID_CHAR_DEVICE_INFO 0xFFF1 +#define GATT_UUID_CHAR_PROTOCOL_INFO 0xFFF3 +#define GATT_UUID_CHAR_SECTION_SIZE_FIRST 0xFFF4 +#define GATT_UUID_CHAR_SECTION_SIZE_SECOND 0xFFF5 + + +#define BT_UUID_CHAR_OTA \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_OTA) + +#define BT_UUID_CHAR_MAC \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_MAC) + +#define BT_UUID_CHAR_PATCH_VERSION \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_PATCH_VERSION) + +#define BT_UUID_CHAR_APP_VERSION \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_APP_VERSION) + +#define BT_UUID_CHAR_DEVICE_INFO \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_DEVICE_INFO) + +#define BT_UUID_CHAR_IMAGE_VERSION_FIRST \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_IMAGE_VERSION_FIRST) + +#define BT_UUID_CHAR_IMAGE_VERSION_SECOND \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_IMAGE_VERSION_SECOND) + +#define BT_UUID_CHAR_PROTOCOL_INFO \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_PROTOCOL_INFO) + +#define BT_UUID_CHAR_SECTION_SIZE_FIRST \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_SECTION_SIZE_FIRST) + +#define BT_UUID_CHAR_SECTION_SIZE_SECOND \ + BT_UUID_DECLARE_16(GATT_UUID_CHAR_SECTION_SIZE_SECOND) + + +#ifdef __cplusplus +} +#endif