From b79b781067d81094917ee9a08fec69e2483ecdfa Mon Sep 17 00:00:00 2001 From: pankore <86098180+pankore@users.noreply.github.com> Date: Mon, 24 Jan 2022 21:03:12 +0800 Subject: [PATCH] [Ameba] Support OTA requestor app (#13408) * [Ameba] Support OTA requestor app * [Ameba] Remove unwanted ota files and apply minor updates * Fix restyled errors * Update wordlist * Update OTA requestor chipinterface * Fix BLE commissioning issue due to CASESession fail * Add OTAR to all-clusters-app and lighting-app * Fix restyled error * Replace term 'otar' to 'ota_requestor' * Update QueryImage and ApplyUpdate command in chipinterface Fix bug in SystemTimeSupport.cpp * Fix restyled errors * Replace term 'otar' to 'ota_requestor' --- config/ameba/chip.cmake | 7 + .../all-clusters-app/ameba/chip_main.cmake | 18 + .../ameba/main/chipinterface.cpp | 61 ++- .../ameba/main/include/LEDWidget.h | 125 +----- examples/lighting-app/ameba/chip_main.cmake | 18 + .../lighting-app/ameba/main/chipinterface.cpp | 61 ++- examples/ota-requestor-app/ameba/README.md | 62 +++ .../ota-requestor-app/ameba/chip_main.cmake | 96 +++++ .../ameba/main/CHIPDeviceManager.cpp | 92 ++++ .../ameba/main/DeviceCallbacks.cpp | 168 ++++++++ .../ota-requestor-app/ameba/main/Globals.cpp | 22 + .../ameba/main/LEDWidget.cpp | 60 +++ .../ameba/main/chipinterface.cpp | 142 +++++++ .../ameba/main/include/CHIPDeviceManager.h | 125 ++++++ .../ameba/main/include/DeviceCallbacks.h | 45 ++ .../ameba/main/include/Globals.h | 24 ++ .../ameba/main/include/LEDWidget.h | 281 +++++++++++++ .../ameba/third_party/connectedhomeip | 1 + src/platform/Ameba/AmebaOTAImageProcessor.cpp | 398 ++++++++++++++++++ src/platform/Ameba/AmebaOTAImageProcessor.h | 88 ++++ src/platform/Ameba/BUILD.gn | 9 +- src/platform/Ameba/PlatformManagerImpl.cpp | 6 + src/platform/Ameba/SystemTimeSupport.cpp | 52 ++- src/platform/Ameba/SystemTimeSupport.h | 29 ++ 24 files changed, 1841 insertions(+), 149 deletions(-) mode change 100755 => 100644 examples/lighting-app/ameba/main/chipinterface.cpp create mode 100644 examples/ota-requestor-app/ameba/README.md create mode 100644 examples/ota-requestor-app/ameba/chip_main.cmake create mode 100644 examples/ota-requestor-app/ameba/main/CHIPDeviceManager.cpp create mode 100644 examples/ota-requestor-app/ameba/main/DeviceCallbacks.cpp create mode 100644 examples/ota-requestor-app/ameba/main/Globals.cpp create mode 100644 examples/ota-requestor-app/ameba/main/LEDWidget.cpp create mode 100644 examples/ota-requestor-app/ameba/main/chipinterface.cpp create mode 100644 examples/ota-requestor-app/ameba/main/include/CHIPDeviceManager.h create mode 100644 examples/ota-requestor-app/ameba/main/include/DeviceCallbacks.h create mode 100644 examples/ota-requestor-app/ameba/main/include/Globals.h create mode 100644 examples/ota-requestor-app/ameba/main/include/LEDWidget.h create mode 100644 examples/ota-requestor-app/ameba/third_party/connectedhomeip create mode 100644 src/platform/Ameba/AmebaOTAImageProcessor.cpp create mode 100644 src/platform/Ameba/AmebaOTAImageProcessor.h create mode 100644 src/platform/Ameba/SystemTimeSupport.h diff --git a/config/ameba/chip.cmake b/config/ameba/chip.cmake index b7986d5d1a6f53..fa0258dd497fd2 100644 --- a/config/ameba/chip.cmake +++ b/config/ameba/chip.cmake @@ -103,6 +103,7 @@ string(APPEND CHIP_GN_ARGS "ameba_cxx = \"arm-none-eabi-c++\"\n") string(APPEND CHIP_GN_ARGS "ameba_cpu = \"ameba\"\n") # Build RPC +if (matter_enable_rpc) #string(APPEND CHIP_GN_ARGS "remove_default_configs = [\"//third_party/connectedhomeip/third_party/pigweed/repo/pw_build:cpp17\"]\n") string(APPEND CHIP_GN_ARGS "chip_build_pw_rpc_lib = true\n") string(APPEND CHIP_GN_ARGS "pw_log_BACKEND = \"//third_party/connectedhomeip/third_party/pigweed/repo/pw_log_basic\"\n") @@ -110,6 +111,12 @@ string(APPEND CHIP_GN_ARGS "pw_assert_BACKEND = \"//third_party/connectedhomeip/ string(APPEND CHIP_GN_ARGS "pw_sys_io_BACKEND = \"//third_party/connectedhomeip/examples/platform/ameba/pw_sys_io:pw_sys_io_ameba\"\n") string(APPEND CHIP_GN_ARGS "dir_pw_third_party_nanopb = \"//third_party/connectedhomeip/third_party/nanopb/repo\"\n") string(APPEND CHIP_GN_ARGS "pw_build_LINK_DEPS = [\"//third_party/connectedhomeip/third_party/pigweed/repo/pw_assert:impl\", \"//third_party/connectedhomeip/third_party/pigweed/repo/pw_log:impl\"]\n") +endif (matter_enable_rpc) + +# Build ota-requestor +if (matter_enable_ota_requestor) +string(APPEND CHIP_GN_ARGS "chip_enable_ota_requestor = true\n") +endif (matter_enable_ota_requestor) file(GENERATE OUTPUT ${CHIP_OUTPUT}/args.gn CONTENT ${CHIP_GN_ARGS}) diff --git a/examples/all-clusters-app/ameba/chip_main.cmake b/examples/all-clusters-app/ameba/chip_main.cmake index cb86b9f8b23d34..752571498d2a8e 100755 --- a/examples/all-clusters-app/ameba/chip_main.cmake +++ b/examples/all-clusters-app/ameba/chip_main.cmake @@ -112,6 +112,16 @@ list( ) endif (matter_enable_rpc) +if (matter_enable_ota_requestor) +list( + APPEND ${list_chip_main_sources} + #OTARequestor + ${chip_dir}/src/app/clusters/ota-requestor/BDXDownloader.cpp + ${chip_dir}/src/app/clusters/ota-requestor/OTARequestor.cpp + ${chip_dir}/src/app/clusters/ota-requestor/ota-requestor-server.cpp +) +endif (matter_enable_ota_requestor) + list( APPEND ${list_chip_main_sources} @@ -229,6 +239,14 @@ list( ) endif (matter_enable_rpc) +if (matter_enable_ota_requestor) +list( + APPEND chip_main_flags + + -DCONFIG_ENABLE_OTA_REQUESTOR=1 +) +endif (matter_enable_ota_requestor) + list( APPEND chip_main_cpp_flags diff --git a/examples/all-clusters-app/ameba/main/chipinterface.cpp b/examples/all-clusters-app/ameba/main/chipinterface.cpp index c5d0071dd12ade..6e4ecb8ef62dd7 100644 --- a/examples/all-clusters-app/ameba/main/chipinterface.cpp +++ b/examples/all-clusters-app/ameba/main/chipinterface.cpp @@ -36,6 +36,13 @@ #include #include +#if CONFIG_ENABLE_OTA_REQUESTOR +#include "app/clusters/ota-requestor/BDXDownloader.h" +#include "app/clusters/ota-requestor/OTARequestor.h" +#include "platform/Ameba/AmebaOTAImageProcessor.h" +#include "platform/GenericOTARequestorDriver.h" +#endif + #if CONFIG_ENABLE_PW_RPC #include "Rpc.h" #endif @@ -44,6 +51,7 @@ using namespace ::chip; using namespace ::chip::Credentials; using namespace ::chip::DeviceManager; using namespace ::chip::DeviceLayer; +using namespace ::chip::System; Identify gIdentify0 = { chip::EndpointId{ 0 }, @@ -72,6 +80,13 @@ Identify gIdentify1 = { static DeviceCallbacks EchoCallbacks; +#if CONFIG_ENABLE_OTA_REQUESTOR +OTARequestor gRequestorCore; +GenericOTARequestorDriver gRequestorUser; +BDXDownloader gDownloader; +AmebaOTAImageProcessor gImageProcessor; +#endif + void GetGatewayIP(char * ip_buf, size_t ip_len) { uint8_t * gateway = LwIP_GetGW(&xnetif[0]); @@ -185,6 +200,47 @@ std::string createSetupPayload() return result; }; +#if CONFIG_ENABLE_OTA_REQUESTOR +extern "C" void amebaQueryImageCmdHandler(uint32_t nodeId, uint32_t fabricId) +{ + ChipLogProgress(DeviceLayer, "Calling amebaQueryImageCmdHandler"); + // In this mode Provider node ID and fabric idx must be supplied explicitly from ATS$ cmd + gRequestorCore.TestModeSetProviderParameters(nodeId, fabricId, chip::kRootEndpointId); + + static_cast(GetRequestorInstance())->TriggerImmediateQuery(); +} + +extern "C" void amebaApplyUpdateCmdHandler() +{ + ChipLogProgress(DeviceLayer, "Calling amebaApplyUpdateCmdHandler"); + + static_cast(GetRequestorInstance())->ApplyUpdate(); +} + +static void InitOTARequestor(void) +{ + // Initialize and interconnect the Requestor and Image Processor objects -- START + SetRequestorInstance(&gRequestorCore); + + // Set server instance used for session establishment + gRequestorCore.Init(&(chip::Server::GetInstance()), &gRequestorUser, &gDownloader); + + // WARNING: this is probably not realistic to know such details of the image or to even have an OTADownloader instantiated at + // the beginning of program execution. We're using hardcoded values here for now since this is a reference application. + // TODO: instatiate and initialize these values when QueryImageResponse tells us an image is available + // TODO: add API for OTARequestor to pass QueryImageResponse info to the application to use for OTADownloader init + OTAImageProcessorParams ipParams; + gImageProcessor.SetOTAImageProcessorParams(ipParams); + gImageProcessor.SetOTADownloader(&gDownloader); + + // Connect the Downloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&gImageProcessor); + gRequestorUser.Init(&gRequestorCore, &gImageProcessor); + + // Initialize and interconnect the Requestor and Image Processor objects -- END +} +#endif // CONFIG_ENABLE_OTA_REQUESTOR + extern "C" void ChipTest(void) { ChipLogProgress(DeviceLayer, "All Clusters Demo!"); @@ -229,8 +285,9 @@ extern "C" void ChipTest(void) statusLED1.Init(STATUS_LED_GPIO_NUM); - while (true) - vTaskDelay(pdMS_TO_TICKS(50)); +#if CONFIG_ENABLE_OTA_REQUESTOR + InitOTARequestor(); +#endif } bool lowPowerClusterSleep() diff --git a/examples/all-clusters-app/ameba/main/include/LEDWidget.h b/examples/all-clusters-app/ameba/main/include/LEDWidget.h index 53459a3628c22c..9f1456daa7492d 100755 --- a/examples/all-clusters-app/ameba/main/include/LEDWidget.h +++ b/examples/all-clusters-app/ameba/main/include/LEDWidget.h @@ -21,132 +21,9 @@ #include #ifdef CONFIG_PLATFORM_8710C +#include "gpio_api.h" #include "rtl8710c_pin_name.h" -typedef struct hal_gpio_pin_adapter_s -{ - uint8_t pin_name; ///< chip pin name to locate the GPIO pin by port & pin index - uint8_t port_idx; ///< the GPIO IP port index of the GPIO pin - uint8_t pin_idx; ///< the GPIO IP pin index of the GPIO port - uint8_t debounce_idx; ///< the index of GPIO debounce function allocated to this GPIO pin, 0 ~ 15 - uint32_t bit_mask; ///< the bit mask to read/write register - - volatile uint32_t * in_port; ///< the IN port address - volatile uint32_t * out0_port; ///< the OUT port address for write 0 - volatile uint32_t * out1_port; ///< the OUT port address for write 1 - volatile uint32_t * outt_port; ///< the OUT port address for toggling -} hal_gpio_adapter_t, *phal_gpio_adapter_t; - -typedef enum -{ - PIN_INPUT = 0, - PIN_OUTPUT -} PinDirection; - -typedef enum -{ - PA_0 = PIN_A0, - PA_1 = PIN_A1, - PA_2 = PIN_A2, - PA_3 = PIN_A3, - PA_4 = PIN_A4, - PA_5 = PIN_A5, - PA_6 = PIN_A6, - PA_7 = PIN_A7, - PA_8 = PIN_A8, - PA_9 = PIN_A9, - PA_10 = PIN_A10, - PA_11 = PIN_A11, - PA_12 = PIN_A12, - PA_13 = PIN_A13, - PA_14 = PIN_A14, - PA_15 = PIN_A15, - PA_16 = PIN_A16, - PA_17 = PIN_A17, - PA_18 = PIN_A18, - PA_19 = PIN_A19, - PA_20 = PIN_A20, - PA_21 = PIN_A21, - PA_22 = PIN_A22, - PA_23 = PIN_A23, - - PB_0 = PIN_B0, - PB_1 = PIN_B1, - PB_2 = PIN_B2, - PB_3 = PIN_B3, - PB_4 = PIN_B4, - PB_5 = PIN_B5, - PB_6 = PIN_B6, - PB_7 = PIN_B7, - PB_8 = PIN_B8, - PB_9 = PIN_B9, - PB_10 = PIN_B10, - PB_11 = PIN_B11, - PB_12 = PIN_B12, - - // Arduino connector namings - /* - A0 = PA_0, - A1 = PA_1, - A2 = PA_4, - A3 = PB_0, - A4 = PC_1, - A5 = PC_0, - D0 = PA_3, - D1 = PA_2, - D2 = PA_10, - D3 = PB_3, - D4 = PB_5, - D5 = PB_4, - D6 = PB_10, - D7 = PA_8, - D8 = PA_9, - D9 = PC_7, - D10 = PB_6, - D11 = PA_7, - D12 = PA_6, - D13 = PA_5, - D14 = PB_9, - D15 = PB_8, - */ - - // Generic signals namings - /* - LED1 = PB_4, - LED2 = PB_5, - LED3 = PB_6, - LED4 = PB_7, - USER_BUTTON = PA_3, - SERIAL_TX = PA_7, - SERIAL_RX = PA_6, - USBTX = PA_7, - USBRX = PA_6, - I2C_SCL = PC_5, - I2C_SDA = PC_4, - SPI_MOSI = PC_2, - SPI_MISO = PC_3, - SPI_SCK = PC_1, - SPI_CS = PC_0, - PWM_OUT = PD_4, - */ - // Not connected - NC = (uint32_t) 0xFFFFFFFF -} PinName; - -typedef enum -{ - PullNone = 0, - PullUp = 1, - PullDown = 2, - OpenDrain = 3, - PullDefault = PullNone -} PinMode; - -struct gpio_s -{ - hal_gpio_adapter_t adapter; -}; - #else typedef enum diff --git a/examples/lighting-app/ameba/chip_main.cmake b/examples/lighting-app/ameba/chip_main.cmake index 38b08742a0b5fe..31731d1a34d354 100755 --- a/examples/lighting-app/ameba/chip_main.cmake +++ b/examples/lighting-app/ameba/chip_main.cmake @@ -10,6 +10,16 @@ set(list_chip_main_sources chip_main_sources) include(${prj_root}/GCC-RELEASE/project_hp/asdk/includepath.cmake) +if (matter_enable_ota_requestor) +list( + APPEND ${list_chip_main_sources} + #OTARequestor + ${chip_dir}/src/app/clusters/ota-requestor/BDXDownloader.cpp + ${chip_dir}/src/app/clusters/ota-requestor/OTARequestor.cpp + ${chip_dir}/src/app/clusters/ota-requestor/ota-requestor-server.cpp +) +endif (matter_enable_ota_requestor) + list( APPEND ${list_chip_main_sources} @@ -73,6 +83,14 @@ list( -DMBEDTLS_CONFIG_FILE= ) +if (matter_enable_ota_requestor) +list( + APPEND chip_main_flags + + -DCONFIG_ENABLE_OTA_REQUESTOR=1 +) +endif (matter_enable_ota_requestor) + list( APPEND chip_main_cpp_flags diff --git a/examples/lighting-app/ameba/main/chipinterface.cpp b/examples/lighting-app/ameba/main/chipinterface.cpp old mode 100755 new mode 100644 index 6c9536c23fd2c9..0aff78c4743001 --- a/examples/lighting-app/ameba/main/chipinterface.cpp +++ b/examples/lighting-app/ameba/main/chipinterface.cpp @@ -38,10 +38,18 @@ #include +#if CONFIG_ENABLE_OTA_REQUESTOR +#include "app/clusters/ota-requestor/BDXDownloader.h" +#include "app/clusters/ota-requestor/OTARequestor.h" +#include "platform/Ameba/AmebaOTAImageProcessor.h" +#include "platform/GenericOTARequestorDriver.h" +#endif + using namespace ::chip; using namespace ::chip::Credentials; using namespace ::chip::DeviceManager; using namespace ::chip::DeviceLayer; +using namespace ::chip::System; #define QRCODE_BASE_URL "https://dhrishi.github.io/connectedhomeip/qrcode.html" #define EXAMPLE_VENDOR_TAG_IP 1 @@ -56,6 +64,13 @@ using namespace ::chip::DeviceLayer; static DeviceCallbacks EchoCallbacks; +#if CONFIG_ENABLE_OTA_REQUESTOR +OTARequestor gRequestorCore; +GenericOTARequestorDriver gRequestorUser; +BDXDownloader gDownloader; +AmebaOTAImageProcessor gImageProcessor; +#endif + void GetGatewayIP(char * ip_buf, size_t ip_len) { uint8_t * gateway = LwIP_GetGW(&xnetif[0]); @@ -169,6 +184,47 @@ std::string createSetupPayload() return result; }; +#if CONFIG_ENABLE_OTA_REQUESTOR +extern "C" void amebaQueryImageCmdHandler(uint32_t nodeId, uint32_t fabricId) +{ + ChipLogProgress(DeviceLayer, "Calling amebaQueryImageCmdHandler"); + // In this mode Provider node ID and fabric idx must be supplied explicitly from ATS$ cmd + gRequestorCore.TestModeSetProviderParameters(nodeId, fabricId, chip::kRootEndpointId); + + static_cast(GetRequestorInstance())->TriggerImmediateQuery(); +} + +extern "C" void amebaApplyUpdateCmdHandler() +{ + ChipLogProgress(DeviceLayer, "Calling amebaApplyUpdateCmdHandler"); + + static_cast(GetRequestorInstance())->ApplyUpdate(); +} + +static void InitOTARequestor(void) +{ + // Initialize and interconnect the Requestor and Image Processor objects -- START + SetRequestorInstance(&gRequestorCore); + + // Set server instance used for session establishment + gRequestorCore.Init(&(chip::Server::GetInstance()), &gRequestorUser, &gDownloader); + + // WARNING: this is probably not realistic to know such details of the image or to even have an OTADownloader instantiated at + // the beginning of program execution. We're using hardcoded values here for now since this is a reference application. + // TODO: instatiate and initialize these values when QueryImageResponse tells us an image is available + // TODO: add API for OTARequestor to pass QueryImageResponse info to the application to use for OTADownloader init + OTAImageProcessorParams ipParams; + gImageProcessor.SetOTAImageProcessorParams(ipParams); + gImageProcessor.SetOTADownloader(&gDownloader); + + // Connect the Downloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&gImageProcessor); + gRequestorUser.Init(&gRequestorCore, &gImageProcessor); + + // Initialize and interconnect the Requestor and Image Processor objects -- END +} +#endif // CONFIG_ENABLE_OTA_REQUESTOR + void OnIdentifyStart(Identify *) { ChipLogProgress(Zcl, "OnIdentifyStart"); @@ -246,8 +302,9 @@ extern "C" void ChipTest(void) statusLED1.Init(STATUS_LED_GPIO_NUM); - while (true) - vTaskDelay(pdMS_TO_TICKS(50)); +#if CONFIG_ENABLE_OTA_REQUESTOR + InitOTARequestor(); +#endif } bool lowPowerClusterSleep() diff --git a/examples/ota-requestor-app/ameba/README.md b/examples/ota-requestor-app/ameba/README.md new file mode 100644 index 00000000000000..ef132c1acdb37f --- /dev/null +++ b/examples/ota-requestor-app/ameba/README.md @@ -0,0 +1,62 @@ +# CHIP Ameba OTA Requestor Example + +A prototype application that demonstrates OTA Requestor capabilities. + +## Building the Example Application + +- Pull docker image: + + $ docker pull pankore/chip-build-ameba:latest + +- Run docker container: + + $ docker run -it -v ${CHIP_DIR}:/root/chip pankore/chip-build-ameba:latest + +- Setup build environment: + + $ source ./scripts/bootstrap.sh + +- To build the demo application: + + $ ./scripts/build/build_examples.py --target ameba-amebad-ota-requestor build + + The output image files are stored in + `out/ameba-amebad-ota-requestor/asdk/image` folder. + + The bootloader image files are stored in + `out/ameba-amebad-ota-requestor/asdk/bootloader` folder. + +- After building the application, **Ameba Image Tool** is used to flash it to + Ameba board. + +1. Connect your device via USB and open Ameba Image Tool. +2. Select correct serial port and set baudrate as **115200**. +3. Browse and add the corresponding image files in the Flash Download list to + the correct locations +4. Click **Download** button. + +## Testing the Example Application + +Launch the linux [ota-provider-app](../../ota-provider-app/linux) and provide +the SW_IMAGE_FILE + + $ ./chip-ota-provider-app -f ${SW_IMAGE_FILE} + +Commission the ota-provider-app using +[chip-tool](https://github.com/project-chip/connectedhomeip/tree/master/examples/chip-tool) + + $ ./chip-tool pairing onnetwork 1 20202021 + +Input `ATS$` command to start the CHIP ota-requestor task, then use chip-tool to +commission it + + $ ./chip-tool pairing ble-wifi 2 20202021 3840 + +After commissioning the ota-requestor, use the chip-tool to announce the +ota-provider-app to start the OTA process + + $ ./chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 2 0 + +The OTA process should include downloading the image, verification of image +header, erasing upgraded flash partition, writing to flash and checksum +verification diff --git a/examples/ota-requestor-app/ameba/chip_main.cmake b/examples/ota-requestor-app/ameba/chip_main.cmake new file mode 100644 index 00000000000000..eae13963755f71 --- /dev/null +++ b/examples/ota-requestor-app/ameba/chip_main.cmake @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.6) + +project(chip_main) + +set(chip_dir "${ameba_matter_root}") +set(chip_dir_output "${matter_output_path}/chip") +set(dir "${sdk_root}/component/common/api") +set(chip_main chip_main) +set(list_chip_main_sources chip_main_sources) + +include(${prj_root}/GCC-RELEASE/project_hp/asdk/includepath.cmake) + +list( + APPEND ${list_chip_main_sources} + + ${chip_dir}/zzz_generated/ota-requestor-app/zap-generated/callback-stub.cpp + ${chip_dir}/zzz_generated/ota-requestor-app/zap-generated/IMClusterCommandHandler.cpp + ${chip_dir}/zzz_generated/ota-requestor-app/zap-generated/CHIPClusters.cpp + ${chip_dir}/zzz_generated/ota-requestor-app/zap-generated/CHIPClientCallbacks.cpp + + ${chip_dir}/examples/ota-requestor-app/ameba/main/chipinterface.cpp + ${chip_dir}/examples/ota-requestor-app/ameba/main/Globals.cpp + ${chip_dir}/examples/ota-requestor-app/ameba/main/LEDWidget.cpp + ${chip_dir}/examples/ota-requestor-app/ameba/main/CHIPDeviceManager.cpp + ${chip_dir}/examples/ota-requestor-app/ameba/main/DeviceCallbacks.cpp + + ${chip_dir}/src/app/clusters/ota-requestor/BDXDownloader.cpp + ${chip_dir}/src/app/clusters/ota-requestor/OTARequestor.cpp + ${chip_dir}/src/app/clusters/ota-requestor/ota-requestor-server.cpp + ${chip_dir}/src/app/util/im-client-callbacks.cpp +) + +add_library( + ${chip_main} + STATIC + ${chip_main_sources} +) + +chip_configure_data_model(chip_main + INCLUDE_SERVER + ZAP_FILE ${matter_example_path}/../ota-requestor-common/ota-requestor-app.zap +) + +target_include_directories( + ${chip_main} + PUBLIC + ${inc_path} + ${chip_dir}/zzz_generated/ota-requestor-app + ${chip_dir}/zzz_generated/app-common + ${chip_dir}/zzz_generated + ${chip_dir_output}/gen/include + ${chip_dir}/src/include/ + ${chip_dir}/src/lib/ + ${chip_dir}/src/ + ${chip_dir}/third_party/nlassert/repo/include/ + ${chip_dir}/src/app/ + ${chip_dir}/src/app/util/ + ${chip_dir}/src/app/server/ + ${chip_dir}/src/controller/data_model + ${chip_dir}/third_party/nlio/repo/include/ + ${chip_dir}/third_party/nlunit-test/repo/src + + ${chip_dir}/src/app/clusters/ota-requestor + ${chip_dir}/examples/ota-requestor-app/ameba/main/include + + ${sdk_root}/component/soc/realtek/amebad/fwlib/include +) + +list( + APPEND chip_main_flags + + -DINET_CONFIG_ENABLE_IPV4=1 + -DCHIP_PROJECT=1 + -DCHIP_DEVICE_LAYER_TARGET=Ameba + -DUSE_ZAP_CONFIG + -DCHIP_HAVE_CONFIG_H + -DMBEDTLS_CONFIG_FILE= +) + +list( + APPEND chip_main_cpp_flags + + -Wno-unused-parameter + -std=gnu++11 + -std=c++14 + -fno-rtti +) +target_compile_definitions(${chip_main} PRIVATE ${chip_main_flags} ) +target_compile_options(${chip_main} PRIVATE ${chip_main_cpp_flags}) + +# move static library post build command +add_custom_command( + TARGET ${chip_main} + POST_BUILD + COMMAND cp lib${chip_main}.a ${CMAKE_CURRENT_SOURCE_DIR}/lib/application +) diff --git a/examples/ota-requestor-app/ameba/main/CHIPDeviceManager.cpp b/examples/ota-requestor-app/ameba/main/CHIPDeviceManager.cpp new file mode 100644 index 00000000000000..2a2d964b5d6614 --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/CHIPDeviceManager.cpp @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file implements the CHIP Device Interface that is used by + * applications to interact with the CHIP stack + * + */ + +#include + +#include "CHIPDeviceManager.h" +#include +#include +#include +#include +#include + +using namespace ::chip; + +namespace chip { + +namespace DeviceManager { + +using namespace ::chip::DeviceLayer; + +void CHIPDeviceManager::CommonDeviceEventHandler(const ChipDeviceEvent * event, intptr_t arg) +{ + CHIPDeviceManagerCallbacks * cb = reinterpret_cast(arg); + if (cb != nullptr) + { + cb->DeviceEventCallback(event, reinterpret_cast(cb)); + } +} + +CHIP_ERROR CHIPDeviceManager::Init(CHIPDeviceManagerCallbacks * cb) +{ + CHIP_ERROR err; + mCB = cb; + + // Initialize the CHIP stack. + err = PlatformMgr().InitChipStack(); + SuccessOrExit(err); + + if (CONFIG_NETWORK_LAYER_BLE) + { + ConnectivityMgr().SetBLEAdvertisingEnabled(true); + } + + err = Platform::MemoryInit(); + SuccessOrExit(err); + + // Register a function to receive events from the CHIP device layer. Note that calls to + // this function will happen on the CHIP event loop thread, not the app_main thread. + PlatformMgr().AddEventHandler(CHIPDeviceManager::CommonDeviceEventHandler, reinterpret_cast(cb)); + + // Start a task to run the CHIP Device event loop. + err = PlatformMgr().StartEventLoopTask(); + SuccessOrExit(err); + +exit: + return err; +} +} // namespace DeviceManager +} // namespace chip + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & path, uint8_t mask, uint8_t type, uint16_t size, + uint8_t * value) +{ + chip::DeviceManager::CHIPDeviceManagerCallbacks * cb = + chip::DeviceManager::CHIPDeviceManager::GetInstance().GetCHIPDeviceManagerCallbacks(); + if (cb != nullptr) + { + cb->PostAttributeChangeCallback(path.mEndpointId, path.mClusterId, path.mAttributeId, mask, type, size, value); + } +} diff --git a/examples/ota-requestor-app/ameba/main/DeviceCallbacks.cpp b/examples/ota-requestor-app/ameba/main/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..5ff6b6713d4ed3 --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/DeviceCallbacks.cpp @@ -0,0 +1,168 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" + +#include "CHIPDeviceManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Globals.h" +#include "LEDWidget.h" + +static const char * TAG = "app-devicecallbacks"; + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; + +uint32_t identifyTimerCount; +constexpr uint32_t kIdentifyTimerDelayMS = 250; + +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kSessionEstablished: + OnSessionEstablished(event); + break; + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t mask, + uint8_t type, uint16_t size, uint8_t * value) +{ + switch (clusterId) + { + case ZCL_ON_OFF_CLUSTER_ID: + OnOnOffPostAttributeChangeCallback(endpointId, attributeId, value); + break; + + case ZCL_IDENTIFY_CLUSTER_ID: + OnIdentifyPostAttributeChangeCallback(endpointId, attributeId, value); + break; + + default: + break; + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "Server ready at: %s:%d", event->InternetConnectivityChange.address, CHIP_PORT); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} + +void DeviceCallbacks::OnSessionEstablished(const ChipDeviceEvent * event) +{ + if (event->SessionEstablished.IsCommissioner) + { + ChipLogProgress(DeviceLayer, "Commissioner detected!"); + } +} + +void DeviceCallbacks::OnOnOffPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == ZCL_ON_OFF_ATTRIBUTE_ID, + ChipLogError(DeviceLayer, TAG, "Unhandled Attribute ID: '0x%04x", attributeId)); + VerifyOrExit(endpointId == 1 || endpointId == 2, + ChipLogError(DeviceLayer, TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId)); + + // At this point we can assume that value points to a bool value. + statusLED1.Set(*value); + +exit: + return; +} + +void IdentifyTimerHandler(Layer * systemLayer, void * appState, CHIP_ERROR error) +{ + if (identifyTimerCount) + { + identifyTimerCount--; + } +} + +void DeviceCallbacks::OnIdentifyPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == ZCL_IDENTIFY_TIME_ATTRIBUTE_ID, + ChipLogError(DeviceLayer, "[%s] Unhandled Attribute ID: '0x%04x", TAG, attributeId)); + VerifyOrExit(endpointId == 1, ChipLogError(DeviceLayer, "[%s] Unexpected EndPoint ID: `0x%02x'", TAG, endpointId)); + + // timerCount represents the number of callback executions before we stop the timer. + // value is expressed in seconds and the timer is fired every 250ms, so just multiply value by 4. + // Also, we want timerCount to be odd number, so the ligth state ends in the same state it starts. + identifyTimerCount = (*value) * 4; +exit: + return; +} + +bool emberAfBasicClusterMfgSpecificPingCallback(chip::app::CommandHandler * commandObj) +{ + emberAfSendDefaultResponse(emberAfCurrentCommand(), EMBER_ZCL_STATUS_SUCCESS); + return true; +} diff --git a/examples/ota-requestor-app/ameba/main/Globals.cpp b/examples/ota-requestor-app/ameba/main/Globals.cpp new file mode 100644 index 00000000000000..8534ca34dfcf25 --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/Globals.cpp @@ -0,0 +1,22 @@ + +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Globals.h" + +LEDWidget statusLED1; diff --git a/examples/ota-requestor-app/ameba/main/LEDWidget.cpp b/examples/ota-requestor-app/ameba/main/LEDWidget.cpp new file mode 100644 index 00000000000000..a050f4a4d4f0f0 --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/LEDWidget.cpp @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file LEDWidget.cpp + * + * Implements an LED Widget controller that is usually tied to a GPIO + * It also updates the display widget if it's enabled + */ + +#include "LEDWidget.h" + +gpio_t gpio_led; + +void LEDWidget::Init(PinName gpioNum) +{ + + mGPIONum = gpioNum; + mState = false; + + if (gpioNum != (PinName) NC) + { + // Init LED control pin + gpio_init(&gpio_led, gpioNum); + gpio_dir(&gpio_led, PIN_OUTPUT); // Direction: Output + gpio_mode(&gpio_led, PullNone); // No pull + gpio_write(&gpio_led, mState); + } +} + +void LEDWidget::Set(bool state) +{ + DoSet(state); +} + +void LEDWidget::DoSet(bool state) +{ + bool stateChange = (mState != state); + mState = state; + + if (stateChange) + { + gpio_write(&gpio_led, state); + } +} diff --git a/examples/ota-requestor-app/ameba/main/chipinterface.cpp b/examples/ota-requestor-app/ameba/main/chipinterface.cpp new file mode 100644 index 00000000000000..bdff13a45b0ee1 --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/chipinterface.cpp @@ -0,0 +1,142 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "chip_porting.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "app/clusters/ota-requestor/BDXDownloader.h" +#include "app/clusters/ota-requestor/OTARequestor.h" +#include "platform/Ameba/AmebaOTAImageProcessor.h" +#include "platform/GenericOTARequestorDriver.h" + +void * __dso_handle = 0; + +using chip::AmebaOTAImageProcessor; +using chip::BDXDownloader; +using chip::ByteSpan; +using chip::EndpointId; +using chip::FabricIndex; +using chip::GetRequestorInstance; +using chip::NodeId; +using chip::OnDeviceConnected; +using chip::OnDeviceConnectionFailure; +using chip::OTADownloader; +using chip::OTAImageProcessorParams; +using chip::OTARequestor; +using chip::PeerId; +using chip::Server; +using chip::VendorId; +using chip::Callback::Callback; +using chip::System::Layer; +using chip::Transport::PeerAddress; +using namespace chip::Messaging; +using namespace chip::app::Clusters::OtaSoftwareUpdateProvider::Commands; + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; + +static DeviceCallbacks EchoCallbacks; + +OTARequestor gRequestorCore; +GenericOTARequestorDriver gRequestorUser; +BDXDownloader gDownloader; +AmebaOTAImageProcessor gImageProcessor; + +extern "C" void amebaQueryImageCmdHandler(uint32_t nodeId, uint32_t fabricId) +{ + ChipLogProgress(DeviceLayer, "Calling amebaQueryImageCmdHandler"); + // In this mode Provider node ID and fabric idx must be supplied explicitly from ATS$ cmd + gRequestorCore.TestModeSetProviderParameters(nodeId, fabricId, chip::kRootEndpointId); + + static_cast(GetRequestorInstance())->TriggerImmediateQuery(); +} + +extern "C" void amebaApplyUpdateCmdHandler() +{ + ChipLogProgress(DeviceLayer, "Calling amebaApplyUpdateCmdHandler"); + + static_cast(GetRequestorInstance())->ApplyUpdate(); +} + +static void InitOTARequestor(void) +{ + // Initialize and interconnect the Requestor and Image Processor objects -- START + SetRequestorInstance(&gRequestorCore); + + // Set server instance used for session establishment + gRequestorCore.Init(&(chip::Server::GetInstance()), &gRequestorUser, &gDownloader); + + // WARNING: this is probably not realistic to know such details of the image or to even have an OTADownloader instantiated at + // the beginning of program execution. We're using hardcoded values here for now since this is a reference application. + // TODO: instatiate and initialize these values when QueryImageResponse tells us an image is available + // TODO: add API for OTARequestor to pass QueryImageResponse info to the application to use for OTADownloader init + OTAImageProcessorParams ipParams; + gImageProcessor.SetOTAImageProcessorParams(ipParams); + gImageProcessor.SetOTADownloader(&gDownloader); + + // Connect the Downloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&gImageProcessor); + gRequestorUser.Init(&gRequestorCore, &gImageProcessor); + + // Initialize and interconnect the Requestor and Image Processor objects -- END +} + +extern "C" void ChipTest(void) +{ + ChipLogProgress(SoftwareUpdate, "ota-requestor!"); + CHIP_ERROR err = CHIP_NO_ERROR; + + initPref(); + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + err = deviceMgr.Init(&EchoCallbacks); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "DeviceManagerInit() - ERROR!\r\n"); + } + else + { + ChipLogProgress(DeviceLayer, "DeviceManagerInit() - OK\r\n"); + } + + chip::Server::GetInstance().Init(); + + // Initialize device attestation config + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + + InitOTARequestor(); + + while (true) + vTaskDelay(pdMS_TO_TICKS(50)); + +exit: + ChipLogProgress(SoftwareUpdate, "Exited"); + return; +} diff --git a/examples/ota-requestor-app/ameba/main/include/CHIPDeviceManager.h b/examples/ota-requestor-app/ameba/main/include/CHIPDeviceManager.h new file mode 100644 index 00000000000000..97002717225d1a --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/include/CHIPDeviceManager.h @@ -0,0 +1,125 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file contains definitions for the CHIP DeviceManager Interface + * + * This object will co-ordinate multiple activities such as + * initialisation, rendezvous, session mgmt and other such + * activities within the CHIP stack. This is a singleton object. + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include + +#include "af-types.h" + +namespace chip { +namespace DeviceManager { + +/** + * @brief + * This class provides a skeleton for all the callback functions. The functions will be + * called by other objects within the CHIP stack for specific events. + * Applications interested in receiving specific callbacks can specialize this class and handle + * these events in their implementation of this class. + */ +class CHIPDeviceManagerCallbacks +{ +public: + /** + * @brief + * Called when CHIP Device events (PublicEventTypes) are triggered. + * + * @param event ChipDeviceEvent that occurred + * @param arg arguments specific to the event, if any + */ + virtual void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg) {} + + /** + * @brief + * Called after an attribute has been changed + * + * @param endpoint endpoint id + * @param clusterID cluster id + * @param attributeId attribute id that was changed + * @param mask mask of the attribute + * @param manufacturerCode manufacturer code + * @param type attribute type + * @param size size of the attribute + * @param value pointer to the new value + */ + virtual void PostAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t mask, uint8_t type, uint16_t size, uint8_t * value) + {} + virtual ~CHIPDeviceManagerCallbacks() {} +}; + +/** + * @brief + * A common class that drives other components of the CHIP stack + */ +class DLL_EXPORT CHIPDeviceManager +{ +public: + CHIPDeviceManager(const CHIPDeviceManager &) = delete; + CHIPDeviceManager(const CHIPDeviceManager &&) = delete; + CHIPDeviceManager & operator=(const CHIPDeviceManager &) = delete; + + static CHIPDeviceManager & GetInstance() + { + static CHIPDeviceManager instance; + return instance; + } + + /** + * @brief + * Initialise CHIPDeviceManager + * + * @param cb Application's instance of the CHIPDeviceManagerCallbacks for consuming events + */ + CHIP_ERROR Init(CHIPDeviceManagerCallbacks * cb); + + /** + * @brief + * Fetch a pointer to the registered CHIPDeviceManagerCallbacks object. + * + */ + CHIPDeviceManagerCallbacks * GetCHIPDeviceManagerCallbacks() { return mCB; } + + /** + * Use internally for registration of the ChipDeviceEvents + */ + static void CommonDeviceEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + +private: + CHIPDeviceManagerCallbacks * mCB = nullptr; + CHIPDeviceManager() {} +}; + +} // namespace DeviceManager +} // namespace chip diff --git a/examples/ota-requestor-app/ameba/main/include/DeviceCallbacks.h b/examples/ota-requestor-app/ameba/main/include/DeviceCallbacks.h new file mode 100644 index 00000000000000..10ac917c02890a --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/include/DeviceCallbacks.h @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg) override; + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t mask, uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); + void OnSessionEstablished(const chip::DeviceLayer::ChipDeviceEvent * event); + void OnOnOffPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); + void OnIdentifyPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); +}; diff --git a/examples/ota-requestor-app/ameba/main/include/Globals.h b/examples/ota-requestor-app/ameba/main/include/Globals.h new file mode 100644 index 00000000000000..b39b6fb4afb140 --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/include/Globals.h @@ -0,0 +1,24 @@ + +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "LEDWidget.h" + +extern LEDWidget statusLED1; diff --git a/examples/ota-requestor-app/ameba/main/include/LEDWidget.h b/examples/ota-requestor-app/ameba/main/include/LEDWidget.h new file mode 100644 index 00000000000000..53459a3628c22c --- /dev/null +++ b/examples/ota-requestor-app/ameba/main/include/LEDWidget.h @@ -0,0 +1,281 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef CONFIG_PLATFORM_8710C +#include "rtl8710c_pin_name.h" + +typedef struct hal_gpio_pin_adapter_s +{ + uint8_t pin_name; ///< chip pin name to locate the GPIO pin by port & pin index + uint8_t port_idx; ///< the GPIO IP port index of the GPIO pin + uint8_t pin_idx; ///< the GPIO IP pin index of the GPIO port + uint8_t debounce_idx; ///< the index of GPIO debounce function allocated to this GPIO pin, 0 ~ 15 + uint32_t bit_mask; ///< the bit mask to read/write register + + volatile uint32_t * in_port; ///< the IN port address + volatile uint32_t * out0_port; ///< the OUT port address for write 0 + volatile uint32_t * out1_port; ///< the OUT port address for write 1 + volatile uint32_t * outt_port; ///< the OUT port address for toggling +} hal_gpio_adapter_t, *phal_gpio_adapter_t; + +typedef enum +{ + PIN_INPUT = 0, + PIN_OUTPUT +} PinDirection; + +typedef enum +{ + PA_0 = PIN_A0, + PA_1 = PIN_A1, + PA_2 = PIN_A2, + PA_3 = PIN_A3, + PA_4 = PIN_A4, + PA_5 = PIN_A5, + PA_6 = PIN_A6, + PA_7 = PIN_A7, + PA_8 = PIN_A8, + PA_9 = PIN_A9, + PA_10 = PIN_A10, + PA_11 = PIN_A11, + PA_12 = PIN_A12, + PA_13 = PIN_A13, + PA_14 = PIN_A14, + PA_15 = PIN_A15, + PA_16 = PIN_A16, + PA_17 = PIN_A17, + PA_18 = PIN_A18, + PA_19 = PIN_A19, + PA_20 = PIN_A20, + PA_21 = PIN_A21, + PA_22 = PIN_A22, + PA_23 = PIN_A23, + + PB_0 = PIN_B0, + PB_1 = PIN_B1, + PB_2 = PIN_B2, + PB_3 = PIN_B3, + PB_4 = PIN_B4, + PB_5 = PIN_B5, + PB_6 = PIN_B6, + PB_7 = PIN_B7, + PB_8 = PIN_B8, + PB_9 = PIN_B9, + PB_10 = PIN_B10, + PB_11 = PIN_B11, + PB_12 = PIN_B12, + + // Arduino connector namings + /* + A0 = PA_0, + A1 = PA_1, + A2 = PA_4, + A3 = PB_0, + A4 = PC_1, + A5 = PC_0, + D0 = PA_3, + D1 = PA_2, + D2 = PA_10, + D3 = PB_3, + D4 = PB_5, + D5 = PB_4, + D6 = PB_10, + D7 = PA_8, + D8 = PA_9, + D9 = PC_7, + D10 = PB_6, + D11 = PA_7, + D12 = PA_6, + D13 = PA_5, + D14 = PB_9, + D15 = PB_8, + */ + + // Generic signals namings + /* + LED1 = PB_4, + LED2 = PB_5, + LED3 = PB_6, + LED4 = PB_7, + USER_BUTTON = PA_3, + SERIAL_TX = PA_7, + SERIAL_RX = PA_6, + USBTX = PA_7, + USBRX = PA_6, + I2C_SCL = PC_5, + I2C_SDA = PC_4, + SPI_MOSI = PC_2, + SPI_MISO = PC_3, + SPI_SCK = PC_1, + SPI_CS = PC_0, + PWM_OUT = PD_4, + */ + // Not connected + NC = (uint32_t) 0xFFFFFFFF +} PinName; + +typedef enum +{ + PullNone = 0, + PullUp = 1, + PullDown = 2, + OpenDrain = 3, + PullDefault = PullNone +} PinMode; + +struct gpio_s +{ + hal_gpio_adapter_t adapter; +}; + +#else + +typedef enum +{ + PORT_A = 0, + PORT_B = 1, +} GPIO_PORT; + +typedef enum +{ + PIN_INPUT = 0, + PIN_OUTPUT +} PinDirection; + +typedef enum +{ + PullNone = 0, // IN HIGHZ + PullUp = 1, + PullDown = 2, + PullDefault = PullNone +} PinMode; + +/* (((port)<<5)|(pin)) */ +typedef enum +{ + PA_0 = (PORT_A << 5 | 0), + PA_1 = (PORT_A << 5 | 1), + PA_2 = (PORT_A << 5 | 2), + PA_3 = (PORT_A << 5 | 3), + PA_4 = (PORT_A << 5 | 4), + PA_5 = (PORT_A << 5 | 5), + PA_6 = (PORT_A << 5 | 6), + PA_7 = (PORT_A << 5 | 7), + PA_8 = (PORT_A << 5 | 8), + PA_9 = (PORT_A << 5 | 9), + PA_10 = (PORT_A << 5 | 10), + PA_11 = (PORT_A << 5 | 11), + PA_12 = (PORT_A << 5 | 12), + PA_13 = (PORT_A << 5 | 13), + PA_14 = (PORT_A << 5 | 14), + PA_15 = (PORT_A << 5 | 15), + PA_16 = (PORT_A << 5 | 16), + PA_17 = (PORT_A << 5 | 17), + PA_18 = (PORT_A << 5 | 18), + PA_19 = (PORT_A << 5 | 19), + PA_20 = (PORT_A << 5 | 20), + PA_21 = (PORT_A << 5 | 21), + PA_22 = (PORT_A << 5 | 22), + PA_23 = (PORT_A << 5 | 23), + PA_24 = (PORT_A << 5 | 24), + PA_25 = (PORT_A << 5 | 25), + PA_26 = (PORT_A << 5 | 26), + PA_27 = (PORT_A << 5 | 27), + PA_28 = (PORT_A << 5 | 28), + PA_29 = (PORT_A << 5 | 29), + PA_30 = (PORT_A << 5 | 30), + PA_31 = (PORT_A << 5 | 31), + + PB_0 = (PORT_B << 5 | 0), + PB_1 = (PORT_B << 5 | 1), + PB_2 = (PORT_B << 5 | 2), + PB_3 = (PORT_B << 5 | 3), + PB_4 = (PORT_B << 5 | 4), + PB_5 = (PORT_B << 5 | 5), + PB_6 = (PORT_B << 5 | 6), + PB_7 = (PORT_B << 5 | 7), + PB_8 = (PORT_B << 5 | 8), + PB_9 = (PORT_B << 5 | 9), + PB_10 = (PORT_B << 5 | 10), + PB_11 = (PORT_B << 5 | 11), + PB_12 = (PORT_B << 5 | 12), + PB_13 = (PORT_B << 5 | 13), + PB_14 = (PORT_B << 5 | 14), + PB_15 = (PORT_B << 5 | 15), + PB_16 = (PORT_B << 5 | 16), + PB_17 = (PORT_B << 5 | 17), + PB_18 = (PORT_B << 5 | 18), + PB_19 = (PORT_B << 5 | 19), + PB_20 = (PORT_B << 5 | 20), + PB_21 = (PORT_B << 5 | 21), + PB_22 = (PORT_B << 5 | 22), + PB_23 = (PORT_B << 5 | 23), + PB_24 = (PORT_B << 5 | 24), + PB_25 = (PORT_B << 5 | 25), + PB_26 = (PORT_B << 5 | 26), + PB_27 = (PORT_B << 5 | 27), + PB_28 = (PORT_B << 5 | 28), + PB_29 = (PORT_B << 5 | 29), + PB_30 = (PORT_B << 5 | 30), + PB_31 = (PORT_B << 5 | 31), + + VBAT_MEAS = (0x7 << 5 | 2), + AD_0 = PB_4, // CH0 + AD_1 = PB_5, // CH1 + AD_2 = PB_6, // CH2 + AD_3 = PB_7, // CH3 + AD_4 = PB_1, // CH4 + AD_5 = PB_2, // CH5 + AD_6 = PB_3, // CH6 + AD_7 = VBAT_MEAS, // CH7 + + // Not connected + NC = (uint32_t) 0xFFFFFFFF +} PinName; + +typedef struct gpio_s +{ + PinName pin; +} gpio_t; + +#endif + +typedef struct gpio_s gpio_t; + +extern "C" void gpio_init(gpio_t * obj, PinName pin); +extern "C" uint32_t gpio_set(PinName pin); +extern "C" void gpio_mode(gpio_t * obj, PinMode mode); +extern "C" void gpio_dir(gpio_t * obj, PinDirection direction); +extern "C" void gpio_write(gpio_t * obj, int value); +extern "C" int gpio_read(gpio_t * obj); + +class LEDWidget +{ +public: + void Init(PinName gpioNum); + void Set(bool state); + +private: + PinName mGPIONum; + bool mState; + void DoSet(bool state); +}; diff --git a/examples/ota-requestor-app/ameba/third_party/connectedhomeip b/examples/ota-requestor-app/ameba/third_party/connectedhomeip new file mode 100644 index 00000000000000..4e0b7219502094 --- /dev/null +++ b/examples/ota-requestor-app/ameba/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ diff --git a/src/platform/Ameba/AmebaOTAImageProcessor.cpp b/src/platform/Ameba/AmebaOTAImageProcessor.cpp new file mode 100644 index 00000000000000..706559912021ad --- /dev/null +++ b/src/platform/Ameba/AmebaOTAImageProcessor.cpp @@ -0,0 +1,398 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#if defined(CONFIG_PLATFORM_8710C) +static flash_t flash_ota; +#endif + +namespace chip { + +CHIP_ERROR AmebaOTAImageProcessor::PrepareDownload() +{ + ChipLogProgress(SoftwareUpdate, "Prepare download"); + + DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaOTAImageProcessor::Finalize() +{ + ChipLogProgress(SoftwareUpdate, "Finalize"); + + DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaOTAImageProcessor::Apply() +{ + ChipLogProgress(SoftwareUpdate, "Apply"); + + DeviceLayer::PlatformMgr().ScheduleWork(HandleApply, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaOTAImageProcessor::Abort() +{ + ChipLogProgress(SoftwareUpdate, "Abort"); + + DeviceLayer::PlatformMgr().ScheduleWork(HandleAbort, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaOTAImageProcessor::ProcessBlock(ByteSpan & block) +{ + ChipLogProgress(SoftwareUpdate, "Process Block"); + + if ((block.data() == nullptr) || block.empty()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + CHIP_ERROR err = SetBlock(block); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +void AmebaOTAImageProcessor::HandlePrepareDownload(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + + // Get OTA update partition +#if defined(CONFIG_PLATFORM_8721D) + if (ota_get_cur_index() == OTA_INDEX_1) + imageProcessor->ota_target_index = OTA_INDEX_2; + else if (ota_get_cur_index() == OTA_INDEX_2) + imageProcessor->ota_target_index = OTA_INDEX_1; + ChipLogProgress(SoftwareUpdate, "OTA%d address space will be upgraded", imageProcessor->ota_target_index + 1); +#elif defined(CONFIG_PLATFORM_8710C) + imageProcessor->flash_addr = sys_update_ota_prepare_addr(); + ChipLogProgress(SoftwareUpdate, "New Flash Address: 0x%X", imageProcessor->flash_addr); +#endif + + imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); +} + +void AmebaOTAImageProcessor::HandleFinalize(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + + // Verify checksum +#if defined(CONFIG_PLATFORM_8721D) + if (verify_ota_checksum(imageProcessor->pOtaTgtHdr) != 1) + { + ChipLogError(SoftwareUpdate, "OTA checksum verification failed"); + return; + } +#endif + + // Update signature +#if defined(CONFIG_PLATFORM_8721D) + if (change_ota_signature(imageProcessor->pOtaTgtHdr, imageProcessor->ota_target_index) != 1) + { + ChipLogError(SoftwareUpdate, "OTA update signature failed"); + return; + } +#elif defined(CONFIG_PLATFORM_8710C) + if (update_ota_signature(imageProcessor->signature, imageProcessor->flash_addr) < 0) + { + ChipLogError(SoftwareUpdate, "OTA update signature failed"); + return; + } +#endif + + imageProcessor->ReleaseBlock(); + + ChipLogProgress(SoftwareUpdate, "OTA image downloaded and written to flash"); +} + +void AmebaOTAImageProcessor::HandleAbort(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + + // Abort OTA procedure + + imageProcessor->ReleaseBlock(); +} + +void AmebaOTAImageProcessor::HandleProcessBlock(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + +#if defined(CONFIG_PLATFORM_8721D) + if (!imageProcessor->readHeader) // First block received, process header + { + uint8_t * tempBuf = (uint8_t *) ota_update_malloc(32); + imageProcessor->pOtaTgtHdr = (update_ota_target_hdr *) ota_update_malloc(sizeof(update_ota_target_hdr)); + + memcpy(tempBuf, imageProcessor->mBlock.data(), 32); + memcpy(imageProcessor->pOtaTgtHdr, tempBuf, 8); // Store FwVer, HdrNum + memcpy(&(imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgHdrLen), tempBuf + 12, + 16); // Store ImgHdrLen, Checksum, ImgLen, Offset + memcpy(&(imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgId), tempBuf + 8, 4); // Store OTA id + + if (imageProcessor->ota_target_index == OTA_INDEX_1) + imageProcessor->pOtaTgtHdr->FileImgHdr[0].FlashAddr = LS_IMG2_OTA1_ADDR; + else if (imageProcessor->ota_target_index == OTA_INDEX_2) + imageProcessor->pOtaTgtHdr->FileImgHdr[0].FlashAddr = LS_IMG2_OTA2_ADDR; + + imageProcessor->pOtaTgtHdr->ValidImgCnt = 1; + + if (strncmp("OTA", (const char *) &(imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgId), 3) != 0) + { + ChipLogError(SoftwareUpdate, "Wrong Image ID for OTA"); + return; + } + + imageProcessor->readHeader = true; + ChipLogProgress(SoftwareUpdate, "Correct OTA Image ID, get firmware header success"); + ChipLogProgress(SoftwareUpdate, "FwVer: 0x%X", imageProcessor->pOtaTgtHdr->FileHdr.FwVer); + ChipLogProgress(SoftwareUpdate, "HdrNum: 0x%X", imageProcessor->pOtaTgtHdr->FileHdr.HdrNum); + ChipLogProgress(SoftwareUpdate, "ImgHdrLen: 0x%X", imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgHdrLen); + ChipLogProgress(SoftwareUpdate, "Checksum: 0x%X", imageProcessor->pOtaTgtHdr->FileImgHdr[0].Checksum); + ChipLogProgress(SoftwareUpdate, "ImgLen: 0x%X", imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgLen); + ChipLogProgress(SoftwareUpdate, "Offset: 0x%X", imageProcessor->pOtaTgtHdr->FileImgHdr[0].Offset); + ChipLogProgress(SoftwareUpdate, "FlashAddr: 0x%X", imageProcessor->pOtaTgtHdr->FileImgHdr[0].FlashAddr); + + // Erase update partition + ChipLogProgress(SoftwareUpdate, "Erasing target partition..."); + erase_ota_target_flash(imageProcessor->pOtaTgtHdr->FileImgHdr[0].FlashAddr, + imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgLen); + ChipLogProgress(SoftwareUpdate, "Erased partition OTA%d", imageProcessor->ota_target_index + 1); + + // Set RemainBytes to image length, excluding 8bytes of signature + imageProcessor->RemainBytes = imageProcessor->pOtaTgtHdr->FileImgHdr[0].ImgLen - 8; + + // Set flash address, incremented by 8bytes to account for signature + imageProcessor->flash_addr = imageProcessor->pOtaTgtHdr->FileImgHdr[0].FlashAddr - SPI_FLASH_BASE + 8; + + // Set signature to point to pOtaTgtHdr->Sign + imageProcessor->signature = &(imageProcessor->pOtaTgtHdr->Sign[0][0]); + + // Store the signature temporarily + uint8_t * tempbufptr = imageProcessor->mBlock.data() + imageProcessor->pOtaTgtHdr->FileImgHdr[0].Offset; + memcpy(imageProcessor->signature, tempbufptr, 8); + tempbufptr += 8; + + // Write remaining downloaded bytes to flash_addr + uint32_t tempsize = imageProcessor->mBlock.size() - imageProcessor->pOtaTgtHdr->FileImgHdr[0].Offset - 8; + device_mutex_lock(RT_DEV_LOCK_FLASH); + if (ota_writestream_user(imageProcessor->flash_addr + imageProcessor->size, tempsize, tempbufptr) < 0) + { + ChipLogError(SoftwareUpdate, "Write to flash failed"); + device_mutex_unlock(RT_DEV_LOCK_FLASH); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + device_mutex_unlock(RT_DEV_LOCK_FLASH); + + imageProcessor->size += tempsize; + imageProcessor->RemainBytes -= tempsize; + + ota_update_free(tempBuf); + } + else // received subsequent blocks + { + device_mutex_lock(RT_DEV_LOCK_FLASH); + if (ota_writestream_user(imageProcessor->flash_addr + imageProcessor->size, imageProcessor->mBlock.size(), + imageProcessor->mBlock.data()) < 0) + { + ChipLogError(SoftwareUpdate, "Write to flash failed"); + device_mutex_unlock(RT_DEV_LOCK_FLASH); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + device_mutex_unlock(RT_DEV_LOCK_FLASH); + + imageProcessor->size += imageProcessor->mBlock.size(); + imageProcessor->RemainBytes -= imageProcessor->mBlock.size(); + } +#elif defined(CONFIG_PLATFORM_8710C) + if (!imageProcessor->readHeader) // First block received, process 32bytes signature + { + // Store signature temporarily + memcpy(imageProcessor->signature, imageProcessor->mBlock.data(), 32); + + imageProcessor->block_len = imageProcessor->mBlock.size() - 32; // minus 32 to account for signature + + // Erase target partition + ChipLogProgress(SoftwareUpdate, "Erasing partition"); + imageProcessor->NewFWBlkSize = ((0x1F8000 - 1) / 4096) + 1; // Use a fixed image length of 0xF8000, change in the future + ChipLogProgress(SoftwareUpdate, "Erasing %d sectors", imageProcessor->NewFWBlkSize); + device_mutex_lock(RT_DEV_LOCK_FLASH); + for (int i = 0; i < imageProcessor->NewFWBlkSize; i++) + flash_erase_sector(&flash_ota, imageProcessor->flash_addr + i * 4096); + device_mutex_unlock(RT_DEV_LOCK_FLASH); + + // Write first block to target flash + if (imageProcessor->block_len > 0) + { + device_mutex_lock(RT_DEV_LOCK_FLASH); + if (flash_burst_write(&flash_ota, imageProcessor->flash_addr + 32, imageProcessor->block_len, + imageProcessor->mBlock.data() + 32) < 0) + { + device_mutex_unlock(RT_DEV_LOCK_FLASH); + ChipLogError(SoftwareUpdate, "Write to flash failed"); + return; + } + else + { + imageProcessor->size += imageProcessor->block_len; + device_mutex_unlock(RT_DEV_LOCK_FLASH); + } + } + else + { + ChipLogError(SoftwareUpdate, "Invalid size"); + return; + } + + imageProcessor->readHeader = true; + } + else // received subsequent blocks + { + imageProcessor->block_len = imageProcessor->mBlock.size(); + + // Write first block to target flash + if (imageProcessor->block_len > 0) + { + device_mutex_lock(RT_DEV_LOCK_FLASH); + if (flash_burst_write(&flash_ota, imageProcessor->flash_addr + 32 + imageProcessor->size, imageProcessor->block_len, + imageProcessor->mBlock.data()) < 0) + { + device_mutex_unlock(RT_DEV_LOCK_FLASH); + ChipLogError(SoftwareUpdate, "Write to flash failed"); + return; + } + else + { + imageProcessor->size += imageProcessor->block_len; + device_mutex_unlock(RT_DEV_LOCK_FLASH); + } + } + else + { + ChipLogError(SoftwareUpdate, "Invalid size"); + return; + } + } +#endif + imageProcessor->mParams.downloadedBytes += imageProcessor->mBlock.size(); + imageProcessor->mDownloader->FetchNextData(); +} + +void AmebaOTAImageProcessor::HandleApply(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + + // Reboot + ota_platform_reset(); +} + +CHIP_ERROR AmebaOTAImageProcessor::SetBlock(ByteSpan & block) +{ + if ((block.data() == nullptr) || block.empty()) + { + return CHIP_NO_ERROR; + } + + if (mBlock.size() < block.size()) + { + if (!mBlock.empty()) + { + ReleaseBlock(); + } + uint8_t * mBlock_ptr = static_cast(chip::Platform::MemoryAlloc(block.size())); + if (mBlock_ptr == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + mBlock = MutableByteSpan(mBlock_ptr, block.size()); + } + + // Allocate memory for block data if it has not been done yet + if (mBlock.empty()) + { + mBlock = MutableByteSpan(static_cast(chip::Platform::MemoryAlloc(block.size())), block.size()); + if (mBlock.data() == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + } + + // Store the actual block data + CHIP_ERROR err = CopySpanToMutableSpan(block, mBlock); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot copy block data: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaOTAImageProcessor::ReleaseBlock() +{ + if (mBlock.data() != nullptr) + { + chip::Platform::MemoryFree(mBlock.data()); + } + + mBlock = MutableByteSpan(); + return CHIP_NO_ERROR; +} +} // namespace chip diff --git a/src/platform/Ameba/AmebaOTAImageProcessor.h b/src/platform/Ameba/AmebaOTAImageProcessor.h new file mode 100644 index 00000000000000..78616416e9a1e1 --- /dev/null +++ b/src/platform/Ameba/AmebaOTAImageProcessor.h @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PLATFORM_8710C) +#include "ota_8710c.h" +#include "sys.h" +#include "sys_api.h" +#elif defined(CONFIG_PLATFORM_8721D) +#include "rtl8721d_ota.h" +#endif + +namespace chip { + +class AmebaOTAImageProcessor : public OTAImageProcessorInterface +{ +public: + //////////// OTAImageProcessorInterface Implementation /////////////// + CHIP_ERROR PrepareDownload() override; + CHIP_ERROR Finalize() override; + CHIP_ERROR Apply() override; + CHIP_ERROR Abort() override; + CHIP_ERROR ProcessBlock(ByteSpan & block) override; + void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; } + +private: + //////////// Actual handlers for the OTAImageProcessorInterface /////////////// + static void HandlePrepareDownload(intptr_t context); + static void HandleFinalize(intptr_t context); + static void HandleAbort(intptr_t context); + static void HandleProcessBlock(intptr_t context); + static void HandleApply(intptr_t context); + + /** + * Called to allocate memory for mBlock if necessary and set it to block + */ + CHIP_ERROR SetBlock(ByteSpan & block); + + /** + * Called to release allocated memory for mBlock + */ + CHIP_ERROR ReleaseBlock(); + + MutableByteSpan mBlock; + OTADownloader * mDownloader; + +#if defined(CONFIG_PLATFORM_8721D) + bool readHeader = false; + uint32_t ota_target_index = OTA_INDEX_2; + update_ota_target_hdr * pOtaTgtHdr; + uint32_t flash_addr; + uint32_t size = 0; + uint32_t RemainBytes; + uint8_t * signature; +#elif defined(CONFIG_PLATFORM_8710C) + bool readHeader = false; + uint32_t ota_target_index; + uint32_t flash_addr; + uint32_t NewFWBlkSize = 0; + uint32_t block_len = 0; + uint32_t size = 0; + uint8_t signature[32]; +#endif +}; + +} // namespace chip diff --git a/src/platform/Ameba/BUILD.gn b/src/platform/Ameba/BUILD.gn index 0376c59b749733..74cad16e189fbc 100755 --- a/src/platform/Ameba/BUILD.gn +++ b/src/platform/Ameba/BUILD.gn @@ -20,7 +20,6 @@ assert(chip_device_platform == "ameba") static_library("Ameba") { sources = [ - "../FreeRTOS/SystemTimeSupport.cpp", "../SingletonConfigurationManager.cpp", "AmebaConfig.cpp", "AmebaConfig.h", @@ -46,6 +45,7 @@ static_library("Ameba") { "ServiceProvisioning.h", "SoftwareUpdateManagerImpl.h", "SystemTimeSupport.cpp", + "SystemTimeSupport.h", ] deps = [ "${chip_root}/src/lib/dnssd:platform_header" ] @@ -54,4 +54,11 @@ static_library("Ameba") { "${chip_root}/src/crypto", "${chip_root}/src/platform:platform_base", ] + + if (chip_enable_ota_requestor) { + sources += [ + "AmebaOTAImageProcessor.cpp", + "AmebaOTAImageProcessor.h", + ] + } } diff --git a/src/platform/Ameba/PlatformManagerImpl.cpp b/src/platform/Ameba/PlatformManagerImpl.cpp index 5a4fbf631b12fa..5b787042e77f9e 100644 --- a/src/platform/Ameba/PlatformManagerImpl.cpp +++ b/src/platform/Ameba/PlatformManagerImpl.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -76,6 +77,11 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) // Call _InitChipStack() on the generic implementation base class // to finish the initialization process. err = Internal::GenericPlatformManagerImpl_FreeRTOS::_InitChipStack(); + + SuccessOrExit(err); + + err = System::Clock::InitClock_RealTime(); + SuccessOrExit(err); exit: diff --git a/src/platform/Ameba/SystemTimeSupport.cpp b/src/platform/Ameba/SystemTimeSupport.cpp index fa753fc1120c5e..2e6f9df93889ad 100644 --- a/src/platform/Ameba/SystemTimeSupport.cpp +++ b/src/platform/Ameba/SystemTimeSupport.cpp @@ -24,9 +24,10 @@ /* this file behaves like a config.h, comes first */ #include -#include +#include #include +#include "rtc_api.h" #include "task.h" #include @@ -42,25 +43,23 @@ struct rtkTimeVal namespace chip { namespace System { -namespace Platform { -namespace Layer { +namespace Clock { -uint64_t GetClock_Monotonic(void) -{ - return xTaskGetTickCount() * 1000; -} +namespace Internal { +ClockImpl gClockImpl; +} // namespace Internal -uint64_t GetClock_MonotonicMS(void) +Microseconds64 ClockImpl::GetMonotonicMicroseconds64(void) { - return xTaskGetTickCount(); + return (Clock::Microseconds64(xTaskGetTickCount()) * configTICK_RATE_HZ); } -uint64_t GetClock_MonotonicHiRes(void) +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64(void) { - return xTaskGetTickCount() * 1000; + return (Clock::Milliseconds64(xTaskGetTickCount())); } -CHIP_ERROR GetClock_RealTime(uint64_t & curTime) +CHIP_ERROR ClockImpl::GetClock_RealTime(Clock::Microseconds64 & curTime) { time_t seconds; struct rtkTimeVal tv; @@ -74,12 +73,13 @@ CHIP_ERROR GetClock_RealTime(uint64_t & curTime) { return CHIP_ERROR_REAL_TIME_NOT_SYNCED; } - curTime = (tv.tv_sec * UINT64_C(1000000)) + tv.tv_usec; + static_assert(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD >= 0, "We might be letting through negative tv_sec values!"); + curTime = Clock::Microseconds64((static_cast(tv.tv_sec) * UINT64_C(1000000)) + static_cast(tv.tv_usec)); return CHIP_NO_ERROR; } -CHIP_ERROR GetClock_RealTimeMS(uint64_t & curTime) +CHIP_ERROR ClockImpl::GetClock_RealTimeMS(Clock::Milliseconds64 & curTime) { time_t seconds; struct rtkTimeVal tv; @@ -93,21 +93,33 @@ CHIP_ERROR GetClock_RealTimeMS(uint64_t & curTime) { return CHIP_ERROR_REAL_TIME_NOT_SYNCED; } - - curTime = (tv.tv_sec * UINT64_C(1000)) + (tv.tv_usec / 1000); + static_assert(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD >= 0, "We might be letting through negative tv_sec values!"); + curTime = + Clock::Milliseconds64((static_cast(tv.tv_sec) * UINT64_C(1000)) + (static_cast(tv.tv_usec) / 1000)); return CHIP_NO_ERROR; } -CHIP_ERROR SetClock_RealTime(uint64_t newCurTime) +CHIP_ERROR ClockImpl::SetClock_RealTime(Clock::Microseconds64 aNewCurTime) { + struct rtkTimeVal tv; + tv.tv_sec = static_cast(aNewCurTime.count() / UINT64_C(1000000)); + tv.tv_usec = static_cast(aNewCurTime.count() % UINT64_C(1000000)); rtc_init(); - rtc_write(newCurTime); + rtc_write(tv.tv_sec); return CHIP_NO_ERROR; } -} // namespace Layer -} // namespace Platform +CHIP_ERROR InitClock_RealTime() +{ + Clock::Microseconds64 curTime = + Clock::Microseconds64((static_cast(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD) * UINT64_C(1000000))); + // Use CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD as the initial value of RealTime. + // Then the RealTime obtained from GetClock_RealTime will be always valid. + return System::SystemClock().SetClock_RealTime(curTime); +} + +} // namespace Clock } // namespace System } // namespace chip diff --git a/src/platform/Ameba/SystemTimeSupport.h b/src/platform/Ameba/SystemTimeSupport.h new file mode 100644 index 00000000000000..89eb960eea07b9 --- /dev/null +++ b/src/platform/Ameba/SystemTimeSupport.h @@ -0,0 +1,29 @@ + +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace chip { +namespace System { +namespace Clock { + +CHIP_ERROR InitClock_RealTime(); + +} // namespace Clock +} // namespace System +} // namespace chip