From 2bfed72264a905cef23cf1dea016b85a41b4c2ac Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Mon, 13 Nov 2023 08:04:27 -0600 Subject: [PATCH 01/19] initial build --- examples/apps/CMakeLists.txt | 2 +- examples/apps/cli/CMakeLists.txt | 12 +- src/CMakeLists.txt | 99 +++++++- src/openthread.syscfg | 379 +++++++++++++------------------ 4 files changed, 260 insertions(+), 232 deletions(-) diff --git a/examples/apps/CMakeLists.txt b/examples/apps/CMakeLists.txt index 03da6f0..c2fc23e 100644 --- a/examples/apps/CMakeLists.txt +++ b/examples/apps/CMakeLists.txt @@ -30,4 +30,4 @@ if(OT_APP_CLI) add_subdirectory(cli) endif() -add_subdirectory(ncp) +#add_subdirectory(ncp) diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 32f71e5..1408a17 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -48,14 +48,14 @@ else() message(FATAL_ERROR "Unsuported TI_SIMPLELINK_KERNEL: ${TI_SIMPLELINK_KERNEL}") endif() -if(OT_FTD) - include(ftd.cmake) -endif() +#if(OT_FTD) +# include(ftd.cmake) +#endif() if(OT_MTD) include(mtd.cmake) endif() -if(OT_RCP) - include(radio.cmake) -endif() +#if(OT_RCP) +# include(radio.cmake) +#endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e28415c..d15342f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,24 +48,92 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_radio_config.c ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_radio_config.h + # JJM - adding the BLE configuration source + ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_ble_config.c + ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_ble_config.h + + # TI SimpleLink FreeRTOS configuration and build is not possible until # configTICK_RATE_HZ is configurable and source directory set correctly. #${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_freertos_config.c #${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_freertos_portable_config.c #${CMAKE_CURRENT_BINARY_DIR}/syscfg/FreeRTOSConfig.h ) + + # JJM - System Cofiguration Include Paths + set(SYSCONFIG_INCLUDES + #DMM + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/thread/platform + ${TI_SIMPLELINK_SDK_DIR}/source/ti + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/thread + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/thread/source/activity + ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv + + # BLE + # JJM - including /src here to avoid duplicates of FreeRTOSConfig.h. I think this is ok? + ${PROJECT_SOURCE_DIR}/src + + # BLE (cont) + ${TI_SIMPLELINK_SDK_DIR}/kernel/tirtos7/packages + ${TI_SIMPLELINK_SDK_DIR}/source + ${TI_SIMPLELINK_SDK_DIR}/source/ti + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/npi/stack/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/rcosc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/controller/cc26xx/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/target/_common + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/heapmgr + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/npi/src/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/npi/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/osal/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/dev_info + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/simple_profile + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/services/src/saddr + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/services/src/sdata + ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/cc26xx + ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv + ${TI_SIMPLELINK_SDK_DIR}/source/ti/devices/cc13x4_cc26x4 + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos + ) + + # JJM - setup the source files required for DMM builds + set(DMM_OUTPUT_C + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/thread/source/activity/dmm_thread_activity.c + ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_dmm_application_policy.c + ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_dmm_application_policy.h + ) + set(SYSCONFIG_OUTPUT_OTHER ${CMAKE_CURRENT_BINARY_DIR}/syscfg/syscfg_c.rov.xs ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_build_config.opt + # JJM - this doesn't seem to work for some reason, had to add to User Defs + ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_ble_app_config.opt ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_utils_build_linker.cmd.genlibs ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_utils_runtime_Makefile ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_utils_runtime_model.gv + + # mirrors the simple-peripheral Startup folder + # JJM - cannot get this to link + #${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c ) set(GENLIBS_INCLUDES -L${TI_SIMPLELINK_SDK_DIR}/source ) elseif(TI_SIMPLELINK_KERNEL STREQUAL "tirtos7") + + # JJM - not used, using FreeRTOS + set(SYSCONFIG_OUTPUT_C ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_drivers_config.h ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_radio_config.h @@ -99,6 +167,8 @@ add_custom_command( OUTPUT ${SYSCONFIG_OUTPUT_C} ${SYSCONFIG_OUTPUT_OTHER} + ${DMM_OUTPUT_C} + ${BLE_OUTPUT_C} COMMAND ${TI_SYSCONFIG_CMD} -s ${TI_SIMPLELINK_SDK_DIR}/.metadata/product.json @@ -143,15 +213,42 @@ target_link_libraries(openthread-cc13xx_cc26xx ot-config ) +set(USR_COMPILE_DEFINITIONS + "SYSCFG" + "CC13X4" + "CC13XX" + "POWER_SAVING" + "TBM_ACTIVE_ITEMS_ONLY" + "STACK_LIBRARY" + "EXTENDED_STACK_SETTINGS=EXTENDED_STACK_SETTINGS_DEFAULT" + "NPI_USE_UART" + "ICALL_EVENTS" + "ICALL_JT" + "ICALL_LITE" + "ICALL_STACK0_ADDR" + "USE_ICALL" + "ICALL_MAX_NUM_ENTITIES=6" + "ICALL_MAX_NUM_TASKS=3" + "OSAL_CBTIMER_NUM_TASKS=1" + "ONE_BLE_LIB_SIZE_OPTIMIZATION" + "HOST_CONFIG=PERIPHERAL_CFG" + "USE_AE" + "GAP_BOND_MGR" + "HCI_TL_NONE" + "FREERTOS" +) + target_compile_definitions(openthread-cc13xx_cc26xx PUBLIC ${OT_PLATFORM_DEFINES} OT_TI_KERNEL_${TI_SIMPLELINK_KERNEL} + # JJM - add in the user compile definitions + ${USR_COMPILE_DEFINITIONS} ) target_compile_options(openthread-cc13xx_cc26xx PRIVATE - ${OT_CFLAGS} + ${OT_CFLAGS} ) target_include_directories(openthread-cc13xx_cc26xx diff --git a/src/openthread.syscfg b/src/openthread.syscfg index 7b93ec3..24c9757 100755 --- a/src/openthread.syscfg +++ b/src/openthread.syscfg @@ -1,229 +1,160 @@ -/* - * Copyright (c) 2018, Texas Instruments Incorporated - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of Texas Instruments Incorporated nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/** + * These arguments were used when this file was generated. They will be automatically applied on subsequent loads + * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. + * @cliArgs --board "/ti/boards/LP_EM_CC1354P10_1" --product "simplelink_cc13xx_cc26xx_sdk@7.10.00.98" + * @versions {"tool":"1.15.0+2826"} */ -/* - * cli_ftd.syscfg +/** + * Import the modules used in this configuration. */ +const ble = scripting.addModule("/ti/ble5stack/ble"); +const CCFG = scripting.addModule("/ti/devices/CCFG"); +const custom = scripting.addModule("/ti/devices/radioconfig/custom"); +const rfdesign = scripting.addModule("/ti/devices/radioconfig/rfdesign"); +const dmm = scripting.addModule("/ti/dmm/dmm"); +const AESCCM = scripting.addModule("/ti/drivers/AESCCM", {}, false); +const AESCCM1 = AESCCM.addInstance(); +const AESCTRDRBG = scripting.addModule("/ti/drivers/AESCTRDRBG", {}, false); +const AESCTRDRBG1 = AESCTRDRBG.addInstance(); +const AESECB = scripting.addModule("/ti/drivers/AESECB"); +const AESECB1 = AESECB.addInstance(); +const DMA = scripting.addModule("/ti/drivers/DMA"); +const ECDH = scripting.addModule("/ti/drivers/ECDH"); +const ECDH1 = ECDH.addInstance(); +const ECDSA = scripting.addModule("/ti/drivers/ECDSA"); +const ECDSA1 = ECDSA.addInstance(); +const ECJPAKE = scripting.addModule("/ti/drivers/ECJPAKE"); +const ECJPAKE1 = ECJPAKE.addInstance(); +const GPIO = scripting.addModule("/ti/drivers/GPIO"); +const GPIO1 = GPIO.addInstance(); +const GPIO2 = GPIO.addInstance(); +const GPIO3 = GPIO.addInstance(); +const GPIO4 = GPIO.addInstance(); +const GPIO5 = GPIO.addInstance(); +const NVS = scripting.addModule("/ti/drivers/NVS"); +const NVS1 = NVS.addInstance(); +const Power = scripting.addModule("/ti/drivers/Power"); +const RF = scripting.addModule("/ti/drivers/RF"); +const SHA2 = scripting.addModule("/ti/drivers/SHA2"); +const SHA21 = SHA2.addInstance(); +const SPI = scripting.addModule("/ti/drivers/SPI"); +const SPI1 = SPI.addInstance(); +const TRNG = scripting.addModule("/ti/drivers/TRNG"); +const TRNG1 = TRNG.addInstance(); +const UART2 = scripting.addModule("/ti/drivers/UART2"); +const UART21 = UART2.addInstance(); +const Watchdog = scripting.addModule("/ti/drivers/Watchdog"); +const Watchdog1 = Watchdog.addInstance(); + +/** + * Write custom configuration values to the imported modules. + */ +ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param1"; +ble.connUpdateParamsPeripheral.$name = "ti_ble5stack_general_ble_conn_update_params0"; +ble.advSet1.$name = "ti_ble5stack_broadcaster_advertisement_set0"; +ble.advSet1.advParam1.$name = "ti_ble5stack_broadcaster_advertisement_params0"; +ble.advSet1.advData1.$name = "ti_ble5stack_broadcaster_advertisement_data0"; +ble.advSet1.scanRes1.$name = "ti_ble5stack_broadcaster_advertisement_data1"; +ble.advSet2.$name = "ti_ble5stack_broadcaster_advertisement_set1"; +ble.advSet2.advParam2.$name = "ti_ble5stack_broadcaster_advertisement_params1"; +ble.advSet2.advData2.$name = "ti_ble5stack_broadcaster_advertisement_data2"; +ble.advSet2.scanRes2.$name = "ti_ble5stack_broadcaster_advertisement_data3"; + +CCFG.xoscCapArray = true; +CCFG.xoscCapArrayDelta = 0xD5; +CCFG.enableBootloader = true; +CCFG.dioBootloaderBackdoor = 15; +CCFG.levelBootloaderBackdoor = "Active low"; +CCFG.srcClkLF = "Derived from HF XOSC"; +CCFG.ccfgTemplate.$name = "ti_devices_CCFG_CCFGCC26XXTemplate0"; + +custom.ieee = ["ieee154"]; +custom.radioConfigieee154.$name = "ti_devices_radioconfig_settings_ieee_15_40"; +custom.radioConfigieee154.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param0"; +custom.radioConfigieee154.codeExportConfig.useConst = true; +custom.radioConfigieee154.codeExportConfig.useMulti = true; +custom.radioConfigieee154.codeExportConfig.symGenMethod = "Custom"; +custom.radioConfigieee154.codeExportConfig.cmdRadioSetupPa = "RF_cmdIeeeRadioSetup"; +custom.radioConfigieee154.codeExportConfig.cmdList_ieee_15_4 = ["cmdIeeeCsma","cmdIeeeEdScan","cmdIeeeRx","cmdIeeeRxAck","cmdIeeeTx","cmdRadioSetupPa","cmdTxTest"]; + +rfdesign.rfDesign = "LP_EM_CC1354P10_1"; + +dmm.stackRoles = ["blePeripheral","custom1"]; +dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; +dmm.policyArray[0].custom1.$name = "ti_dmm_policy_stack_dmm_stack_custom0"; +dmm.policyArray[0].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble0"; +dmm.policyArray[0].blePeripheral.weight = 1; + +AESCCM1.$name = "CONFIG_AESCCM_0"; + +AESCTRDRBG1.$name = "CONFIG_AESCTRDRBG_0"; + +AESECB1.$name = "CONFIG_AESECB_MBEDTLS"; + +ECDH1.$name = "CONFIG_ECDH_0"; + +ECDSA1.$name = "CONFIG_ECDSA_0"; + +ECJPAKE1.$name = "CONFIG_ECJPAKE_0"; + +GPIO1.$hardware = system.deviceData.board.components["BTN-1"]; +GPIO1.$name = "CONFIG_GPIO_BTN1"; + +GPIO2.$hardware = system.deviceData.board.components["BTN-2"]; +GPIO2.$name = "CONFIG_GPIO_BTN2"; + +GPIO3.$hardware = system.deviceData.board.components.LED_GREEN; +GPIO3.$name = "CONFIG_GPIO_GLED"; + +GPIO4.$hardware = system.deviceData.board.components.LED_RED; +GPIO4.$name = "CONFIG_GPIO_RLED"; + +GPIO5.$name = "CONFIG_SPINEL_INT"; +GPIO5.mode = "Output"; +GPIO5.outputStrength = "High"; +GPIO5.initialOutputState = "High"; +GPIO5.gpioPin.$assign = "boosterpack.32"; + +NVS1.$name = "CONFIG_NVSINTERNAL"; +NVS1.internalFlash.$name = "ti_drivers_nvs_NVSCC26XX0"; +NVS1.internalFlash.regionBase = 0x52000; +NVS1.internalFlash.regionSize = 0x4000; + +RF.$hardware = system.deviceData.board.components["SKY13317-373LF"]; + +SHA21.$name = "CONFIG_SHA2_0"; + +SPI1.$name = "CONFIG_SPI_1"; +SPI1.mode = "Four Pin CS Active Low"; +SPI1.spi.sclkPin.$assign = "boosterpack.24"; +SPI1.spi.pociPin.$assign = "boosterpack.6"; +SPI1.spi.picoPin.$assign = "boosterpack.23"; +SPI1.spi.csnPin.$assign = "boosterpack.25"; + +TRNG1.$name = "CONFIG_TRNG_THREAD"; + +UART21.$name = "CONFIG_UART2_0"; +UART21.$hardware = system.deviceData.board.components.XDS110UART; + +Watchdog1.$name = "CONFIG_WATCHDOG0"; +Watchdog1.watchdog.$assign = "WDT0"; -/* Modules */ -var AESECB = scripting.addModule("/ti/drivers/AESECB"); -var DMA = scripting.addModule("/ti/drivers/DMA"); -var Device = scripting.addModule("/ti/devices/CCFG"); -var ECDH = scripting.addModule("/ti/drivers/ECDH"); -var ECDSA = scripting.addModule("/ti/drivers/ECDSA"); -var ECJPAKE = scripting.addModule("/ti/drivers/ECJPAKE"); -var GPIO = scripting.addModule("/ti/drivers/GPIO"); -var NVS = scripting.addModule("/ti/drivers/NVS"); -var Power = scripting.addModule("/ti/drivers/Power"); -var RF = scripting.addModule("/ti/drivers/RF"); -var RFCustom = scripting.addModule("/ti/devices/radioconfig/custom"); -var RFDesign = scripting.addModule("ti/devices/radioconfig/rfdesign"); -var SHA2 = scripting.addModule("/ti/drivers/SHA2"); -var SPI = scripting.addModule("/ti/drivers/SPI"); -var TRNG = scripting.addModule("/ti/drivers/TRNG"); -var UART2 = scripting.addModule("/ti/drivers/UART2"); -var Watchdog = scripting.addModule("/ti/drivers/Watchdog"); - - -/* Instances */ -var AESECB = AESECB.addInstance(); -var ECDH = ECDH.addInstance(); -var ECDSA = ECDSA.addInstance(); -var ECJPAKE = ECJPAKE.addInstance(); -var GPIO1 = GPIO.addInstance(); -var GPIO2 = GPIO.addInstance(); -var GPIO3 = GPIO.addInstance(); -var GPIO4 = GPIO.addInstance(); -var GPIO5 = GPIO.addInstance(); -var NVS1 = NVS.addInstance(); -var SHA21 = SHA2.addInstance(); -var SPI2 = SPI.addInstance(); -var TRNG1 = TRNG.addInstance(); -var UART2 = UART2.addInstance(); -var Watchdog1 = Watchdog.addInstance(); - -const deviceId = system.deviceData.deviceId; - - -/* TI SimpleLink FreeRTOS configuration and build is not possible until - * configTICK_RATE_HZ is configurable and source directory set correctly. - * - * Only generate the kernel configuration for tirtos7 for now. +/** + * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future + * version of the tool will not impact the pinmux you originally saw. These lines can be completely deleted in order to + * re-solve from scratch. */ -/* Kernel Configuration */ -if (system.getRTOS() === "tirtos7") { - system.getScript("kernel_config_release.syscfg.js"); -} - - -/* CCFG */ -const ccfgSettings = system.getScript("/ti/common/lprf_ccfg_settings.js").ccfgSettings; -for(var setting in ccfgSettings) -{ - Device[setting] = ccfgSettings[setting]; -} - -Device.srcClkLF = "Derived from HF XOSC"; - - -/* UART */ -UART2.$hardware = system.deviceData.board.components.XDS110UART; -UART2.$name = "CONFIG_UART2_0"; - - -/* GPIO */ -GPIO1.$hardware = system.deviceData.board.components["BTN-1"]; -GPIO1.$name = "CONFIG_GPIO_BTN1"; - -GPIO2.$hardware = system.deviceData.board.components["BTN-2"]; -GPIO2.$name = "CONFIG_GPIO_BTN2"; - -GPIO3.$hardware = system.deviceData.board.components.LED_GREEN; -GPIO3.$name = "CONFIG_GPIO_GLED"; - -GPIO4.$hardware = system.deviceData.board.components.LED_RED; -GPIO4.$name = "CONFIG_GPIO_RLED"; - - -/* SPI for NCP */ -SPI2.$name = "CONFIG_SPI_1"; -SPI2.mode = "Four Pin SS Active Low"; -SPI2.spi.pociPin.$assign = "DIO24" -SPI2.spi.picoPin.$assign = "DIO25" -SPI2.spi.sclkPin.$assign = "DIO26" -SPI2.spi.csnPin.$assign = "DIO27" - -GPIO5.$name = "CONFIG_SPINEL_INT"; -GPIO5.mode = "Output"; -GPIO5.outputStrength = "High"; -GPIO5.initialOutputState = "High"; -GPIO5.gpioPin.$assign = "DIO16"; - - -/* NVS */ -NVS1.$name = "CONFIG_NVSINTERNAL"; - -/* place at the end of Flash */ -if(deviceId.match(/CC((13|26).2(R|RB|P)7)/)) -{ - NVS1.internalFlash.regionBase = 0xAA000; - NVS1.internalFlash.regionSize = 0x4000; -} -else if(deviceId.match(/CC((13|26).2(R|RB|P)1)/)) -{ - NVS1.internalFlash.regionBase = 0x52000; - NVS1.internalFlash.regionSize = 0x4000; -} -else if(deviceId.match(/CC((13|26).4P10)/)) -{ - NVS1.internalFlash.regionBase = 0x52000; - NVS1.internalFlash.regionSize = 0x4000; -} -else -{ - throw new Error("Could not set NVS location for deviceId: " + deviceId); -} - - -/* Watchdog */ -Watchdog1.$name = "CONFIG_WATCHDOG0"; -Watchdog1.period = 1000; -Watchdog1.watchdog.$assign = "WDT0"; - -/* TRNG */ -TRNG1.$name = "CONFIG_TRNG_THREAD"; - -/* AES */ -AESECB.$name = "CONFIG_AESECB_MBEDTLS"; - -/* RF */ - -/* if an antenna component exists, assign it to the rf instance */ -if (system.deviceData.board && system.deviceData.board.components.RF) { - RF.$hardware = system.deviceData.board.components.RF; -} - -const rfDesignSettings = system.getScript("/ti/common/lprf_rf_design_settings.js").rfDesignSettings; -for(var setting in rfDesignSettings) -{ - RFDesign[setting] = rfDesignSettings[setting]; -} - -/* Handling for RF frontend characterization */ -if(RFDesign.rfDesign.match(/LP_CC2652PSIP/)) -{ - RFCustom.ieee = ["ieee154p10"]; - var rfCodeExportConfig = RFCustom.radioConfigieee154p10.codeExportConfig -} -else -{ - RFCustom.ieee = ["ieee154"]; - var rfCodeExportConfig = RFCustom.radioConfigieee154.codeExportConfig -} - -var cmdList = [ - "cmdIeeeTx", - "cmdIeeeRx", - "cmdIeeeCsma", - "cmdIeeeEdScan", - "cmdIeeeRxAck", - "cmdTxTest" -]; - -rfCodeExportConfig.useConst = true; -rfCodeExportConfig.useMulti = true; -rfCodeExportConfig.symGenMethod = "Custom"; - -// Add high PA options if present -if(deviceId.match(/CC(265[12]R|2674R|1352R1|1354R)/)) -{ - cmdList.push("cmdRadioSetup"); - rfCodeExportConfig.cmdRadioSetup = "RF_cmdIeeeRadioSetup"; -} -else if(deviceId.match(/CC(265[12]P|2674P|1352P)/)) -{ - cmdList.push("cmdRadioSetupPa"); - rfCodeExportConfig.cmdRadioSetupPa = "RF_cmdIeeeRadioSetup"; - rfCodeExportConfig.paExport = "combined"; -} -else if(deviceId.match(/CC(265[34]|1354)P/)) -{ - cmdList.push("cmdRadioSetupPa"); - rfCodeExportConfig.cmdRadioSetupPa = "RF_cmdIeeeRadioSetup"; - // currently not characterized for high PA -} -else -{ - throw new Error("Could not set RF settings for deviceId: " + deviceId); -} - -rfCodeExportConfig.cmdList_ieee_15_4 = cmdList; +GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; +GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; +GPIO3.gpioPin.$suggestSolution = "ball.16"; +GPIO4.gpioPin.$suggestSolution = "ball.15"; +RF.rfAntennaPin0.$suggestSolution = "ball.10"; +RF.rfAntennaPin1.$suggestSolution = "ball.12"; +RF.rfAntennaPin2.$suggestSolution = "ball.11"; +SPI1.spi.$suggestSolution = "SPI0"; +SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; +SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; +UART21.uart.$suggestSolution = "UART0"; +UART21.uart.txPin.$suggestSolution = "boosterpack.4"; +UART21.uart.rxPin.$suggestSolution = "boosterpack.3"; From 0ec7826ee706758e0c8b561ce14bc836616623bb Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Mon, 13 Nov 2023 08:45:03 -0600 Subject: [PATCH 02/19] added the BLE sources to output --- src/CMakeLists.txt | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d15342f..ecda034 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,6 +71,11 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/thread/source/activity ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv + # + # JJM - Note: the include paths below are a mirror (or an attempt to mirror) + # the /Includes folder from the CCS simple-peripheral project + # + # BLE # JJM - including /src here to avoid duplicates of FreeRTOSConfig.h. I think this is ok? ${PROJECT_SOURCE_DIR}/src @@ -102,7 +107,6 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/cc26xx ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv ${TI_SIMPLELINK_SDK_DIR}/source/ti/devices/cc13x4_cc26x4 - ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos ) @@ -113,6 +117,24 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_dmm_application_policy.h ) + # JJM - setup the source files for BLE + set(BLE_OUTPUT_C + # JJM - mirror simple peripheral iCall folder + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_cc2650.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_user_config.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c + + # JJM - mirror simple peripheral iCallBLE folder + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/stack/ble_user_config_stack.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/app/ble_user_config.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/app/icall_api_lite.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/app/icall_hci_tl.c + + # JJM - mirror the simple peripheral Profiles folder + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/dev_info/cc26xx/devinfoservice.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/simple_profile/cc26xx/simple_gatt_profile.c + ) + set(SYSCONFIG_OUTPUT_OTHER ${CMAKE_CURRENT_BINARY_DIR}/syscfg/syscfg_c.rov.xs ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_build_config.opt @@ -184,6 +206,8 @@ add_custom_command( add_library(openthread-cc13xx_cc26xx ${SYSCONFIG_OUTPUT_C} + ${DMM_OUTPUT_C} + ${BLE_OUTPUT_C} alarm.c alarm_micro.c diag.c @@ -213,6 +237,8 @@ target_link_libraries(openthread-cc13xx_cc26xx ot-config ) +# JJM - setting the user compile definitions here as there seems to be +# an issue with the .opt files set(USR_COMPILE_DEFINITIONS "SYSCFG" "CC13X4" From aac406f53a2338347c8b2135114a167502154c2b Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Mon, 13 Nov 2023 09:17:42 -0600 Subject: [PATCH 03/19] added ICall_init() and ICall_createRemoteTasks() - fails to link --- examples/apps/cli/CMakeLists.txt | 17 +++++++++++++++++ examples/apps/cli/freertos_main.c | 14 ++++++++++++++ src/CMakeLists.txt | 6 +++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 1408a17..1b2615b 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -31,11 +31,28 @@ set(COMMON_INCLUDES ${TI_PUBLIC_INCLUDES} ${PROJECT_SOURCE_DIR}/openthread/examples/platforms ${PROJECT_SOURCE_DIR}/openthread/src/core + + # JJM include paths for ICall module + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/inc/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/target/_common + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv + + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom + + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/osal/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/controller/cc26xx/inc + ) set(COMMON_SOURCES cli_uart.cpp main.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c ) if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 4aae8eb..74c2bc7 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -43,6 +43,14 @@ #include #include +#include + +#ifndef USE_DEFAULT_USER_CFG +#include "ble_user_config.h" +// BLE user defined configuration +icall_userCfg_t user0Cfg = BLE_USER_CFG; +#endif // USE_DEFAULT_USER_CFG + // The entry point for the application extern int app_main(int argc, char *argv[]); #define APP_STACK_SIZE (2048) @@ -80,6 +88,12 @@ int main(void) SHA2_init(); + // initialize the ICall module + ICall_init(); + + // Start tasks of external images - Priority 5 + ICall_createRemoteTasks(); + if (NULL == xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, appStack, &appTaskBuffer)) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecda034..f6e232e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,7 +123,7 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_cc2650.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_user_config.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c - + # JJM - mirror simple peripheral iCallBLE folder ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/stack/ble_user_config_stack.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/app/ble_user_config.c @@ -145,8 +145,8 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_utils_runtime_model.gv # mirrors the simple-peripheral Startup folder - # JJM - cannot get this to link - #${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c + # JJM - cannot get this to link for stack_main() + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c ) set(GENLIBS_INCLUDES -L${TI_SIMPLELINK_SDK_DIR}/source From 20974f89aceef1b0468b0d3a3b3ecee4620a0c18 Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Thu, 7 Dec 2023 08:35:10 -0600 Subject: [PATCH 04/19] fix for cmake file --- .gitignore | 1 + src/CMakeLists.txt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 76f4628..4bb839f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build output +.vscode diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6e232e..33724d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -225,6 +225,7 @@ add_library(openthread-cc13xx_cc26xx list(APPEND TI_PLATFORM_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) +# retargeted target_link_libraries(openthread-cc13xx_cc26xx PUBLIC cc13xx-cc26xx-sdk @@ -233,6 +234,7 @@ target_link_libraries(openthread-cc13xx_cc26xx ${GENLIBS_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_utils_build_linker.cmd.genlibs cc13xx-cc26xx-driverlib + -Wl,${CMAKE_CURRENT_BINARY_DIR}/syscfg/ti_utils_build_linker.cmd.genlibs PRIVATE ot-config ) @@ -240,6 +242,7 @@ target_link_libraries(openthread-cc13xx_cc26xx # JJM - setting the user compile definitions here as there seems to be # an issue with the .opt files set(USR_COMPILE_DEFINITIONS + #"USE_DMM" "SYSCFG" "CC13X4" "CC13XX" @@ -257,6 +260,8 @@ set(USR_COMPILE_DEFINITIONS "ICALL_MAX_NUM_TASKS=3" "OSAL_CBTIMER_NUM_TASKS=1" "ONE_BLE_LIB_SIZE_OPTIMIZATION" + + # the following are from ti_build_config.opt "HOST_CONFIG=PERIPHERAL_CFG" "USE_AE" "GAP_BOND_MGR" From b7a5ee5435d40242f620b2cdcf0029eb70c5eb52 Mon Sep 17 00:00:00 2001 From: "Zhang, Wei" Date: Tue, 12 Dec 2023 13:14:13 -0600 Subject: [PATCH 05/19] ble sp test --- examples/apps/cli/CMakeLists.txt | 5 +- examples/apps/cli/Logger.h | 6 + examples/apps/cli/bleAppTask.c | 2558 +++++++++++++++++++++++++++++ examples/apps/cli/bleAppTask.h | 5 + examples/apps/cli/bleStackApp.h | 103 ++ examples/apps/cli/bleStackMenu.c | 61 + examples/apps/cli/bleStack_menu.h | 91 + examples/apps/cli/freertos_main.c | 16 +- 8 files changed, 2839 insertions(+), 6 deletions(-) create mode 100644 examples/apps/cli/Logger.h create mode 100644 examples/apps/cli/bleAppTask.c create mode 100644 examples/apps/cli/bleAppTask.h create mode 100644 examples/apps/cli/bleStackApp.h create mode 100644 examples/apps/cli/bleStackMenu.c create mode 100644 examples/apps/cli/bleStack_menu.h diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 1b2615b..77d16fd 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -45,12 +45,15 @@ set(COMMON_INCLUDES ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/osal/src/inc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/controller/cc26xx/inc - + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/dev_info + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/simple_profile ) set(COMMON_SOURCES cli_uart.cpp main.c + bleAppTask.c + bleStackMenu.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c ) diff --git a/examples/apps/cli/Logger.h b/examples/apps/cli/Logger.h new file mode 100644 index 0000000..607f51a --- /dev/null +++ b/examples/apps/cli/Logger.h @@ -0,0 +1,6 @@ +#pragma once +#include + +#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP +void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...); +#endif \ No newline at end of file diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c new file mode 100644 index 0000000..87a0345 --- /dev/null +++ b/examples/apps/cli/bleAppTask.c @@ -0,0 +1,2558 @@ +//Check to see if BLE5-stack works on exec_core + +#include "bleAppTask.h" +#include +#include +#include +#include +#include "Logger.h" +#include "bleStackApp.h" +#include "ble_user_config.h" +#include +#include +#include "util.h" + +//Wei +//#include +#include + +//Wei +/* remove tirtos code */ +//#include +//#include +//#include +//#include + +#include + +//Wei +/* add freertos code */ +#include +#include +#include + +#if (!(defined __TI_COMPILER_VERSION__) && !(defined __GNUC__)) +#include +#endif + +#include +#include + +#include +/* This Header file contains all BLE API and icall structure definition */ +#include + +#include +#include + +#ifdef USE_RCOSC +#include +#endif //USE_RCOSC + +#include +#include + +#include + +#include "bleStack_menu.h" +#include "ti_ble_config.h" + +#ifdef PTM_MODE +#include "npi_task.h" // To allow RX event registration +#include "npi_ble.h" // To enable transmission of messages to UART +#include "icall_hci_tl.h" // To allow ICall HCI Transport Layer +#endif // PTM_MODE + + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ +// How often to perform periodic event (in ms) +#define SP_PERIODIC_EVT_PERIOD 5000 + +// Task configuration +#define SP_TASK_PRIORITY 1 + +#ifndef SP_TASK_STACK_SIZE +#define SP_TASK_STACK_SIZE 1024 +#endif + +// Application events +#define SP_STATE_CHANGE_EVT 0 +#define SP_CHAR_CHANGE_EVT 1 +#define SP_KEY_CHANGE_EVT 2 +#define SP_ADV_EVT 3 +#define SP_PAIR_STATE_EVT 4 +#define SP_PASSCODE_EVT 5 +#define SP_PERIODIC_EVT 6 +#define SP_READ_RPA_EVT 7 +#define SP_SEND_PARAM_UPDATE_EVT 8 +#define SP_CONN_EVT 9 + +// Internal Events for RTOS application +#define SP_ICALL_EVT ICALL_MSG_EVENT_ID // Event_Id_31 +#define SP_QUEUE_EVT UTIL_QUEUE_EVENT_ID // Event_Id_30 + +// Bitwise OR of all RTOS events to pend on +#define SP_ALL_EVENTS (SP_ICALL_EVT | \ + SP_QUEUE_EVT) + +// Size of string-converted device address ("0xXXXXXXXXXXXX") +#define SP_ADDR_STR_SIZE 15 + +// Row numbers for two-button menu +#define SP_ROW_SEPARATOR_1 (TBM_ROW_APP + 0) +#define SP_ROW_STATUS_1 (TBM_ROW_APP + 1) +#define SP_ROW_STATUS_2 (TBM_ROW_APP + 2) +#define SP_ROW_CONNECTION (TBM_ROW_APP + 3) +#define SP_ROW_ADVSTATE (TBM_ROW_APP + 4) +#define SP_ROW_RSSI (TBM_ROW_APP + 5) +#define SP_ROW_IDA (TBM_ROW_APP + 6) +#define SP_ROW_RPA (TBM_ROW_APP + 7) +#define SP_ROW_DEBUG (TBM_ROW_APP + 8) +#define SP_ROW_AC (TBM_ROW_APP + 9) + +// For storing the active connections +#define SP_RSSI_TRACK_CHNLS 1 // Max possible channels can be GAP_BONDINGS_MAX +#define SP_MAX_RSSI_STORE_DEPTH 5 +#define SP_INVALID_HANDLE 0xFFFF +#define RSSI_2M_THRSHLD -30 +#define RSSI_1M_THRSHLD -40 +#define RSSI_S2_THRSHLD -50 +#define RSSI_S8_THRSHLD -60 +#define SP_PHY_NONE LL_PHY_NONE // No PHY set +#define AUTO_PHY_UPDATE 0xFF + +// Spin if the expression is not true +#define SIMPLEPERIPHERAL_ASSERT(expr) if (!(expr)) simple_peripheral_spin(); + +/********************************************************************* + * TYPEDEFS + */ + +// Auto connect availble groups +enum +{ + AUTOCONNECT_DISABLE = 0, // Disable + AUTOCONNECT_GROUP_A = 1, // Group A + AUTOCONNECT_GROUP_B = 2 // Group B +}; + + +// App event passed from stack modules. This type is defined by the application +// since it can queue events to itself however it wants. +typedef struct +{ + uint8_t event; // event type + void *pData; // pointer to message +} spEvt_t; + +// Container to store passcode data when passing from gapbondmgr callback +// to app event. See the pfnPairStateCB_t documentation from the gapbondmgr.h +// header file for more information on each parameter. +typedef struct +{ + uint8_t state; + uint16_t connHandle; + uint8_t status; +} spPairStateData_t; + +// Container to store passcode data when passing from gapbondmgr callback +// to app event. See the pfnPasscodeCB_t documentation from the gapbondmgr.h +// header file for more information on each parameter. +typedef struct +{ + uint8_t deviceAddr[B_ADDR_LEN]; + uint16_t connHandle; + uint8_t uiInputs; + uint8_t uiOutputs; + uint32_t numComparison; +} spPasscodeData_t; + +// Container to store advertising event data when passing from advertising +// callback to app event. See the respective event in GapAdvScan_Event_IDs +// in gap_advertiser.h for the type that pBuf should be cast to. +typedef struct +{ + uint32_t event; + void *pBuf; +} spGapAdvEventData_t; + +// Container to store information from clock expiration using a flexible array +// since data is not always needed +typedef struct +{ + uint8_t event; // + uint8_t data[]; +} spClockEventData_t; + +// List element for parameter update and PHY command status lists +typedef struct +{ + List_Elem elem; + uint16_t connHandle; +} spConnHandleEntry_t; + +// Connected device information +typedef struct +{ + uint16_t connHandle; // Connection Handle + spClockEventData_t* pParamUpdateEventData; + Clock_Struct* pUpdateClock; // pointer to clock struct + int8_t rssiArr[SP_MAX_RSSI_STORE_DEPTH]; + uint8_t rssiCntr; + int8_t rssiAvg; + bool phyCngRq; // Set to true if PHY change request is in progress + uint8_t currPhy; + uint8_t rqPhy; + uint8_t phyRqFailCnt; // PHY change request count + bool isAutoPHYEnable; // Flag to indicate auto phy change +} spConnRec_t; + +/********************************************************************* + * GLOBAL VARIABLES + */ +//Wei +mqd_t g_EventsQueueID; + +// Display Interface +Display_Handle dispHandle = NULL; + +// Task configuration +//Wei +//Task_Struct spTask; +#if defined __TI_COMPILER_VERSION__ +#pragma DATA_ALIGN(spTaskStack, 8) +#else +#pragma data_alignment=8 +#endif +//Wei +//uint8_t spTaskStack[SP_TASK_STACK_SIZE]; + +#define APP_EVT_EVENT_MAX 0x9 +char *appEventStrings[] = { + "APP_STATE_CHANGE_EVT ", + "APP_CHAR_CHANGE_EVT ", + "APP_KEY_CHANGE_EVT ", + "APP_ADV_EVT ", + "APP_PAIR_STATE_EVT ", + "APP_PASSCODE_EVT ", + "APP_READ_RPA_EVT ", + "APP_PERIODIC_EVT ", + "APP_SEND_PARAM_UPDATE_EVT", + "APP_CONN_EVT ", +}; + +/********************************************************************* + * LOCAL VARIABLES + */ + +// Entity ID globally used to check for source and/or destination of messages +static ICall_EntityID selfEntity; +//Wei +ICall_SyncHandle syncEvent; + +// Event globally used to post local events and pend on system and +// local events. + +//Wei +//static ICall_SyncHandle syncEvent; +mqd_t g_POSIX_appMsgQueue; + +// Queue object used for app messages +//Wei +//static Queue_Struct appMsgQueue; +static QueueHandle_t appMsgQueueHandle; + +// Clock instance for internal periodic events. Only one is needed since +// GattServApp will handle notifying all connected GATT clients +static Clock_Struct clkPeriodic; +// Clock instance for RPA read events. +static Clock_Struct clkRpaRead; + +// Memory to pass periodic event ID to clock handler +spClockEventData_t argPeriodic = +{ .event = SP_PERIODIC_EVT }; + +// Memory to pass RPA read event ID to clock handler +spClockEventData_t argRpaRead = +{ .event = SP_READ_RPA_EVT }; + +// Per-handle connection info +static spConnRec_t connList[MAX_NUM_BLE_CONNS]; + +// Current connection handle as chosen by menu +static uint16_t menuConnHandle = LINKDB_CONNHANDLE_INVALID; + +// List to store connection handles for set phy command status's +static List_List setPhyCommStatList; + +// List to store connection handles for queued param updates +static List_List paramUpdateList; + +// Auto connect Disabled/Enabled {0 - Disabled, 1- Group A , 2-Group B, ...} +uint8_t autoConnect = AUTOCONNECT_DISABLE; + +// Advertising handles +static uint8 advHandleLegacy; +static uint8 advHandleLongRange; + +// Address mode +static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE; + +// Current Random Private Address +static uint8 rpa[B_ADDR_LEN] = {0}; + +/********************************************************************* + * LOCAL FUNCTIONS + */ + +static void SimplePeripheral_init( void ); +//Wei +//static void SimplePeripheral_taskFxn(UArg a0, UArg a1); + +static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg); +static uint8_t SimplePeripheral_processGATTMsg(gattMsgEvent_t *pMsg); +static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg); +static void SimplePeripheral_advCallback(uint32_t event, void *pBuf, uintptr_t arg); +static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData); +static void SimplePeripheral_processAppMsg(spEvt_t *pMsg); +static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId); +static void SimplePeripheral_performPeriodicTask(void); +static void SimplePeripheral_updateRPA(void); +//Wei +static void SimplePeripheral_clockHandler(void *arg); +//static void SimplePeripheral_clockHandler(UArg arg); +static void SimplePeripheral_passcodeCb(uint8_t *pDeviceAddr, uint16_t connHandle, + uint8_t uiInputs, uint8_t uiOutputs, + uint32_t numComparison); +static void SimplePeripheral_pairStateCb(uint16_t connHandle, uint8_t state, + uint8_t status); +static void SimplePeripheral_processPairState(spPairStateData_t *pPairState); +static void SimplePeripheral_processPasscode(spPasscodeData_t *pPasscodeData); +static void SimplePeripheral_charValueChangeCB(uint8_t paramId); +static status_t SimplePeripheral_enqueueMsg(uint8_t event, void *pData); +static void SimplePeripheral_keyChangeHandler(uint8 keys); +static void SimplePeripheral_handleKeys(uint8_t keys); +static void SimplePeripheral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg); +static void SimplePeripheral_initPHYRSSIArray(void); +static void SimplePeripheral_updatePHYStat(uint16_t eventCode, uint8_t *pMsg); +static uint8_t SimplePeripheral_addConn(uint16_t connHandle); +static uint8_t SimplePeripheral_getConnIndex(uint16_t connHandle); +static uint8_t SimplePeripheral_removeConn(uint16_t connHandle); +static void SimplePeripheral_processParamUpdate(uint16_t connHandle); +static status_t SimplePeripheral_startAutoPhyChange(uint16_t connHandle); +static status_t SimplePeripheral_stopAutoPhyChange(uint16_t connHandle); +static status_t SimplePeripheral_setPhy(uint16_t connHandle, uint8_t allPhys, + uint8_t txPhy, uint8_t rxPhy, + uint16_t phyOpts); +static uint8_t SimplePeripheral_clearConnListEntry(uint16_t connHandle); +static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, + tbmMenuObj_t* pMenuObjNext); +static void SimplePeripheral_connEvtCB(Gap_ConnEventRpt_t *pReport); +static void SimplePeripheral_processConnEvt(Gap_ConnEventRpt_t *pReport); +#ifdef PTM_MODE +void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg); // Declaration +static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len); // Declaration +#endif // PTM_MODE + +/********************************************************************* + * EXTERN FUNCTIONS + */ +extern void AssertHandler(uint8 assertCause, uint8 assertSubcause); + +/********************************************************************* + * PROFILE CALLBACKS + */ + +// GAP Bond Manager Callbacks +static gapBondCBs_t SimplePeripheral_BondMgrCBs = +{ + SimplePeripheral_passcodeCb, // Passcode callback + SimplePeripheral_pairStateCb // Pairing/Bonding state Callback +}; + +// Simple GATT Profile Callbacks +static simpleProfileCBs_t SimplePeripheral_simpleProfileCBs = +{ + SimplePeripheral_charValueChangeCB // Simple GATT Characteristic value change callback +}; + +//Citadel Application definition + + +static TaskHandle_t BLEAPPTaskHandle = NULL; + +void bleAppTask_init() +{ + // initialize the ICall module + ICall_init(); + + // Start tasks of external images - Priority 5 + ICall_createRemoteTasks(); + + if (xTaskCreate(BleMain, "BleMain", BLEAPP_TASK_STACK_SIZE/sizeof(StackType_t), NULL, BLEAPP_TASK_PRIORITY, &BLEAPPTaskHandle)!=pdPASS) + { + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM,"BLEAPP Failed to created\n"); + while (1) + ; + } + +} + +static void BleMain(void * pvParameter) +{ + //Initialize ble application + bleStack_init(); + + //ble application main loop + for (;;) + { + /* main loop for BleMain functionalities */ + { + uint32_t events; + + // Waits for an event to be posted associated with the calling thread. + // Note that an event associated with a thread is posted when a + // message is queued to the message receive queue of the thread + + //Wei + mq_receive(syncEvent, (char*)&events, sizeof(uint32_t), NULL); + //events = Event_pend(syncEvent, Event_Id_NONE, SP_ALL_EVENTS, + // ICALL_TIMEOUT_FOREVER); + + if (events) + { + ICall_EntityID dest; + ICall_ServiceEnum src; + ICall_HciExtEvt *pMsg = NULL; + + // Fetch any available messages that might have been sent from the stack + if (ICall_fetchServiceMsg(&src, &dest, + (void **)&pMsg) == ICALL_ERRNO_SUCCESS) + { + uint8 safeToDealloc = TRUE; + + if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity)) + { + ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg; + + // Check for BLE stack events first + if (pEvt->signature != 0xffff) + { + // Process inter-task message + safeToDealloc = SimplePeripheral_processStackMsg((ICall_Hdr *)pMsg); + } + } + + if (pMsg && safeToDealloc) + { + ICall_freeMsg(pMsg); + } + } + + // If RTOS queue is not empty, process app message. + if (events & SP_QUEUE_EVT) + { + //Wei + spEvt_t *pMsg; + do { + pMsg = (spEvt_t *)Util_dequeueMsg(g_POSIX_appMsgQueue); + if (NULL != pMsg) + { + // Process message. + SimplePeripheral_processAppMsg(pMsg); + + // Free the space from the message. + ICall_free(pMsg); + } + else + { + break; + } + }while(1); + //while (!Queue_empty(appMsgQueueHandle)) + //{ + // spEvt_t *pMsg = (spEvt_t *)Util_dequeueMsg(appMsgQueueHandle); + // if (pMsg) + // { + // Process message. + // SimplePeripheral_processAppMsg(pMsg); + + // Free the space from the message. + // ICall_free(pMsg); + // } + } + } + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_processStackMsg + * + * @brief Process an incoming stack message. + * + * @param pMsg - message to process + * + * @return TRUE if safe to deallocate incoming message, FALSE otherwise. + */ +static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) +{ + // Always dealloc pMsg unless set otherwise + uint8_t safeToDealloc = TRUE; + + BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : Stack msg status=%d, event=0x%x\n", pMsg->status, pMsg->event); + + switch (pMsg->event) + { + case GAP_MSG_EVENT: + SimplePeripheral_processGapMessage((gapEventHdr_t*) pMsg); + break; + + case GATT_MSG_EVENT: + // Process GATT message + safeToDealloc = SimplePeripheral_processGATTMsg((gattMsgEvent_t *)pMsg); + break; + + case HCI_GAP_EVENT_EVENT: + { + // Process HCI message + switch(pMsg->status) + { + case HCI_COMMAND_COMPLETE_EVENT_CODE: + // Process HCI Command Complete Events here + { + SimplePeripheral_processCmdCompleteEvt((hciEvt_CmdComplete_t *) pMsg); + break; + } + + case HCI_BLE_HARDWARE_ERROR_EVENT_CODE: + AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); + break; + + // HCI Commands Events + case HCI_COMMAND_STATUS_EVENT_CODE: + { + hciEvt_CommandStatus_t *pMyMsg = (hciEvt_CommandStatus_t *)pMsg; + switch ( pMyMsg->cmdOpcode ) + { + case HCI_LE_SET_PHY: + { + if (pMyMsg->cmdStatus == HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE) + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, + "PHY Change failure, peer does not support this"); + } + else + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, + "PHY Update Status Event: 0x%x", + pMyMsg->cmdStatus); + } + + SimplePeripheral_updatePHYStat(HCI_LE_SET_PHY, (uint8_t *)pMsg); + break; + } + + default: + break; + } + break; + } + + // LE Events + case HCI_LE_EVENT_CODE: + { + hciEvt_BLEPhyUpdateComplete_t *pPUC = + (hciEvt_BLEPhyUpdateComplete_t*) pMsg; + + // A Phy Update Has Completed or Failed + if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT) + { + if (pPUC->status != SUCCESS) + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, + "PHY Change failure"); + } + else + { + // Only symmetrical PHY is supported. + // rxPhy should be equal to txPhy. + Display_printf(dispHandle, SP_ROW_STATUS_2, 0, + "PHY Updated to %s", + (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_1M) ? "1M" : + (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_2M) ? "2M" : + (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_CODED) ? "CODED" : "Unexpected PHY Value"); + } + + SimplePeripheral_updatePHYStat(HCI_BLE_PHY_UPDATE_COMPLETE_EVENT, (uint8_t *)pMsg); + } + break; + } + + default: + break; + } + + break; + } + + default: + // do nothing + break; + } + +#ifdef PTM_MODE + // Check for NPI Messages + hciPacket_t *pBuf = (hciPacket_t *)pMsg; + + // Serialized HCI Event + if (pBuf->hdr.event == HCI_CTRL_TO_HOST_EVENT) + { + uint16_t len = 0; + + // Determine the packet length + switch(pBuf->pData[0]) + { + case HCI_EVENT_PACKET: + len = HCI_EVENT_MIN_LENGTH + pBuf->pData[2]; + break; + + case HCI_ACL_DATA_PACKET: + len = HCI_DATA_MIN_LENGTH + BUILD_UINT16(pBuf->pData[3], pBuf->pData[4]); + break; + + default: + break; + } + + // Send to Remote Host. + simple_peripheral_sendToNPI(pBuf->pData, len); + + // Free buffers if needed. + switch (pBuf->pData[0]) + { + case HCI_ACL_DATA_PACKET: + case HCI_SCO_DATA_PACKET: + BM_free(pBuf->pData); + default: + break; + } + } +#endif // PTM_MODE + + return (safeToDealloc); +} + +/********************************************************************* + * @fn SimplePeripheral_processGATTMsg + * + * @brief Process GATT messages and events. + * + * @return TRUE if safe to deallocate incoming message, FALSE otherwise. + */ +static uint8_t SimplePeripheral_processGATTMsg(gattMsgEvent_t *pMsg) +{ + if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) + { + // ATT request-response or indication-confirmation flow control is + // violated. All subsequent ATT requests or indications will be dropped. + // The app is informed in case it wants to drop the connection. + + // Display the opcode of the message that caused the violation. + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); + } + else if (pMsg->method == ATT_MTU_UPDATED_EVENT) + { + // MTU size updated + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); + } + + // Free message payload. Needed only for ATT Protocol messages + GATT_bm_free(&pMsg->msg, pMsg->method); + + // It's safe to free the incoming message + return (TRUE); +} + +/********************************************************************* + * @fn SimplePeripheral_processAppMsg + * + * @brief Process an incoming callback from a profile. + * + * @param pMsg - message to process + * + * @return None. + */ +static void SimplePeripheral_processAppMsg(spEvt_t *pMsg) +{ + bool dealloc = TRUE; + + if (pMsg->event <= APP_EVT_EVENT_MAX) + { + BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : App msg status=%d, event=%s\n", 0, appEventStrings[pMsg->event]); + } + else + { + BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : App msg status=%d, event=0x%x\n", 0, pMsg->event); + } + + switch (pMsg->event) + { + case SP_CHAR_CHANGE_EVT: + SimplePeripheral_processCharValueChangeEvt(*(uint8_t*)(pMsg->pData)); + break; + + case SP_KEY_CHANGE_EVT: + SimplePeripheral_handleKeys(*(uint8_t*)(pMsg->pData)); + break; + + case SP_ADV_EVT: + SimplePeripheral_processAdvEvent((spGapAdvEventData_t*)(pMsg->pData)); + break; + + case SP_PAIR_STATE_EVT: + SimplePeripheral_processPairState((spPairStateData_t*)(pMsg->pData)); + break; + + case SP_PASSCODE_EVT: + SimplePeripheral_processPasscode((spPasscodeData_t*)(pMsg->pData)); + break; + + case SP_PERIODIC_EVT: + SimplePeripheral_performPeriodicTask(); + break; + + case SP_READ_RPA_EVT: + SimplePeripheral_updateRPA(); + break; + + case SP_SEND_PARAM_UPDATE_EVT: + { + // Extract connection handle from data + uint16_t connHandle = *(uint16_t *)(((spClockEventData_t *)pMsg->pData)->data); + + SimplePeripheral_processParamUpdate(connHandle); + + // This data is not dynamically allocated + dealloc = FALSE; + break; + } + + case SP_CONN_EVT: + SimplePeripheral_processConnEvt((Gap_ConnEventRpt_t *)(pMsg->pData)); + break; + + default: + // Do nothing. + break; + } + + // Free message data if it exists and we are to dealloc + if ((dealloc == TRUE) && (pMsg->pData != NULL)) + { + ICall_free(pMsg->pData); + } +} + +/********************************************************************* + * @fn SimplePeripheral_processGapMessage + * + * @brief Process an incoming GAP event. + * + * @param pMsg - message to process + */ +static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) +{ + switch(pMsg->opcode) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + bStatus_t status = FAILURE; + + gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg; + + if(pPkt->hdr.status == SUCCESS) + { + // Store the system ID + uint8_t systemId[DEVINFO_SYSTEM_ID_LEN]; + + // use 6 bytes of device address for 8 bytes of system ID value + systemId[0] = pPkt->devAddr[0]; + systemId[1] = pPkt->devAddr[1]; + systemId[2] = pPkt->devAddr[2]; + + // set middle bytes to zero + systemId[4] = 0x00; + systemId[3] = 0x00; + + // shift three bytes up + systemId[7] = pPkt->devAddr[5]; + systemId[6] = pPkt->devAddr[4]; + systemId[5] = pPkt->devAddr[3]; + + // Set Device Info Service Parameter + DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId); + + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Initialized"); + + BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_DEVICE_INIT_DONE_EVENT", 0); + // Setup and start Advertising + // For more information, see the GAP section in the User's Guide: + // http://software-dl.ti.com/lprf/ble5stack-latest/ + + BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- call GapAdv_create set=%d,%d\n", 0, 0); + // Create Advertisement set #1 and assign handle + status = GapAdv_create(&SimplePeripheral_advCallback, &advParams1, + &advHandleLegacy); + //Wei + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + // Load advertising data for set #1 that is statically allocated by the app + //Wei + status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_ADV, + sizeof(advData1), advData1); + //Wei + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + // Load scan response data for set #1 that is statically allocated by the app + status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_SCAN_RSP, + sizeof(scanResData1), scanResData1); + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + // Set event mask for set #1 + status = GapAdv_setEventMask(advHandleLegacy, + GAP_ADV_EVT_MASK_START_AFTER_ENABLE | + GAP_ADV_EVT_MASK_END_AFTER_DISABLE | + GAP_ADV_EVT_MASK_SET_TERMINATED); + + // Enable legacy advertising for set #1 + status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //Wei + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- call GapAdv_create set=%d,%d\n", 1, 0); + // Create Advertisement set #2 and assign handle + status = GapAdv_create(&SimplePeripheral_advCallback, &advParams2, + &advHandleLongRange); + //Wei + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + // Load advertising data for set #2 that is statically allocated by the app + status = GapAdv_loadByHandle(advHandleLongRange, GAP_ADV_DATA_TYPE_ADV, + sizeof(advData2), advData2); + //Wei + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + // Set event mask for set #2 + status = GapAdv_setEventMask(advHandleLongRange, + GAP_ADV_EVT_MASK_START_AFTER_ENABLE | + GAP_ADV_EVT_MASK_END_AFTER_DISABLE | + GAP_ADV_EVT_MASK_SET_TERMINATED); + + BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- GapAdv_enable", 0); + // Enable long range advertising for set #2 + status = GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //Wei + //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + + // Display device address + Display_printf(dispHandle, SP_ROW_IDA, 0, "%s Addr: %s", + (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID", + Util_convertBdAddr2Str(pPkt->devAddr)); + + if (addrMode > ADDRMODE_RANDOM) + { + SimplePeripheral_updateRPA(); + + // Create one-shot clock for RPA check event. + //Wei + + Util_constructClock(&clkRpaRead,(void*)SimplePeripheral_clockHandler, READ_RPA_PERIOD, 0, true, (uint32_t)&argRpaRead); + // Util_constructClock(&clkRpaRead, SimplePeripheral_clockHandler, + // READ_RPA_PERIOD, 0, true, + // (void *)&argRpaRead); + } + tbm_setItemStatus(&spMenuMain, SP_ITEM_AUTOCONNECT, TBM_ITEM_NONE); + } + + break; + } + + case GAP_LINK_ESTABLISHED_EVENT: + { + gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg; + + BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_LINK_ESTABLISHED_EVENT", 0); + // Display the amount of current connections + uint8_t numActive = linkDB_NumActive(); + Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d", + (uint16_t)numActive); + + if (pPkt->hdr.status == SUCCESS) + { + // Add connection to list and start RSSI + SimplePeripheral_addConn(pPkt->connectionHandle); + + // Display the address of this connection + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connected to %s", + Util_convertBdAddr2Str(pPkt->devAddr)); + + // Enable connection selection option + tbm_setItemStatus(&spMenuMain, SP_ITEM_SELECT_CONN,SP_ITEM_AUTOCONNECT); + + // Start Periodic Clock. + Util_startClock(&clkPeriodic); + } + if ((numActive < MAX_NUM_BLE_CONNS) && (autoConnect == AUTOCONNECT_DISABLE)) + { + // Start advertising since there is room for more connections + GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + } + else + { + // Stop advertising since there is no room for more connections + GapAdv_disable(advHandleLongRange); + GapAdv_disable(advHandleLegacy); + } + break; + } + + case GAP_LINK_TERMINATED_EVENT: + { + gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg; + + // Display the amount of current connections + uint8_t numActive = linkDB_NumActive(); + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Device Disconnected!"); + Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d", + (uint16_t)numActive); + + // Remove the connection from the list and disable RSSI if needed + SimplePeripheral_removeConn(pPkt->connectionHandle); + + // If no active connections + if (numActive == 0) + { + // Stop periodic clock + Util_stopClock(&clkPeriodic); + + // Disable Connection Selection option + tbm_setItemStatus(&spMenuMain, SP_ITEM_AUTOCONNECT, SP_ITEM_SELECT_CONN); + } + + BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : GAP msg: status=%d, opcode=%s\n", 0, "GAP_LINK_TERMINATED_EVENT"); + // Start advertising since there is room for more connections + GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + + // Clear remaining lines + Display_clearLine(dispHandle, SP_ROW_CONNECTION); + + break; + } + + case GAP_UPDATE_LINK_PARAM_REQ_EVENT: + { + gapUpdateLinkParamReqReply_t rsp; + + gapUpdateLinkParamReqEvent_t *pReq = (gapUpdateLinkParamReqEvent_t *)pMsg; + + rsp.connectionHandle = pReq->req.connectionHandle; + rsp.signalIdentifier = pReq->req.signalIdentifier; + + // Only accept connection intervals with slave latency of 0 + // This is just an example of how the application can send a response + if(pReq->req.connLatency == 0) + { + rsp.intervalMin = pReq->req.intervalMin; + rsp.intervalMax = pReq->req.intervalMax; + rsp.connLatency = pReq->req.connLatency; + rsp.connTimeout = pReq->req.connTimeout; + rsp.accepted = TRUE; + } + else + { + rsp.accepted = FALSE; + } + + // Send Reply + VOID GAP_UpdateLinkParamReqReply(&rsp); + + break; + } + + case GAP_LINK_PARAM_UPDATE_EVENT: + { + gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; + + // Get the address from the connection handle + linkDBInfo_t linkInfo; + linkDB_GetInfo(pPkt->connectionHandle, &linkInfo); + + if(pPkt->status == SUCCESS) + { + // Display the address of the connection update + Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Link Param Updated: %s", + Util_convertBdAddr2Str(linkInfo.addr)); + } + else + { + // Display the address of the connection update failure + Display_printf(dispHandle, SP_ROW_STATUS_2, 0, + "Link Param Update Failed 0x%x: %s", pPkt->opcode, + Util_convertBdAddr2Str(linkInfo.addr)); + } + + // Check if there are any queued parameter updates + spConnHandleEntry_t *connHandleEntry = (spConnHandleEntry_t *)List_get(¶mUpdateList); + if (connHandleEntry != NULL) + { + // Attempt to send queued update now + SimplePeripheral_processParamUpdate(connHandleEntry->connHandle); + + // Free list element + ICall_free(connHandleEntry); + } + + break; + } + +#if defined ( NOTIFY_PARAM_UPDATE_RJCT ) + case GAP_LINK_PARAM_UPDATE_REJECT_EVENT: + { + linkDBInfo_t linkInfo; + gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; + + // Get the address from the connection handle + linkDB_GetInfo(pPkt->connectionHandle, &linkInfo); + + // Display the address of the connection update failure + Display_printf(dispHandle, SP_ROW_STATUS_2, 0, + "Peer Device's Update Request Rejected 0x%x: %s", pPkt->opcode, + Util_convertBdAddr2Str(linkInfo.addr)); + + break; + } +#endif + + default: + Display_clearLines(dispHandle, SP_ROW_STATUS_1, SP_ROW_STATUS_2); + break; + } +} + +/********************************************************************* + * @fn SimplePeripheral_charValueChangeCB + * + * @brief Callback from Simple Profile indicating a characteristic + * value change. + * + * @param paramId - parameter Id of the value that was changed. + * + * @return None. + */ +static void SimplePeripheral_charValueChangeCB(uint8_t paramId) +{ + uint8_t *pValue = ICall_malloc(sizeof(uint8_t)); + + if (pValue) + { + *pValue = paramId; + + if (SimplePeripheral_enqueueMsg(SP_CHAR_CHANGE_EVT, pValue) != SUCCESS) + { + ICall_free(pValue); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_processCharValueChangeEvt + * + * @brief Process a pending Simple Profile characteristic value change + * event. + * + * @param paramID - parameter ID of the value that was changed. + */ +static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId) +{ + uint8_t newValue; + + switch(paramId) + { + case SIMPLEPROFILE_CHAR1: + SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue); + + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 1: %d", (uint16_t)newValue); + break; + + case SIMPLEPROFILE_CHAR3: + SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue); + + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 3: %d", (uint16_t)newValue); + break; + + default: + // should not reach here! + break; + } +} + +/********************************************************************* + * @fn SimplePeripheral_performPeriodicTask + * + * @brief Perform a periodic application task. This function gets called + * every five seconds (SP_PERIODIC_EVT_PERIOD). In this example, + * the value of the third characteristic in the SimpleGATTProfile + * service is retrieved from the profile, and then copied into the + * value of the the fourth characteristic. + * + * @param None. + * + * @return None. + */ +static void SimplePeripheral_performPeriodicTask(void) +{ + uint8_t valueToCopy; + + // Call to retrieve the value of the third characteristic in the profile + if (SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &valueToCopy) == SUCCESS) + { + // Call to set that value of the fourth characteristic in the profile. + // Note that if notifications of the fourth characteristic have been + // enabled by a GATT client device, then a notification will be sent + // every time this function is called. + SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t), + &valueToCopy); + } +} + +/********************************************************************* + * @fn SimplePeripheral_updateRPA + * + * @brief Read the current RPA from the stack and update display + * if the RPA has changed. + * + * @param None. + * + * @return None. + */ +static void SimplePeripheral_updateRPA(void) +{ + uint8_t* pRpaNew; + + // Read the current RPA. + pRpaNew = GAP_GetDevAddress(FALSE); + + if (memcmp(pRpaNew, rpa, B_ADDR_LEN)) + { + // If the RPA has changed, update the display + Display_printf(dispHandle, SP_ROW_RPA, 0, "RP Addr: %s", + Util_convertBdAddr2Str(pRpaNew)); + memcpy(rpa, pRpaNew, B_ADDR_LEN); + } +} + +/********************************************************************* + * @fn SimplePeripheral_clockHandler + * + * @brief Handler function for clock timeouts. + * + * @param arg - event type + * + * @return None. + */ + //Wei +static void SimplePeripheral_clockHandler(void *arg) +{ + spClockEventData_t *pData = (spClockEventData_t *)arg; + + if (pData->event == SP_PERIODIC_EVT) + { + // Start the next period + Util_startClock(&clkPeriodic); + + // Post event to wake up the application + SimplePeripheral_enqueueMsg(SP_PERIODIC_EVT, NULL); + } + else if (pData->event == SP_READ_RPA_EVT) + { + // Start the next period + Util_startClock(&clkRpaRead); + + // Post event to read the current RPA + SimplePeripheral_enqueueMsg(SP_READ_RPA_EVT, NULL); + } + else if (pData->event == SP_SEND_PARAM_UPDATE_EVT) + { + // Send message to app + SimplePeripheral_enqueueMsg(SP_SEND_PARAM_UPDATE_EVT, pData); + } +} + +/********************************************************************* + * @fn SimplePeripheral_keyChangeHandler + * + * @brief Key event handler function + * + * @param keys - bitmap of pressed keys + * + * @return none + */ +static void SimplePeripheral_keyChangeHandler(uint8_t keys) +{ + uint8_t *pValue = ICall_malloc(sizeof(uint8_t)); + + if (pValue) + { + *pValue = keys; + + if(SimplePeripheral_enqueueMsg(SP_KEY_CHANGE_EVT, pValue) != SUCCESS) + { + ICall_free(pValue); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_handleKeys + * + * @brief Handles all key events for this device. + * + * @param keys - bit field for key events. Valid entries: + * KEY_LEFT + * KEY_RIGHT + */ +static void SimplePeripheral_handleKeys(uint8_t keys) +{ + if (keys & KEY_LEFT) + { + // Check if the key is still pressed. Workaround for possible bouncing. + if (GPIO_read(CONFIG_GPIO_BTN1) == 0) + { + tbm_buttonLeft(); + } + } + else if (keys & KEY_RIGHT) + { + // Check if the key is still pressed. Workaround for possible bouncing. + if (GPIO_read(CONFIG_GPIO_BTN2) == 0) + { + tbm_buttonRight(); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_doSetConnPhy + * + * @brief Set PHY preference. + * + * @param index - 0: 1M PHY + * 1: 2M PHY + * 2: 1M + 2M PHY + * 3: CODED PHY (Long range) + * 4: 1M + 2M + CODED PHY + * + * @return always true + */ +bool SimplePeripheral_doSetConnPhy(uint8 index) +{ + bool status = TRUE; + + static uint8_t phy[] = { + HCI_PHY_1_MBPS, HCI_PHY_2_MBPS, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS, + HCI_PHY_CODED, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS | HCI_PHY_CODED, + AUTO_PHY_UPDATE + }; + + uint8_t connIndex = SimplePeripheral_getConnIndex(menuConnHandle); + if (connIndex >= MAX_NUM_BLE_CONNS) + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); + return FALSE; + } + + // Set Phy Preference on the current connection. Apply the same value + // for RX and TX. + // If auto PHY update is not selected and if auto PHY update is enabled, then + // stop auto PHY update + // Note PHYs are already enabled by default in build_config.opt in stack project. + if(phy[index] != AUTO_PHY_UPDATE) + { + // Cancel RSSI reading and auto phy changing + SimplePeripheral_stopAutoPhyChange(connList[connIndex].connHandle); + + SimplePeripheral_setPhy(menuConnHandle, 0, phy[index], phy[index], 0); + + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "PHY preference: %s", + TBM_GET_ACTION_DESC(&spMenuConnPhy, index)); + } + else + { + // Start RSSI read for auto PHY update (if it is disabled) + SimplePeripheral_startAutoPhyChange(menuConnHandle); + } + + return status; +} +/********************************************************************* + * @fn SimplePeripheral_advCallback + * + * @brief GapAdv module callback + * + * @param pMsg - message to process + */ +static void SimplePeripheral_advCallback(uint32_t event, void *pBuf, uintptr_t arg) +{ + spGapAdvEventData_t *pData = ICall_malloc(sizeof(spGapAdvEventData_t)); + + if (pData) + { + pData->event = event; + pData->pBuf = pBuf; + + if(SimplePeripheral_enqueueMsg(SP_ADV_EVT, pData) != SUCCESS) + { + ICall_free(pData); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_processAdvEvent + * + * @brief Process advertising event in app context + * + * @param pEventData + */ +static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData) +{ + switch (pEventData->event) + { + case GAP_EVT_ADV_START_AFTER_ENABLE: + BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- GAP_EVT_ADV_START_AFTER_ENABLE", 0); + Display_printf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d Enabled", + *(uint8_t *)(pEventData->pBuf)); + break; + + case GAP_EVT_ADV_END_AFTER_DISABLE: + Display_doPrintf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d Disabled", + *(uint8_t *)(pEventData->pBuf)); + break; + + case GAP_EVT_ADV_START: + break; + + case GAP_EVT_ADV_END: + break; + + case GAP_EVT_ADV_SET_TERMINATED: + { +#ifndef Display_DISABLE_ALL + GapAdv_setTerm_t *advSetTerm = (GapAdv_setTerm_t *)(pEventData->pBuf); + + Display_printf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d disabled after conn %d", + advSetTerm->handle, advSetTerm->connHandle ); +#endif + } + break; + + case GAP_EVT_SCAN_REQ_RECEIVED: + break; + + case GAP_EVT_INSUFFICIENT_MEMORY: + break; + + default: + break; + } + + // All events have associated memory to free except the insufficient memory + // event + if (pEventData->event != GAP_EVT_INSUFFICIENT_MEMORY) + { + ICall_free(pEventData->pBuf); + } +} + + +/********************************************************************* + * @fn SimplePeripheral_pairStateCb + * + * @brief Pairing state callback. + * + * @return none + */ +static void SimplePeripheral_pairStateCb(uint16_t connHandle, uint8_t state, + uint8_t status) +{ + spPairStateData_t *pData = ICall_malloc(sizeof(spPairStateData_t)); + + // Allocate space for the event data. + if (pData) + { + pData->state = state; + pData->connHandle = connHandle; + pData->status = status; + + // Queue the event. + if(SimplePeripheral_enqueueMsg(SP_PAIR_STATE_EVT, pData) != SUCCESS) + { + ICall_free(pData); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_passcodeCb + * + * @brief Passcode callback. + * + * @return none + */ +static void SimplePeripheral_passcodeCb(uint8_t *pDeviceAddr, + uint16_t connHandle, + uint8_t uiInputs, + uint8_t uiOutputs, + uint32_t numComparison) +{ + spPasscodeData_t *pData = ICall_malloc(sizeof(spPasscodeData_t)); + + // Allocate space for the passcode event. + if (pData ) + { + pData->connHandle = connHandle; + memcpy(pData->deviceAddr, pDeviceAddr, B_ADDR_LEN); + pData->uiInputs = uiInputs; + pData->uiOutputs = uiOutputs; + pData->numComparison = numComparison; + + // Enqueue the event. + if(SimplePeripheral_enqueueMsg(SP_PASSCODE_EVT, pData) != SUCCESS) + { + ICall_free(pData); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_processPairState + * + * @brief Process the new paring state. + * + * @return none + */ +static void SimplePeripheral_processPairState(spPairStateData_t *pPairData) +{ + uint8_t state = pPairData->state; + uint8_t status = pPairData->status; + + switch (state) + { + case GAPBOND_PAIRING_STATE_STARTED: + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing started"); + break; + + case GAPBOND_PAIRING_STATE_COMPLETE: + if (status == SUCCESS) + { + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing success"); + } + else + { + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing fail: %d", status); + } + break; + + case GAPBOND_PAIRING_STATE_ENCRYPTED: + if (status == SUCCESS) + { + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Encryption success"); + } + else + { + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Encryption failed: %d", status); + } + break; + + case GAPBOND_PAIRING_STATE_BOND_SAVED: + if (status == SUCCESS) + { + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Bond save success"); + } + else + { + Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Bond save failed: %d", status); + } + break; + + default: + break; + } +} + +/********************************************************************* + * @fn SimplePeripheral_processPasscode + * + * @brief Process the Passcode request. + * + * @return none + */ +static void SimplePeripheral_processPasscode(spPasscodeData_t *pPasscodeData) +{ + // Display passcode to user + if (pPasscodeData->uiOutputs != 0) + { + Display_doPrintf(dispHandle, SP_ROW_CONNECTION, 0, "Passcode: %d", + B_APP_DEFAULT_PASSCODE); + } + + // Send passcode response + GAPBondMgr_PasscodeRsp(pPasscodeData->connHandle , SUCCESS, + B_APP_DEFAULT_PASSCODE); +} + +/********************************************************************* + * @fn SimplePeripheral_connEvtCB + * + * @brief Connection event callback. + * + * @param pReport pointer to connection event report + */ +static void SimplePeripheral_connEvtCB(Gap_ConnEventRpt_t *pReport) +{ + // Enqueue the event for processing in the app context. + if(SimplePeripheral_enqueueMsg(SP_CONN_EVT, pReport) != SUCCESS) + { + ICall_free(pReport); + } +} + +/********************************************************************* + * @fn SimplePeripheral_processConnEvt + * + * @brief Process connection event. + * + * @param pReport pointer to connection event report + */ +static void SimplePeripheral_processConnEvt(Gap_ConnEventRpt_t *pReport) +{ + // Get index from handle + uint8_t connIndex = SimplePeripheral_getConnIndex(pReport->handle); + + if (connIndex >= MAX_NUM_BLE_CONNS) + { + Display_doPrintf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); + return; + } + + // If auto phy change is enabled + if (connList[connIndex].isAutoPHYEnable == TRUE) + { + // Read the RSSI + HCI_ReadRssiCmd(pReport->handle); + } +} + + +/********************************************************************* + * @fn SimplePeripheral_enqueueMsg + * + * @brief Creates a message and puts the message in RTOS queue. + * + * @param event - message event. + * @param state - message state. + */ +static status_t SimplePeripheral_enqueueMsg(uint8_t event, void *pData) +{ + uint8_t success; + spEvt_t *pMsg = ICall_malloc(sizeof(spEvt_t)); + + // Create dynamic pointer to message. + if(pMsg) + { + pMsg->event = event; + pMsg->pData = pData; + + // Enqueue the message. + success = Util_enqueueMsg(g_POSIX_appMsgQueue, syncEvent, (uint8_t *)pMsg); + return (success) ? SUCCESS : FAILURE; + } + + return(bleMemAllocError); +} + +/********************************************************************* + * @fn SimplePeripheral_doSelectConn + * + * @brief Select a connection to communicate with + * + * @param index - item index from the menu + * + * @return always true + */ +bool SimplePeripheral_doSelectConn(uint8_t index) +{ + menuConnHandle = connList[index].connHandle; + + // Set the menu title and go to this connection's context + TBM_SET_TITLE(&spMenuPerConn, TBM_GET_ACTION_DESC(&spMenuSelectConn, index)); + + // Clear non-connection-related message + Display_clearLine(dispHandle, SP_ROW_CONNECTION); + + tbm_goTo(&spMenuPerConn); + + return (true); +} +/********************************************************************* + * @fn SimplePeripheral_doAutoConnect + * + * @brief Enable/Disable peripheral as AutoConnect node. + * + * @param index - 0 : Disable AutoConnect + * 1 : Enable Group A + * 2 : Enable Group B + * + * @return always true + */ +bool SimplePeripheral_doAutoConnect(uint8_t index) +{ + if (index == 1) + { + if (autoConnect != AUTOCONNECT_GROUP_A) + { + GapAdv_disable(advHandleLongRange); + GapAdv_disable(advHandleLegacy); + advData1[2] = 'G'; + advData1[3] = 'A'; + advData2[2] = 'G'; + advData2[3] = 'A'; + GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + autoConnect = AUTOCONNECT_GROUP_A; + } + Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group A"); + } + else if (index == 2) + { + if (autoConnect != AUTOCONNECT_GROUP_B) + { + GapAdv_disable(advHandleLongRange); + GapAdv_disable(advHandleLegacy); + advData1[2] = 'G'; + advData1[3] = 'B'; + advData2[2] = 'G'; + advData2[3] = 'B'; + GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + autoConnect = AUTOCONNECT_GROUP_B; + } + Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group B"); + } + else + { + if (autoConnect) + { + GapAdv_disable(advHandleLongRange); + GapAdv_disable(advHandleLegacy); + advData1[2] = 'S'; + advData1[3] = 'P'; + advData2[2] = 'S'; + advData2[3] = 'P'; + GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + autoConnect = AUTOCONNECT_DISABLE; + } + Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect disabled"); + } + tbm_goTo(&spMenuMain); + + return (true); +} + + +/********************************************************************* + * @fn SimplePeripheral_addConn + * + * @brief Add a device to the connected device list + * + * @return index of the connected device list entry where the new connection + * info is put in. + * if there is no room, MAX_NUM_BLE_CONNS will be returned. + */ +static uint8_t SimplePeripheral_addConn(uint16_t connHandle) +{ + uint8_t i; + uint8_t status = bleNoResources; + + // Try to find an available entry + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if (connList[i].connHandle == LINKDB_CONNHANDLE_INVALID) + { + // Found available entry to put a new connection info in + connList[i].connHandle = connHandle; + +#ifdef DEFAULT_SEND_PARAM_UPDATE_REQ + // Allocate data to send through clock handler + connList[i].pParamUpdateEventData = ICall_malloc(sizeof(spClockEventData_t) + + sizeof (uint16_t)); + if(connList[i].pParamUpdateEventData) + { + connList[i].pParamUpdateEventData->event = SP_SEND_PARAM_UPDATE_EVT; + *((uint16_t *)connList[i].pParamUpdateEventData->data) = connHandle; + + // Create a clock object and start + connList[i].pUpdateClock + = (Clock_Struct*) ICall_malloc(sizeof(Clock_Struct)); + + if (connList[i].pUpdateClock) + { + //Wei + Util_constructClock(connList[i].pUpdateClock, + (void *)SimplePeripheral_clockHandler, + SEND_PARAM_UPDATE_DELAY, 0, true, + (uint32_t)&connList[i].pParamUpdateEventData); + } + else + { + ICall_free(connList[i].pParamUpdateEventData); + } + } + else + { + status = bleMemAllocError; + } +#endif + + // Set default PHY to 1M + connList[i].currPhy = HCI_PHY_1_MBPS; + + break; + } + } + + return status; +} + +/********************************************************************* + * @fn SimplePeripheral_getConnIndex + * + * @brief Find index in the connected device list by connHandle + * + * @return the index of the entry that has the given connection handle. + * if there is no match, MAX_NUM_BLE_CONNS will be returned. + */ +static uint8_t SimplePeripheral_getConnIndex(uint16_t connHandle) +{ + uint8_t i; + + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if (connList[i].connHandle == connHandle) + { + return i; + } + } + + return(MAX_NUM_BLE_CONNS); +} + +/********************************************************************* + * @fn SimplePeripheral_getConnIndex + * + * @brief Find index in the connected device list by connHandle + * + * @return SUCCESS if connHandle found valid index or bleInvalidRange + * if index wasn't found. LINKDB_CONNHANDLE_ALL will always succeed. + */ +static uint8_t SimplePeripheral_clearConnListEntry(uint16_t connHandle) +{ + uint8_t i; + // Set to invalid connection index initially + uint8_t connIndex = MAX_NUM_BLE_CONNS; + + if(connHandle != LINKDB_CONNHANDLE_ALL) + { + // Get connection index from handle + connIndex = SimplePeripheral_getConnIndex(connHandle); + if(connIndex >= MAX_NUM_BLE_CONNS) + { + return(bleInvalidRange); + } + } + + // Clear specific handle or all handles + for(i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if((connIndex == i) || (connHandle == LINKDB_CONNHANDLE_ALL)) + { + connList[i].connHandle = LINKDB_CONNHANDLE_INVALID; + connList[i].currPhy = 0; + connList[i].phyCngRq = 0; + connList[i].phyRqFailCnt = 0; + connList[i].rqPhy = 0; + memset(connList[i].rssiArr, 0, SP_MAX_RSSI_STORE_DEPTH); + connList[i].rssiAvg = 0; + connList[i].rssiCntr = 0; + connList[i].isAutoPHYEnable = FALSE; + } + } + + return(SUCCESS); +} + +/********************************************************************* + * @fn SimplePeripheral_clearPendingParamUpdate + * + * @brief clean pending param update request in the paramUpdateList list + * + * @param connHandle - connection handle to clean + * + * @return none + */ +void SimplePeripheral_clearPendingParamUpdate(uint16_t connHandle) +{ + List_Elem *curr; + + for (curr = List_head(¶mUpdateList); curr != NULL; curr = List_next(curr)) + { + if (((spConnHandleEntry_t *)curr)->connHandle == connHandle) + { + List_remove(¶mUpdateList, curr); + } + } +} + +/********************************************************************* + * @fn SimplePeripheral_removeConn + * + * @brief Remove a device from the connected device list + * + * @return index of the connected device list entry where the new connection + * info is removed from. + * if connHandle is not found, MAX_NUM_BLE_CONNS will be returned. + */ +static uint8_t SimplePeripheral_removeConn(uint16_t connHandle) +{ + uint8_t connIndex = SimplePeripheral_getConnIndex(connHandle); + + if(connIndex != MAX_NUM_BLE_CONNS) + { + Clock_Struct* pUpdateClock = connList[connIndex].pUpdateClock; + + if (pUpdateClock != NULL) + { + // Stop and destruct the RTOS clock if it's still alive + if (Util_isActive(pUpdateClock)) + { + Util_stopClock(pUpdateClock); + } + + // Destruct the clock object + Clock_destruct(pUpdateClock); + // Free clock struct + ICall_free(pUpdateClock); + // Free ParamUpdateEventData + ICall_free(connList[connIndex].pParamUpdateEventData); + } + // Clear pending update requests from paramUpdateList + SimplePeripheral_clearPendingParamUpdate(connHandle); + // Stop Auto PHY Change + SimplePeripheral_stopAutoPhyChange(connHandle); + // Clear Connection List Entry + SimplePeripheral_clearConnListEntry(connHandle); + } + + return connIndex; +} + +/********************************************************************* + * @fn SimplePeripheral_processParamUpdate + * + * @brief Process a parameters update request + * + * @return None + */ +static void SimplePeripheral_processParamUpdate(uint16_t connHandle) +{ + gapUpdateLinkParamReq_t req; + uint8_t connIndex; + + req.connectionHandle = connHandle; +#ifdef DEFAULT_SEND_PARAM_UPDATE_REQ + req.connLatency = DEFAULT_DESIRED_SLAVE_LATENCY; + req.connTimeout = DEFAULT_DESIRED_CONN_TIMEOUT; + req.intervalMin = DEFAULT_DESIRED_MIN_CONN_INTERVAL; + req.intervalMax = DEFAULT_DESIRED_MAX_CONN_INTERVAL; +#endif + + connIndex = SimplePeripheral_getConnIndex(connHandle); + if (connIndex >= MAX_NUM_BLE_CONNS) + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); + return; + } + + // Deconstruct the clock object + Clock_destruct(connList[connIndex].pUpdateClock); + // Free clock struct, only in case it is not NULL + if (connList[connIndex].pUpdateClock != NULL) + { + ICall_free(connList[connIndex].pUpdateClock); + connList[connIndex].pUpdateClock = NULL; + } + // Free ParamUpdateEventData, only in case it is not NULL + if (connList[connIndex].pParamUpdateEventData != NULL) + ICall_free(connList[connIndex].pParamUpdateEventData); + + // Send parameter update + bStatus_t status = GAP_UpdateLinkParamReq(&req); + + // If there is an ongoing update, queue this for when the udpate completes + if (status == bleAlreadyInRequestedMode) + { + spConnHandleEntry_t *connHandleEntry = ICall_malloc(sizeof(spConnHandleEntry_t)); + if (connHandleEntry) + { + connHandleEntry->connHandle = connHandle; + + List_put(¶mUpdateList, (List_Elem *)connHandleEntry); + } + } +} + +/********************************************************************* + * @fn SimpleCentral_processCmdCompleteEvt + * + * @brief Process an incoming OSAL HCI Command Complete Event. + * + * @param pMsg - message to process + * + * @return none + */ +static void SimplePeripheral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg) +{ + uint8_t status = pMsg->pReturnParam[0]; + + //Find which command this command complete is for + switch (pMsg->cmdOpcode) + { + case HCI_READ_RSSI: + { + int8 rssi = (int8)pMsg->pReturnParam[3]; + + // Display RSSI value, if RSSI is higher than threshold, change to faster PHY + if (status == SUCCESS) + { + uint16_t handle = BUILD_UINT16(pMsg->pReturnParam[1], pMsg->pReturnParam[2]); + + uint8_t index = SimplePeripheral_getConnIndex(handle); + if (index >= MAX_NUM_BLE_CONNS) + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); + return; + } + + if (rssi != LL_RSSI_NOT_AVAILABLE) + { + connList[index].rssiArr[connList[index].rssiCntr++] = rssi; + connList[index].rssiCntr %= SP_MAX_RSSI_STORE_DEPTH; + + int16_t sum_rssi = 0; + for(uint8_t cnt=0; cnt= RSSI_2M_THRSHLD) && + (connList[index].currPhy != HCI_PHY_2_MBPS) && + (connList[index].currPhy != SP_PHY_NONE)) + { + // try to go to higher data rate + phyRqS = phyRq = HCI_PHY_2_MBPS; + } + else if((connList[index].rssiAvg < RSSI_2M_THRSHLD) && + (connList[index].rssiAvg >= RSSI_1M_THRSHLD) && + (connList[index].currPhy != HCI_PHY_1_MBPS) && + (connList[index].currPhy != SP_PHY_NONE)) + { + // try to go to legacy regular data rate + phyRqS = phyRq = HCI_PHY_1_MBPS; + } + else if((connList[index].rssiAvg >= RSSI_S2_THRSHLD) && + (connList[index].rssiAvg < RSSI_1M_THRSHLD) && + (connList[index].currPhy != SP_PHY_NONE)) + { + // try to go to lower data rate S=2(500kb/s) + phyRqS = HCI_PHY_CODED; + phyOpt = LL_PHY_OPT_S2; + phyRq = BLE5_CODED_S2_PHY; + } + else if(connList[index].rssiAvg < RSSI_S2_THRSHLD ) + { + // try to go to lowest data rate S=8(125kb/s) + phyRqS = HCI_PHY_CODED; + phyOpt = LL_PHY_OPT_S8; + phyRq = BLE5_CODED_S8_PHY; + } + if((phyRq != SP_PHY_NONE) && + // First check if the request for this phy change is already not honored then don't request for change + (((connList[index].rqPhy == phyRq) && + (connList[index].phyRqFailCnt < 2)) || + (connList[index].rqPhy != phyRq))) + { + //Initiate PHY change based on RSSI + SimplePeripheral_setPhy(connList[index].connHandle, 0, + phyRqS, phyRqS, phyOpt); + connList[index].phyCngRq = TRUE; + + // If it a request for different phy than failed request, reset the count + if(connList[index].rqPhy != phyRq) + { + // then reset the request phy counter and requested phy + connList[index].phyRqFailCnt = 0; + } + + if(phyOpt == LL_PHY_OPT_NONE) + { + connList[index].rqPhy = phyRq; + } + else if(phyOpt == LL_PHY_OPT_S2) + { + connList[index].rqPhy = BLE5_CODED_S2_PHY; + } + else + { + connList[index].rqPhy = BLE5_CODED_S8_PHY; + } + + } // end of if ((phyRq != SP_PHY_NONE) && ... + } // end of if (connList[index].phyCngRq == FALSE) + } // end of if (rssi != LL_RSSI_NOT_AVAILABLE) + + Display_printf(dispHandle, SP_ROW_RSSI, 0, + "RSSI:%d dBm, AVG RSSI:%d dBm", + (uint32_t)(rssi), + connList[index].rssiAvg); + + } // end of if (status == SUCCESS) + break; + } + + case HCI_LE_READ_PHY: + { + if (status == SUCCESS) + { + Display_printf(dispHandle, SP_ROW_RSSI + 2, 0, "RXPh: %d, TXPh: %d", + pMsg->pReturnParam[3], pMsg->pReturnParam[4]); + } + break; + } + + default: + break; + } // end of switch (pMsg->cmdOpcode) +} + +/********************************************************************* +* @fn SimplePeripheral_initPHYRSSIArray +* +* @brief Initializes the array of structure/s to store data related +* RSSI based auto PHy change +* +* @param connHandle - the connection handle +* +* @param addr - pointer to device address +* +* @return index of connection handle +*/ +static void SimplePeripheral_initPHYRSSIArray(void) +{ + //Initialize array to store connection handle and RSSI values + memset(connList, 0, sizeof(connList)); + for (uint8_t index = 0; index < MAX_NUM_BLE_CONNS; index++) + { + connList[index].connHandle = SP_INVALID_HANDLE; + } +} +/********************************************************************* + // Set default PHY to 1M + * @fn SimplePeripheral_startAutoPhyChange + * + * @brief Start periodic RSSI reads on a link. + * + * @param connHandle - connection handle of link + * @param devAddr - device address + * + * @return SUCCESS: Terminate started + * bleIncorrectMode: No link + * bleNoResources: No resources + */ +static status_t SimplePeripheral_startAutoPhyChange(uint16_t connHandle) +{ + status_t status = FAILURE; + + // Get connection index from handle + uint8_t connIndex = SimplePeripheral_getConnIndex(connHandle); + //Wei + //SIMPLEPERIPHERAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS); + + // Start Connection Event notice for RSSI calculation + status = Gap_RegisterConnEventCb(SimplePeripheral_connEvtCB, GAP_CB_REGISTER, GAP_CB_CONN_EVENT_ALL, connHandle); + + // Flag in connection info if successful + if (status == SUCCESS) + { + connList[connIndex].isAutoPHYEnable = TRUE; + } + + return status; +} + +/********************************************************************* + * @fn SimplePeripheral_stopAutoPhyChange + * + * @brief Cancel periodic RSSI reads on a link. + * + * @param connHandle - connection handle of link + * + * @return SUCCESS: Operation successful + * bleIncorrectMode: No link + */ +static status_t SimplePeripheral_stopAutoPhyChange(uint16_t connHandle) +{ + // Get connection index from handle + uint8_t connIndex = SimplePeripheral_getConnIndex(connHandle); + //Wei + //SIMPLEPERIPHERAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS); + + // Stop connection event notice + Gap_RegisterConnEventCb(NULL, GAP_CB_UNREGISTER, GAP_CB_CONN_EVENT_ALL, connHandle); + + // Also update the phychange request status for active RSSI tracking connection + connList[connIndex].phyCngRq = FALSE; + connList[connIndex].isAutoPHYEnable = FALSE; + + return SUCCESS; +} + +/********************************************************************* + * @fn SimplePeripheral_setPhy + * + * @brief Call the HCI set phy API and and add the handle to a + * list to match it to an incoming command status event + */ +static status_t SimplePeripheral_setPhy(uint16_t connHandle, uint8_t allPhys, + uint8_t txPhy, uint8_t rxPhy, + uint16_t phyOpts) +{ + // Allocate list entry to store handle for command status + spConnHandleEntry_t *connHandleEntry = ICall_malloc(sizeof(spConnHandleEntry_t)); + + if (connHandleEntry) + { + connHandleEntry->connHandle = connHandle; + + // Add entry to the phy command status list + List_put(&setPhyCommStatList, (List_Elem *)connHandleEntry); + + // Send PHY Update + HCI_LE_SetPhyCmd(connHandle, allPhys, txPhy, rxPhy, phyOpts); + } + + return SUCCESS; +} + +/********************************************************************* +* @fn SimplePeripheral_updatePHYStat +* +* @brief Update the auto phy update state machine +* +* @param connHandle - the connection handle +* +* @return None +*/ +static void SimplePeripheral_updatePHYStat(uint16_t eventCode, uint8_t *pMsg) +{ + uint8_t connIndex; + + switch (eventCode) + { + case HCI_LE_SET_PHY: + { + // Get connection handle from list + spConnHandleEntry_t *connHandleEntry = + (spConnHandleEntry_t *)List_get(&setPhyCommStatList); + + if (connHandleEntry) + { + // Get index from connection handle + connIndex = SimplePeripheral_getConnIndex(connHandleEntry->connHandle); + + ICall_free(connHandleEntry); + + // Is this connection still valid? + if (connIndex < MAX_NUM_BLE_CONNS) + { + hciEvt_CommandStatus_t *pMyMsg = (hciEvt_CommandStatus_t *)pMsg; + + if (pMyMsg->cmdStatus == HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE) + { + // Update the phychange request status for active RSSI tracking connection + connList[connIndex].phyCngRq = FALSE; + connList[connIndex].phyRqFailCnt++; + } + } + } + break; + } + + // LE Event - a Phy update has completed or failed + case HCI_BLE_PHY_UPDATE_COMPLETE_EVENT: + { + hciEvt_BLEPhyUpdateComplete_t *pPUC = + (hciEvt_BLEPhyUpdateComplete_t*) pMsg; + + if(pPUC) + { + // Get index from connection handle + connIndex = SimplePeripheral_getConnIndex(pPUC->connHandle); + + // Is this connection still valid? + if (connIndex < MAX_NUM_BLE_CONNS) + { + // Update the phychange request status for active RSSI tracking connection + connList[connIndex].phyCngRq = FALSE; + + if (pPUC->status == SUCCESS) + { + connList[connIndex].currPhy = pPUC->rxPhy; + } + if(pPUC->rxPhy != connList[connIndex].rqPhy) + { + connList[connIndex].phyRqFailCnt++; + } + else + { + // Reset the request phy counter and requested phy + connList[connIndex].phyRqFailCnt = 0; + connList[connIndex].rqPhy = 0; + } + } + } + + break; + } + + default: + break; + } // end of switch (eventCode) +} + +/********************************************************************* + * @fn SimplePeripheral_menuSwitchCb + * + * @brief Detect menu context switching + * + * @param pMenuObjCurr - the current menu object + * @param pMenuObjNext - the menu object the context is about to switch to + * + * @return none + */ +static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, + tbmMenuObj_t* pMenuObjNext) +{ + uint8_t NUMB_ACTIVE_CONNS = linkDB_NumActive(); + + // interested in only the events of + // entering scMenuConnect, spMenuSelectConn, and scMenuMain for now + if (pMenuObjNext == &spMenuSelectConn) + { + static uint8_t* pAddrs; + uint8_t* pAddrTemp; + + if (pAddrs != NULL) + { + ICall_free(pAddrs); + } + + // Allocate buffer to display addresses + pAddrs = ICall_malloc(NUMB_ACTIVE_CONNS * SP_ADDR_STR_SIZE); + + if (pAddrs == NULL) + { + TBM_SET_NUM_ITEM(&spMenuSelectConn, 0); + } + else + { + uint8_t i; + + TBM_SET_NUM_ITEM(&spMenuSelectConn, MAX_NUM_BLE_CONNS); + + pAddrTemp = pAddrs; + + // Add active connection info to the menu object + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if (connList[i].connHandle != LINKDB_CONNHANDLE_INVALID) + { + // Get the address from the connection handle + linkDBInfo_t linkInfo; + linkDB_GetInfo(connList[i].connHandle, &linkInfo); + // This connection is active. Set the corresponding menu item with + // the address of this connection and enable the item. + memcpy(pAddrTemp, Util_convertBdAddr2Str(linkInfo.addr), + SP_ADDR_STR_SIZE); + TBM_SET_ACTION_DESC(&spMenuSelectConn, i, pAddrTemp); + tbm_setItemStatus(&spMenuSelectConn, (1 << i), SP_ITEM_NONE); + pAddrTemp += SP_ADDR_STR_SIZE; + } + else + { + // This connection is not active. Disable the corresponding menu item. + tbm_setItemStatus(&spMenuSelectConn, SP_ITEM_NONE, (1 << i)); + } + } + } + } + else if (pMenuObjNext == &spMenuMain) + { + // Now we are not in a specific connection's context + + // Clear connection-related message + Display_clearLine(dispHandle, SP_ROW_CONNECTION); + } +} +/********************************************************************* +*********************************************************************/ + +static void bleStack_init(void) +{ + bleStack_buildMenu(); + + //Register the current thread as an ICall dispatcher application + ICall_registerApp(&selfEntity, &syncEvent); + +#ifdef USE_RCOSC + // Set device's Sleep Clock Accuracy +#if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) ) + HCI_EXT_SetSCACmd(500); +#endif // (CENTRAL_CFG | PERIPHERAL_CFG) + RCOSC_enableCalibration(); +#endif // USE_RCOSC + + // Create an RTOS queue for message from profile to be sent to app. + //Wei + //appMsgQueueHandle = Util_constructQueue(&appMsgQueue); + Util_constructQueue(&g_POSIX_appMsgQueue); + + // Create one-shot clock for internal periodic events. + //Wei + Util_constructClock(&clkPeriodic, (void *)SimplePeripheral_clockHandler, + SP_PERIODIC_EVT_PERIOD, 0, false, (uint32_t)&argPeriodic); + + // Set the Device Name characteristic in the GAP GATT Service + // For more information, see the section in the User's Guide: + // http://software-dl.ti.com/lprf/ble5stack-latest/ + GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName); + + // Configure GAP + { + uint16_t paramUpdateDecision = DEFAULT_PARAM_UPDATE_REQ_DECISION; + + // Pass all parameter update requests to the app for it to decide + GAP_SetParamValue(GAP_PARAM_LINK_UPDATE_DECISION, paramUpdateDecision); + } + + // Setup the GAP Bond Manager. For more information see the GAP Bond Manager + // section in the User's Guide + setBondManagerParameters(); + // Initialize GATT attributes + GGS_AddService(GAP_SERVICE); // GAP GATT Service + GATTServApp_AddService(GATT_ALL_SERVICES); // GATT Service + DevInfo_AddService(); // Device Information Service + SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile + + // Setup the SimpleProfile Characteristic Values + // For more information, see the GATT and GATTServApp sections in the User's Guide: + // http://software-dl.ti.com/lprf/ble5stack-latest/ + { + uint8_t charValue1 = 1; + uint8_t charValue2 = 2; + uint8_t charValue3 = 3; + uint8_t charValue4 = 4; + uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 }; + + SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t), + &charValue1); + SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t), + &charValue2); + SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t), + &charValue3); + SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t), + &charValue4); + SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN, + charValue5); + } + + // Register callback with SimpleGATTprofile + SimpleProfile_RegisterAppCBs(&SimplePeripheral_simpleProfileCBs); + + // Start Bond Manager and register callback + VOID GAPBondMgr_Register(&SimplePeripheral_BondMgrCBs); + + // Register with GAP for HCI/Host messages. This is needed to receive HCI + // events. For more information, see the HCI section in the User's Guide: + // http://software-dl.ti.com/lprf/ble5stack-latest/ + GAP_RegisterForMsgs(selfEntity); + + // Register for GATT local events and ATT Responses pending for transmission + GATT_RegisterForMsgs(selfEntity); + + // Set default values for Data Length Extension + // Extended Data Length Feature is already enabled by default + { + // Set initial values to maximum, RX is set to max. by default(251 octets, 2120us) + // Some brand smartphone is essentially needing 251/2120, so we set them here. + #define APP_SUGGESTED_PDU_SIZE 251 //default is 27 octets(TX) + #define APP_SUGGESTED_TX_TIME 2120 //default is 328us(TX) + + // This API is documented in hci.h + // See the LE Data Length Extension section in the BLE5-Stack User's Guide for information on using this command: + // http://software-dl.ti.com/lprf/ble5stack-latest/ + HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE, APP_SUGGESTED_TX_TIME); + } + + // Initialize GATT Client + GATT_InitClient(); + + // Init key debouncer + Board_initKeys(SimplePeripheral_keyChangeHandler); + + // Initialize Connection List + SimplePeripheral_clearConnListEntry(LINKDB_CONNHANDLE_ALL); + + BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- call GAP_DeviceInit", GAP_PROFILE_PERIPHERAL); + //Initialize GAP layer for Peripheral role and register to receive GAP events + GAP_DeviceInit(GAP_PROFILE_PERIPHERAL, selfEntity, addrMode, &pRandomAddress); + + // Initialize array to store connection handle and RSSI values + SimplePeripheral_initPHYRSSIArray(); + + // The type of display is configured based on the BOARD_DISPLAY_USE... + // preprocessor definitions + dispHandle = Display_open(Display_Type_ANY, NULL); + + // Initialize Two-Button Menu module + TBM_SET_TITLE(&spMenuMain, "Simple Peripheral"); + tbm_setItemStatus(&spMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL); + + tbm_initTwoBtnMenu(dispHandle, &spMenuMain, 5, SimplePeripheral_menuSwitchCb); + Display_printf(dispHandle, SP_ROW_SEPARATOR_1, 0, "===================="); + +#ifdef PTM_MODE + // Intercept NPI RX events. + NPITask_registerIncomingRXEventAppCB(simple_peripheral_handleNPIRxInterceptEvent, INTERCEPT); + + // Register for Command Status information + HCI_TL_Init(NULL, (HCI_TL_CommandStatusCB_t) simple_peripheral_sendToNPI, NULL, selfEntity); + + // Register for Events + HCI_TL_getCmdResponderID(ICall_getLocalMsgEntityId(ICALL_SERVICE_CLASS_BLE_MSG, selfEntity)); + + // Inform Stack to Initialize PTM + HCI_EXT_EnablePTMCmd(); +#endif // PTM_MODE +} + +/********************************************************************* + * PUBLIC FUNCTIONS + */ + +/********************************************************************* + * @fn simple_peripheral_spin + * + * @brief Spin forever + * + * @param none + */ +static void simple_peripheral_spin(void) +{ + volatile uint8_t x = 0; + + while(1) + { + x++; + } +} + +#ifdef PTM_MODE +/********************************************************************* +* @fn simple_peripheral_handleNPIRxInterceptEvent +* +* @brief Intercept an NPI RX serial message and queue for this application. +* +* @param pMsg - a NPIMSG_msg_t containing the intercepted message. +* +* @return none. +*/ +void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg) +{ + // Send Command via HCI TL + HCI_TL_SendToStack(((NPIMSG_msg_t *)pMsg)->pBuf); + + // The data is stored as a message, free this first. + ICall_freeMsg(((NPIMSG_msg_t *)pMsg)->pBuf); + + // Free container. + ICall_free(pMsg); +} + +/********************************************************************* +* @fn simple_peripheral_sendToNPI +* +* @brief Create an NPI packet and send to NPI to transmit. +* +* @param buf - pointer HCI event or data. +* +* @param len - length of buf in bytes. +* +* @return none +*/ +static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len) +{ + npiPkt_t *pNpiPkt = (npiPkt_t *)ICall_allocMsg(sizeof(npiPkt_t) + len); + + if (pNpiPkt) + { + pNpiPkt->hdr.event = buf[0]; //Has the event status code in first byte of payload + pNpiPkt->hdr.status = 0xFF; + pNpiPkt->pktLen = len; + pNpiPkt->pData = (uint8 *)(pNpiPkt + 1); + + memcpy(pNpiPkt->pData, buf, len); + + // Send to NPI + // Note: there is no need to free this packet. NPI will do that itself. + NPITask_sendToHost((uint8_t *)pNpiPkt); + } +} +#endif // PTM_MODE + diff --git a/examples/apps/cli/bleAppTask.h b/examples/apps/cli/bleAppTask.h new file mode 100644 index 0000000..592db0b --- /dev/null +++ b/examples/apps/cli/bleAppTask.h @@ -0,0 +1,5 @@ +void bleAppTask_init(); +static void BleMain(void *); +static void bleStack_init(); +#define BLEAPP_TASK_STACK_SIZE (2048) +#define BLEAPP_TASK_PRIORITY 4 diff --git a/examples/apps/cli/bleStackApp.h b/examples/apps/cli/bleStackApp.h new file mode 100644 index 0000000..e14c78a --- /dev/null +++ b/examples/apps/cli/bleStackApp.h @@ -0,0 +1,103 @@ + +/****************************************************************************** + + @file simple_peripheral.h + + @brief This file contains the Simple Peripheral sample application + definitions and prototypes. + + Group: WCS, BTS + Target Device: cc13xx_cc26xx + + ****************************************************************************** + + Copyright (c) 2013-2023, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + + + *****************************************************************************/ + +#ifndef SIMPLEPERIPHERAL_H +#define SIMPLEPERIPHERAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ +#include + +/********************************************************************* +* EXTERNAL VARIABLES +*/ + +/********************************************************************* + * CONSTANTS + */ + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * FUNCTIONS + */ + +/* + * Task creation function for the Simple Peripheral. + */ +extern void SimplePeripheral_createTask(void); + +/* + * Functions for menu action + */ +/* Actions for Menu: Choose connection to work with */ +bool SimplePeripheral_doSelectConn(uint8 index); + +/* Action for Menu: AutoConnect */ +bool SimplePeripheral_doAutoConnect(uint8_t index); + +/* Actions for Menu: Set PHY - Select */ +bool SimplePeripheral_doSetConnPhy(uint8 index); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEPERIPHERAL_H */ + diff --git a/examples/apps/cli/bleStackMenu.c b/examples/apps/cli/bleStackMenu.c new file mode 100644 index 0000000..30a4005 --- /dev/null +++ b/examples/apps/cli/bleStackMenu.c @@ -0,0 +1,61 @@ +#include +#include + +#include +#include "bleStack_menu.h" +#include "bleStackApp.h" +#include "ti_ble_config.h" + +/* Main Menu Object */ +tbmMenuObj_t spMenuMain; +tbmMenuObj_t spMenuAutoConnect; +tbmMenuObj_t spMenuSelectConn; +tbmMenuObj_t spMenuPerConn; +tbmMenuObj_t spMenuConnPhy; + +/* + * Menu Lists Initializations + */ + +void bleStack_buildMenu(void) +{ +// Menu: Main +// upper: none + MENU_OBJ(spMenuMain, NULL, 2, NULL) + MENU_ITEM_SUBMENU(spMenuMain,0,&spMenuSelectConn) + MENU_ITEM_SUBMENU(spMenuMain,1,&spMenuAutoConnect) + MENU_OBJ_END + +// Menu: SelectDev +// upper: Main +// NOTE: The number of items in this menu object shall be +// equal to or greater than MAX_NUM_BLE_CONNS + MENU_OBJ(spMenuSelectConn, "Work with", MAX_NUM_BLE_CONNS, &spMenuMain) + MENU_ITEM_MULTIPLE_ACTIONS(spMenuSelectConn, MAX_NUM_BLE_CONNS, NULL, SimplePeripheral_doSelectConn) + MENU_OBJ_END + +// Menu: AutoConnect +// upper: Main + MENU_OBJ(spMenuAutoConnect, "Set AutoConnect", 3, &spMenuMain) + MENU_ITEM_ACTION(spMenuAutoConnect,0,"Disable", SimplePeripheral_doAutoConnect) + MENU_ITEM_ACTION(spMenuAutoConnect,1,"Group A", SimplePeripheral_doAutoConnect) + MENU_ITEM_ACTION(spMenuAutoConnect,2,"Group B", SimplePeripheral_doAutoConnect) + MENU_OBJ_END + +// Menu: PerConnection +// upper: SelectDevice + MENU_OBJ(spMenuPerConn, NULL, 1, &spMenuSelectConn) + MENU_ITEM_SUBMENU(spMenuPerConn,0,&spMenuConnPhy) + MENU_OBJ_END + +// Menu: ConnPhy +// upper: Select Device + MENU_OBJ(spMenuConnPhy, "Set Conn PHY Preference", 6, &spMenuPerConn) + MENU_ITEM_ACTION(spMenuConnPhy,0,"1 Mbps", SimplePeripheral_doSetConnPhy) + MENU_ITEM_ACTION(spMenuConnPhy,1,"2 Mbps", SimplePeripheral_doSetConnPhy) + MENU_ITEM_ACTION(spMenuConnPhy,2,"1 & 2 Mbps", SimplePeripheral_doSetConnPhy) + MENU_ITEM_ACTION(spMenuConnPhy,3,"Coded", SimplePeripheral_doSetConnPhy) + MENU_ITEM_ACTION(spMenuConnPhy,4,"1 & 2 Mbps, & Coded", SimplePeripheral_doSetConnPhy) + MENU_ITEM_ACTION(spMenuConnPhy,5,"Auto PHY change", SimplePeripheral_doSetConnPhy) + MENU_OBJ_END +} diff --git a/examples/apps/cli/bleStack_menu.h b/examples/apps/cli/bleStack_menu.h new file mode 100644 index 0000000..51a2b4f --- /dev/null +++ b/examples/apps/cli/bleStack_menu.h @@ -0,0 +1,91 @@ +/****************************************************************************** + + @file simple_peripheral_menu.h + + @brief This file contains menu objects for simple_peripheral. + + Group: WCS BTS + Target Device: cc13xx_cc26xx + + ****************************************************************************** + + Copyright (c) 2016-2023, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + + + *****************************************************************************/ + +#ifndef SIMPLE_PERIPHERAL_MENU_H +#define SIMPLE_PERIPHERAL_MENU_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Menu item indices. +#define SP_ITEM_NONE TBM_ITEM_NONE +#define SP_ITEM_ALL TBM_ITEM_ALL + +// Note: The defines should be updated accordingly if there is any change +// in the order of the items of the menu objects the items belong to. +#define SP_ITEM_SELECT_CONN TBM_ITEM(0) // "Work with" +#define SP_ITEM_AUTOCONNECT TBM_ITEM(1) // "Auto Connect" + +/* + * Menus Declarations + */ + +/* Main Menu Object */ +extern tbmMenuObj_t spMenuMain; + +/* Items of (Main) */ +/* Action items are defined in simple_peripheral_menu.c */ + +/* + * Menus Declarations + */ + +/* Main Menu Object */ +extern tbmMenuObj_t spMenuMain; +extern tbmMenuObj_t spMenuAutoConnect; +extern tbmMenuObj_t spMenuSelectConn; +extern tbmMenuObj_t spMenuPerConn; +extern tbmMenuObj_t spMenuConnPhy; + +void bleStack_buildMenu(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLE_PERIPHERAL_MENU_H */ \ No newline at end of file diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 74c2bc7..0d686ae 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -43,10 +43,13 @@ #include #include -#include +//#include +#include "bleAppTask.h" + #ifndef USE_DEFAULT_USER_CFG #include "ble_user_config.h" + // BLE user defined configuration icall_userCfg_t user0Cfg = BLE_USER_CFG; #endif // USE_DEFAULT_USER_CFG @@ -58,6 +61,10 @@ extern int app_main(int argc, char *argv[]); StackType_t appStack[APP_STACK_SIZE]; StaticTask_t appTaskBuffer; +#define BLEAPP_TASK_STACK_SIZE (2048) +static TaskHandle_t BLEAPPTaskHandle; +#define BLEAPP_TASK_PRIORITY 4 + void vApplicationStackOverflowHook(void) { while (1) @@ -88,11 +95,10 @@ int main(void) SHA2_init(); - // initialize the ICall module - ICall_init(); + bleAppTask_init(); + - // Start tasks of external images - Priority 5 - ICall_createRemoteTasks(); + if (NULL == xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, appStack, &appTaskBuffer)) From 880aa1f0b545c1483f656740e1957c2f21ebe3d1 Mon Sep 17 00:00:00 2001 From: "Zhang, Wei" Date: Tue, 12 Dec 2023 13:55:42 -0600 Subject: [PATCH 06/19] ble sp test --- examples/apps/cli/bleAppTask.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index 87a0345..05d0f4b 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -31,7 +31,8 @@ #include #include -#if (!(defined __TI_COMPILER_VERSION__) && !(defined __GNUC__)) +/*#if (!(defined __TI_COMPILER_VERSION__) && !(defined __GNUC__))*/ +#if ((!(defined FREERTOS) && !(defined __TI_COMPILER_VERSION__)) && !(defined __GNUC__)) #include #endif From ad3a301c030abd142ae115de2301317203ab0115 Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Wed, 13 Dec 2023 08:26:37 -0600 Subject: [PATCH 07/19] added the advertising sets --- src/openthread.syscfg | 50 +++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/openthread.syscfg b/src/openthread.syscfg index 24c9757..12e9e1e 100755 --- a/src/openthread.syscfg +++ b/src/openthread.syscfg @@ -2,7 +2,7 @@ * These arguments were used when this file was generated. They will be automatically applied on subsequent loads * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. * @cliArgs --board "/ti/boards/LP_EM_CC1354P10_1" --product "simplelink_cc13xx_cc26xx_sdk@7.10.00.98" - * @versions {"tool":"1.15.0+2826"} + * @versions {"tool":"1.16.2+3028"} */ /** @@ -50,16 +50,34 @@ const Watchdog1 = Watchdog.addInstance(); /** * Write custom configuration values to the imported modules. */ -ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param1"; -ble.connUpdateParamsPeripheral.$name = "ti_ble5stack_general_ble_conn_update_params0"; -ble.advSet1.$name = "ti_ble5stack_broadcaster_advertisement_set0"; -ble.advSet1.advParam1.$name = "ti_ble5stack_broadcaster_advertisement_params0"; -ble.advSet1.advData1.$name = "ti_ble5stack_broadcaster_advertisement_data0"; -ble.advSet1.scanRes1.$name = "ti_ble5stack_broadcaster_advertisement_data1"; -ble.advSet2.$name = "ti_ble5stack_broadcaster_advertisement_set1"; -ble.advSet2.advParam2.$name = "ti_ble5stack_broadcaster_advertisement_params1"; -ble.advSet2.advData2.$name = "ti_ble5stack_broadcaster_advertisement_data2"; -ble.advSet2.scanRes2.$name = "ti_ble5stack_broadcaster_advertisement_data3"; +ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param1"; +ble.connUpdateParamsPeripheral.$name = "ti_ble5stack_general_ble_conn_update_params0"; +ble.advSet1.$name = "ti_ble5stack_broadcaster_advertisement_set0"; +ble.advSet1.advParam1.$name = "ti_ble5stack_broadcaster_advertisement_params0"; +ble.advSet1.advData1.$name = "ti_ble5stack_broadcaster_advertisement_data0"; +ble.advSet1.advData1.GAP_ADTYPE_LOCAL_NAME_SHORT = true; +ble.advSet1.advData1.shortenedLocalName = "SP"; +ble.advSet1.advData1.GAP_ADTYPE_FLAGS = true; +ble.advSet1.advData1.advertisingFlags = ["GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED"]; +ble.advSet1.advData1.GAP_ADTYPE_16BIT_MORE = true; +ble.advSet1.advData1.numOfUUIDs16More = 1; +ble.advSet1.advData1.UUID016More = 0xFFF0; +ble.advSet1.scanRes1.$name = "ti_ble5stack_broadcaster_advertisement_data1"; +ble.advSet1.scanRes1.GAP_ADTYPE_LOCAL_NAME_COMPLETE = true; +ble.advSet1.scanRes1.GAP_ADTYPE_POWER_LEVEL = true; +ble.advSet1.scanRes1.GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE = true; +ble.advSet1.scanRes1.maxConnInterval = 130; +ble.advSet2.$name = "ti_ble5stack_broadcaster_advertisement_set1"; +ble.advSet2.advParam2.$name = "ti_ble5stack_broadcaster_advertisement_params1"; +ble.advSet2.advData2.$name = "ti_ble5stack_broadcaster_advertisement_data2"; +ble.advSet2.advData2.GAP_ADTYPE_LOCAL_NAME_SHORT = true; +ble.advSet2.advData2.shortenedLocalName = "SP"; +ble.advSet2.advData2.GAP_ADTYPE_FLAGS = true; +ble.advSet2.advData2.advertisingFlags = ["GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED"]; +ble.advSet2.advData2.GAP_ADTYPE_16BIT_MORE = true; +ble.advSet2.advData2.numOfUUIDs16More = 1; +ble.advSet2.advData2.UUID016More = 0xFFF0; +ble.advSet2.scanRes2.$name = "ti_ble5stack_broadcaster_advertisement_data3"; CCFG.xoscCapArray = true; CCFG.xoscCapArrayDelta = 0xD5; @@ -147,11 +165,11 @@ Watchdog1.watchdog.$assign = "WDT0"; */ GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; -GPIO3.gpioPin.$suggestSolution = "ball.16"; -GPIO4.gpioPin.$suggestSolution = "ball.15"; -RF.rfAntennaPin0.$suggestSolution = "ball.10"; -RF.rfAntennaPin1.$suggestSolution = "ball.12"; -RF.rfAntennaPin2.$suggestSolution = "ball.11"; +GPIO3.gpioPin.$suggestSolution = "DIO_7"; +GPIO4.gpioPin.$suggestSolution = "DIO_6"; +RF.rfAntennaPin0.$suggestSolution = "DIO_34"; +RF.rfAntennaPin1.$suggestSolution = "DIO_3"; +RF.rfAntennaPin2.$suggestSolution = "DIO_35"; SPI1.spi.$suggestSolution = "SPI0"; SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; From e37199421a01be413537e49ea7c1947b8e78adaf Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Wed, 13 Dec 2023 08:57:41 -0600 Subject: [PATCH 08/19] adding in the display stuff --- examples/apps/cli/CMakeLists.txt | 5 +++++ examples/apps/cli/bleAppTask.c | 2 +- src/openthread.syscfg | 34 ++++++++++++++++++++------------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 77d16fd..5212e60 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -47,6 +47,8 @@ set(COMMON_INCLUDES ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/controller/cc26xx/inc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/dev_info ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/simple_profile + + ${TI_SIMPLELINK_SDK_DIR}/source/ti/display ) set(COMMON_SOURCES @@ -56,6 +58,9 @@ set(COMMON_SOURCES bleStackMenu.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/util.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/menu/two_btn_menu.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c ) if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index 05d0f4b..4e9908a 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -533,7 +533,7 @@ static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) } case HCI_BLE_HARDWARE_ERROR_EVENT_CODE: - AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); + //AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); break; // HCI Commands Events diff --git a/src/openthread.syscfg b/src/openthread.syscfg index 12e9e1e..04cc0f4 100755 --- a/src/openthread.syscfg +++ b/src/openthread.syscfg @@ -12,6 +12,8 @@ const ble = scripting.addModule("/ti/ble5stack/ble"); const CCFG = scripting.addModule("/ti/devices/CCFG"); const custom = scripting.addModule("/ti/devices/radioconfig/custom"); const rfdesign = scripting.addModule("/ti/devices/radioconfig/rfdesign"); +const Display = scripting.addModule("/ti/display/Display", {}, false); +const Display1 = Display.addInstance(); const dmm = scripting.addModule("/ti/dmm/dmm"); const AESCCM = scripting.addModule("/ti/drivers/AESCCM", {}, false); const AESCCM1 = AESCCM.addInstance(); @@ -98,6 +100,9 @@ custom.radioConfigieee154.codeExportConfig.cmdList_ieee_15_4 = ["cmdIeeeCsma","c rfdesign.rfDesign = "LP_EM_CC1354P10_1"; +Display1.$name = "CONFIG_Display_0"; +Display1.uart.$name = "CONFIG_UART2_1"; + dmm.stackRoles = ["blePeripheral","custom1"]; dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; dmm.policyArray[0].custom1.$name = "ti_dmm_policy_stack_dmm_stack_custom0"; @@ -163,16 +168,19 @@ Watchdog1.watchdog.$assign = "WDT0"; * version of the tool will not impact the pinmux you originally saw. These lines can be completely deleted in order to * re-solve from scratch. */ -GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; -GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; -GPIO3.gpioPin.$suggestSolution = "DIO_7"; -GPIO4.gpioPin.$suggestSolution = "DIO_6"; -RF.rfAntennaPin0.$suggestSolution = "DIO_34"; -RF.rfAntennaPin1.$suggestSolution = "DIO_3"; -RF.rfAntennaPin2.$suggestSolution = "DIO_35"; -SPI1.spi.$suggestSolution = "SPI0"; -SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; -SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; -UART21.uart.$suggestSolution = "UART0"; -UART21.uart.txPin.$suggestSolution = "boosterpack.4"; -UART21.uart.rxPin.$suggestSolution = "boosterpack.3"; +Display1.uart.uart.$suggestSolution = "UART0"; +Display1.uart.uart.txPin.$suggestSolution = "boosterpack.36"; +Display1.uart.uart.rxPin.$suggestSolution = "boosterpack.31"; +GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; +GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; +GPIO3.gpioPin.$suggestSolution = "DIO_7"; +GPIO4.gpioPin.$suggestSolution = "DIO_6"; +RF.rfAntennaPin0.$suggestSolution = "DIO_34"; +RF.rfAntennaPin1.$suggestSolution = "DIO_3"; +RF.rfAntennaPin2.$suggestSolution = "DIO_35"; +SPI1.spi.$suggestSolution = "SPI0"; +SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; +SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; +UART21.uart.$suggestSolution = "UART1"; +UART21.uart.txPin.$suggestSolution = "boosterpack.4"; +UART21.uart.rxPin.$suggestSolution = "boosterpack.3"; From 75eb3c5e6e344b3af0230a3e7a7405cd091411df Mon Sep 17 00:00:00 2001 From: "Zhang, Wei" Date: Wed, 13 Dec 2023 11:22:16 -0600 Subject: [PATCH 09/19] fix compilation error --- examples/apps/cli/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 5212e60..724a2f0 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -47,7 +47,6 @@ set(COMMON_INCLUDES ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/controller/cc26xx/inc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/dev_info ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/profiles/simple_profile - ${TI_SIMPLELINK_SDK_DIR}/source/ti/display ) @@ -61,6 +60,8 @@ set(COMMON_SOURCES ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/util.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/menu/two_btn_menu.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/board_key.c + ${TI_SIMPLELINK_SDK_DIR}/kernel/nortos/dpl/SystemP_nortos.c ) if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") From f1e5b648cde992a2cbcbd57cc3dc8a5eae35a0c6 Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Wed, 13 Dec 2023 13:56:26 -0600 Subject: [PATCH 10/19] USE_DMM defined --- examples/apps/cli/main.c | 28 +++++++++++++++++++++++++++- src/CMakeLists.txt | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/examples/apps/cli/main.c b/examples/apps/cli/main.c index e1fc63c..8b5d332 100644 --- a/examples/apps/cli/main.c +++ b/examples/apps/cli/main.c @@ -41,6 +41,8 @@ #include "lib/platform/reset_util.h" +otInstance *instance; + /** * This function initializes the CLI app. * @@ -96,7 +98,7 @@ static const otCliCommand kCommands[] = { int app_main(int argc, char *argv[]) { - otInstance *instance; + OT_SETUP_RESET_JUMP(argv); @@ -156,3 +158,27 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat va_end(ap); } #endif + +otInstance *OtInstance_get(void) +{ + otInstance *ret; + + if (NULL != instance) + { + ret = instance; + } + else + { + /* lock and unlock the API to make sure that the stack is initialized + * before the caller tries to use this pointer. + */ + // FIXME: Not sure about the locking here, as these symbols are + // not defined. + // + //OtRtosApi_lock(); + ret = instance; + //OtRtosApi_unlock(); + } + + return ret; +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 33724d4..cc18660 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -242,7 +242,7 @@ target_link_libraries(openthread-cc13xx_cc26xx # JJM - setting the user compile definitions here as there seems to be # an issue with the .opt files set(USR_COMPILE_DEFINITIONS - #"USE_DMM" + "USE_DMM" "SYSCFG" "CC13X4" "CC13XX" From d79c16f5629858ac8173c54362b654c0ce0d531a Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Wed, 13 Dec 2023 16:28:59 -0600 Subject: [PATCH 11/19] switching to POSIX --- examples/apps/cli/bleAppTask.c | 8 +++----- examples/apps/cli/freertos_main.c | 14 +++++++++++--- src/CMakeLists.txt | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index 4e9908a..7052f10 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -390,7 +390,7 @@ static TaskHandle_t BLEAPPTaskHandle = NULL; void bleAppTask_init() { - // initialize the ICall module + // initialize the ICall module ICall_init(); // Start tasks of external images - Priority 5 @@ -398,11 +398,9 @@ void bleAppTask_init() if (xTaskCreate(BleMain, "BleMain", BLEAPP_TASK_STACK_SIZE/sizeof(StackType_t), NULL, BLEAPP_TASK_PRIORITY, &BLEAPPTaskHandle)!=pdPASS) { - otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM,"BLEAPP Failed to created\n"); - while (1) - ; + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM,"BLEAPP Failed to created\n"); + while (1) ; } - } static void BleMain(void * pvParameter) diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 0d686ae..5a655b2 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -49,6 +49,7 @@ #ifndef USE_DEFAULT_USER_CFG #include "ble_user_config.h" +#include // BLE user defined configuration icall_userCfg_t user0Cfg = BLE_USER_CFG; @@ -95,10 +96,16 @@ int main(void) SHA2_init(); - bleAppTask_init(); - + user0Cfg.appServiceInfo->timerTickPeriod = ICall_getTickPeriod(); + user0Cfg.appServiceInfo->timerMaxMillisecond = ICall_getMaxMSecs(); + +#if 0 + /* Initialize ICall module */ + ICall_init(); - + /* Start tasks of external images */ + ICall_createRemoteTasks(); +#endif if (NULL == xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, appStack, &appTaskBuffer)) @@ -107,6 +114,7 @@ int main(void) ; } + bleAppTask_init(); vTaskStartScheduler(); // Should never get here. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc18660..3c85620 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,7 +122,7 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") # JJM - mirror simple peripheral iCall folder ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_cc2650.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_user_config.c - ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/icall_POSIX.c # JJM - mirror simple peripheral iCallBLE folder ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/stack/ble_user_config_stack.c From 71163032e4e586378c5e182e93e6bd7f98352944 Mon Sep 17 00:00:00 2001 From: "Zhang, Wei" Date: Wed, 13 Dec 2023 18:30:22 -0600 Subject: [PATCH 12/19] add simpeperipheral_assert AssertHandler back --- examples/apps/cli/bleAppTask.c | 62 ++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index 4e9908a..bfca959 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -11,6 +11,7 @@ #include #include #include "util.h" +#include "hal_assert.h" //Wei //#include @@ -313,6 +314,7 @@ static uint8 rpa[B_ADDR_LEN] = {0}; */ static void SimplePeripheral_init( void ); +static void simple_peripheral_spin( void ); //Wei //static void SimplePeripheral_taskFxn(UArg a0, UArg a1); @@ -533,7 +535,7 @@ static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) } case HCI_BLE_HARDWARE_ERROR_EVENT_CODE: - //AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); + AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); break; // HCI Commands Events @@ -812,19 +814,19 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) status = GapAdv_create(&SimplePeripheral_advCallback, &advParams1, &advHandleLegacy); //Wei - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Load advertising data for set #1 that is statically allocated by the app //Wei status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_ADV, sizeof(advData1), advData1); //Wei - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Load scan response data for set #1 that is statically allocated by the app status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_SCAN_RSP, sizeof(scanResData1), scanResData1); - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Set event mask for set #1 status = GapAdv_setEventMask(advHandleLegacy, @@ -835,20 +837,20 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) // Enable legacy advertising for set #1 status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); //Wei - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- call GapAdv_create set=%d,%d\n", 1, 0); // Create Advertisement set #2 and assign handle status = GapAdv_create(&SimplePeripheral_advCallback, &advParams2, &advHandleLongRange); //Wei - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Load advertising data for set #2 that is statically allocated by the app status = GapAdv_loadByHandle(advHandleLongRange, GAP_ADV_DATA_TYPE_ADV, sizeof(advData2), advData2); //Wei - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Set event mask for set #2 status = GapAdv_setEventMask(advHandleLongRange, @@ -860,7 +862,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) // Enable long range advertising for set #2 status = GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); //Wei - //SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); + SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Display device address Display_printf(dispHandle, SP_ROW_IDA, 0, "%s Addr: %s", @@ -2113,7 +2115,7 @@ static status_t SimplePeripheral_startAutoPhyChange(uint16_t connHandle) // Get connection index from handle uint8_t connIndex = SimplePeripheral_getConnIndex(connHandle); //Wei - //SIMPLEPERIPHERAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS); + SIMPLEPERIPHERAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS); // Start Connection Event notice for RSSI calculation status = Gap_RegisterConnEventCb(SimplePeripheral_connEvtCB, GAP_CB_REGISTER, GAP_CB_CONN_EVENT_ALL, connHandle); @@ -2142,7 +2144,7 @@ static status_t SimplePeripheral_stopAutoPhyChange(uint16_t connHandle) // Get connection index from handle uint8_t connIndex = SimplePeripheral_getConnIndex(connHandle); //Wei - //SIMPLEPERIPHERAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS); + SIMPLEPERIPHERAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS); // Stop connection event notice Gap_RegisterConnEventCb(NULL, GAP_CB_UNREGISTER, GAP_CB_CONN_EVENT_ALL, connHandle); @@ -2557,3 +2559,43 @@ static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len) } #endif // PTM_MODE +//self define AssertHandler +void AssertHandler(uint8 assertCause, uint8 assertSubcause) +{ + //do nothing for now, need to define at application layer + switch (assertCause) + { + case HAL_ASSERT_CAUSE_OUT_OF_MEMORY: + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM, "OUT_OF_MEMORY\n"); + break; + + case HAL_ASSERT_CAUSE_INTERNAL_ERROR: + // check the subcause + if (assertSubcause == HAL_ASSERT_SUBCAUSE_FW_INERNAL_ERROR) + { + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM, "FW INTERNAL ERROR\n"); + } + else + { + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM, "INTERNAL ERROR\n"); + } + break; + + case HAL_ASSERT_CAUSE_ICALL_ABORT: + HAL_ASSERT_SPINLOCK; + break; + + case HAL_ASSERT_CAUSE_ICALL_TIMEOUT: + HAL_ASSERT_SPINLOCK; + break; + + case HAL_ASSERT_CAUSE_WRONG_API_CALL: + HAL_ASSERT_SPINLOCK; + break; + + default: + HAL_ASSERT_SPINLOCK; + } + +} + From f1d39bf6cb77ca488007637b5c2d35fb53cc3d71 Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Thu, 14 Dec 2023 07:57:20 -0600 Subject: [PATCH 13/19] corrected the Display driver --- examples/apps/cli/bleAppTask.c | 1 + src/openthread.syscfg | 16 +++++----------- src/uart.c | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index 8b59abb..fa556eb 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -392,6 +392,7 @@ static TaskHandle_t BLEAPPTaskHandle = NULL; void bleAppTask_init() { + RegisterAssertCback(AssertHandler); // initialize the ICall module ICall_init(); diff --git a/src/openthread.syscfg b/src/openthread.syscfg index 04cc0f4..b03913d 100755 --- a/src/openthread.syscfg +++ b/src/openthread.syscfg @@ -45,7 +45,6 @@ const SPI1 = SPI.addInstance(); const TRNG = scripting.addModule("/ti/drivers/TRNG"); const TRNG1 = TRNG.addInstance(); const UART2 = scripting.addModule("/ti/drivers/UART2"); -const UART21 = UART2.addInstance(); const Watchdog = scripting.addModule("/ti/drivers/Watchdog"); const Watchdog1 = Watchdog.addInstance(); @@ -100,8 +99,9 @@ custom.radioConfigieee154.codeExportConfig.cmdList_ieee_15_4 = ["cmdIeeeCsma","c rfdesign.rfDesign = "LP_EM_CC1354P10_1"; -Display1.$name = "CONFIG_Display_0"; -Display1.uart.$name = "CONFIG_UART2_1"; +Display1.$name = "CONFIG_Display_0"; +Display1.uart.$name = "CONFIG_DISPLAY_UART"; +Display1.uart.$hardware = system.deviceData.board.components.XDS110UART; dmm.stackRoles = ["blePeripheral","custom1"]; dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; @@ -157,9 +157,6 @@ SPI1.spi.csnPin.$assign = "boosterpack.25"; TRNG1.$name = "CONFIG_TRNG_THREAD"; -UART21.$name = "CONFIG_UART2_0"; -UART21.$hardware = system.deviceData.board.components.XDS110UART; - Watchdog1.$name = "CONFIG_WATCHDOG0"; Watchdog1.watchdog.$assign = "WDT0"; @@ -169,8 +166,8 @@ Watchdog1.watchdog.$assign = "WDT0"; * re-solve from scratch. */ Display1.uart.uart.$suggestSolution = "UART0"; -Display1.uart.uart.txPin.$suggestSolution = "boosterpack.36"; -Display1.uart.uart.rxPin.$suggestSolution = "boosterpack.31"; +Display1.uart.uart.txPin.$suggestSolution = "boosterpack.4"; +Display1.uart.uart.rxPin.$suggestSolution = "boosterpack.3"; GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; GPIO3.gpioPin.$suggestSolution = "DIO_7"; @@ -181,6 +178,3 @@ RF.rfAntennaPin2.$suggestSolution = "DIO_35"; SPI1.spi.$suggestSolution = "SPI0"; SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; -UART21.uart.$suggestSolution = "UART1"; -UART21.uart.txPin.$suggestSolution = "boosterpack.4"; -UART21.uart.rxPin.$suggestSolution = "boosterpack.3"; diff --git a/src/uart.c b/src/uart.c index 30faf1c..ccbcdb4 100644 --- a/src/uart.c +++ b/src/uart.c @@ -112,7 +112,7 @@ otError otPlatUartEnable(void) params.writeCallback = uartWriteCallback; #endif - PlatformUart_uartHandle = UART2_open(CONFIG_UART2_0, ¶ms); + PlatformUart_uartHandle = UART2_open(CONFIG_DISPLAY_UART, ¶ms); UART2_read(PlatformUart_uartHandle, PlatformUart_receiveBuffer, sizeof(PlatformUart_receiveBuffer), NULL); From e36fe29034b7619d540d1c509e2ec101f4c2dbb3 Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Thu, 14 Dec 2023 08:06:39 -0600 Subject: [PATCH 14/19] toying with the printfs --- examples/apps/cli/bleAppTask.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index fa556eb..5d13697 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -810,9 +810,13 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- call GapAdv_create set=%d,%d\n", 0, 0); // Create Advertisement set #1 and assign handle - status = GapAdv_create(&SimplePeripheral_advCallback, &advParams1, - &advHandleLegacy); - //Wei + status = GapAdv_create(&SimplePeripheral_advCallback, &advParams1, &advHandleLegacy); + //Wei + if ( status != SUCCESS ) + { + Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Failed to create the GAP Adv (%d:0x%02x)", status, status); + vTaskDelay(pdMS_TO_TICKS(500)); + } SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); // Load advertising data for set #1 that is statically allocated by the app From d531129efcda2c0e43291c1a2cc5c58a37b32244 Mon Sep 17 00:00:00 2001 From: "Markel, Joe" Date: Tue, 16 Jan 2024 11:26:46 -0600 Subject: [PATCH 15/19] heap added --- examples/apps/cli/CMakeLists.txt | 3 +++ examples/apps/cli/freertos_main.c | 12 ++++++++++-- src/FreeRTOSConfig.h | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 724a2f0..c564cce 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -29,6 +29,7 @@ set(COMMON_INCLUDES ${OT_PUBLIC_INCLUDES} ${TI_PUBLIC_INCLUDES} + ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/openthread/examples/platforms ${PROJECT_SOURCE_DIR}/openthread/src/core @@ -39,6 +40,7 @@ set(COMMON_INCLUDES ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/inc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/target/_common ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom @@ -62,6 +64,7 @@ set(COMMON_SOURCES ${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/board_key.c ${TI_SIMPLELINK_SDK_DIR}/kernel/nortos/dpl/SystemP_nortos.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos/bget.c ) if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 5a655b2..771af90 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -45,7 +45,7 @@ //#include #include "bleAppTask.h" - +#include #ifndef USE_DEFAULT_USER_CFG #include "ble_user_config.h" @@ -66,6 +66,13 @@ StaticTask_t appTaskBuffer; static TaskHandle_t BLEAPPTaskHandle; #define BLEAPP_TASK_PRIORITY 4 +#include +#define TOTAL_ICALL_HEAP_SIZE (0xf700) + + +__attribute__((section(".heap"))) uint8_t GlobalHeapZoneBuffer[TOTAL_ICALL_HEAP_SIZE]; +uint32_t heapSize = TOTAL_ICALL_HEAP_SIZE; + void vApplicationStackOverflowHook(void) { while (1) @@ -83,6 +90,7 @@ void vTaskCode(void *pvParameters) int main(void) { Board_init(); + bpool((void *) GlobalHeapZoneBuffer, TOTAL_ICALL_HEAP_SIZE); GPIO_init(); @@ -99,7 +107,7 @@ int main(void) user0Cfg.appServiceInfo->timerTickPeriod = ICall_getTickPeriod(); user0Cfg.appServiceInfo->timerMaxMillisecond = ICall_getMaxMSecs(); -#if 0 +#if 1 /* Initialize ICall module */ ICall_init(); diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 59cf79d..f08706d 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -69,7 +69,8 @@ #elif defined(DeviceFamily_CC13X4_CC26X4) \ || defined(DeviceFamily_CC13X4) \ || defined(DeviceFamily_CC26X4) -#define configTOTAL_HEAP_SIZE ((size_t)(0x14000)) +//#define configTOTAL_HEAP_SIZE ((size_t)(0x14000)) +#define configTOTAL_HEAP_SIZE ((size_t) (0)) #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 /* TrustZone/PSA settings */ /* We do not set ENABLE_TRUSTZONE, as this is only for Secure Side function call support */ From 9bf0bca535aa5194cf095a4a7ae266b1020231e7 Mon Sep 17 00:00:00 2001 From: Stuart Baker Date: Thu, 25 Jan 2024 14:26:40 -0600 Subject: [PATCH 16/19] Apply R&D updates. BLE advertising working. BLE connections still fail. --- examples/apps/cli/CMakeLists.txt | 16 +- examples/apps/cli/TI_heap_wrapper.c | 63 + examples/apps/cli/TI_heap_wrapper.h | 9 + examples/apps/cli/bget.c | 1629 +++++++++++ examples/apps/cli/bget.h | 49 + examples/apps/cli/bleAppTask.c | 35 +- examples/apps/cli/ble_user_config.c | 560 ++++ examples/apps/cli/freertos_main.c | 40 +- examples/apps/cli/icall_FreeRTOS.c | 4119 +++++++++++++++++++++++++++ src/CMakeLists.txt | 26 + src/FreeRTOSConfig.h | 1 + src/openthread.syscfg | 6 +- third_party/freertos/CMakeLists.txt | 4 +- 13 files changed, 6536 insertions(+), 21 deletions(-) create mode 100755 examples/apps/cli/TI_heap_wrapper.c create mode 100755 examples/apps/cli/TI_heap_wrapper.h create mode 100755 examples/apps/cli/bget.c create mode 100755 examples/apps/cli/bget.h create mode 100755 examples/apps/cli/ble_user_config.c create mode 100755 examples/apps/cli/icall_FreeRTOS.c diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index c564cce..3fa6f75 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -32,16 +32,20 @@ set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/openthread/examples/platforms ${PROJECT_SOURCE_DIR}/openthread/src/core + ${PROJECT_SOURCE_DIR}/examples/apps/cli # JJM include paths for ICall module + ${TI_SIMPLELINK_SDK_DIR}/source/ti ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/inc/ ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/inc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src/inc + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/icall/src ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/inc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/hal/src/target/_common ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/ ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/nv + ${TI_SIMPLELINK_SDK_DIR}/source/ti/common/cc26xx ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom @@ -57,14 +61,22 @@ set(COMMON_SOURCES main.c bleAppTask.c bleStackMenu.c + bget.c + TI_heap_wrapper.c + ble_user_config.c + icall_FreeRTOS.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c - ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/dmm_priority_ble_thread.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/util.c + #${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/util.c +# ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/menu/two_btn_menu.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/board_key.c ${TI_SIMPLELINK_SDK_DIR}/kernel/nortos/dpl/SystemP_nortos.c - ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos/bget.c + #${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos/bget.c ) if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") diff --git a/examples/apps/cli/TI_heap_wrapper.c b/examples/apps/cli/TI_heap_wrapper.c new file mode 100755 index 0000000..df4a46b --- /dev/null +++ b/examples/apps/cli/TI_heap_wrapper.c @@ -0,0 +1,63 @@ +#include "bget.h" +#include +#include + +typedef unsigned int dpl_CSState; + +typedef union _dpl_cs_state_union_t +{ + /** critical section variable as declared in the interface */ + dpl_CSState state; + /** @internal field used to access internal data */ + struct _dpl_cs_state_aggr_t + { + /** field to store Swi_disable() return value */ + uint_least16_t swikey; + /** field to store Hwi_disable() return value */ + uint_least16_t hwikey; + } each; +} dpl_CSStateUnion; + +/* This is enter critical section for DPL supported devices */ +dpl_CSState dpl_enterCSImpl(void) +{ + + dpl_CSStateUnion cu; + cu.each.swikey = (uint_least16_t) SwiP_disable(); + cu.each.hwikey = (uint_least16_t) HwiP_disable(); + return cu.state; +} + +/* This is exit critical section for DPL supported devices */ +void dpl_leaveCSImpl(dpl_CSState key) +{ + dpl_CSStateUnion *cu = (dpl_CSStateUnion *) &key; + HwiP_restore((uint32_t) cu->each.hwikey); + SwiP_restore((uint32_t) cu->each.swikey); +} + +/* Protected allocation */ +void *pvPortMalloc( size_t xWantedSize ) +{ + void* retVal = NULL; + + dpl_CSState state; + state = dpl_enterCSImpl(); + + retVal = bget(xWantedSize); + + dpl_leaveCSImpl(state); + return retVal; + +} + +/* Protected Deallocation */ +void vPortFree( void *pv ) +{ + dpl_CSState state; + state = dpl_enterCSImpl(); + + brel(pv); + + dpl_leaveCSImpl(state); +} diff --git a/examples/apps/cli/TI_heap_wrapper.h b/examples/apps/cli/TI_heap_wrapper.h new file mode 100755 index 0000000..4aa1f4a --- /dev/null +++ b/examples/apps/cli/TI_heap_wrapper.h @@ -0,0 +1,9 @@ +/* Protected allocation + malloc/ICall_heapMalloc --> ti_heap_wrapper --> bget protected by critical section +*/ +void *pvPortMalloc( size_t xWantedSize ); + +/* Protected Deallocation + Free/ICall_heapFree --> ti_heap_wrapper --> brel protected by critical section + */ +void vPortFree( void *pv ); diff --git a/examples/apps/cli/bget.c b/examples/apps/cli/bget.c new file mode 100755 index 0000000..e0be4bc --- /dev/null +++ b/examples/apps/cli/bget.c @@ -0,0 +1,1629 @@ +/* + + B G E T + + Buffer allocator + + Designed and implemented in April of 1972 by John Walker, based on the + Case Algol OPRO$ algorithm implemented in 1966. + + Reimplemented in 1975 by John Walker for the Interdata 70. + Reimplemented in 1977 by John Walker for the Marinchip 9900. + Reimplemented in 1982 by Duff Kurland for the Intel 8080. + + Portable C version implemented in September of 1990 by an older, wiser + instance of the original implementor. + + Souped up and/or weighed down slightly shortly thereafter by Greg + Lutz. + + AMIX edition, including the new compaction call-back option, prepared + by John Walker in July of 1992. + + Bug in built-in test program fixed, ANSI compiler warnings eradicated, + buffer pool validator implemented, and guaranteed repeatable test + added by John Walker in October of 1995. + + This program is in the public domain. + + 1. This is the book of the generations of Adam. In the day that God + created man, in the likeness of God made he him; + 2. Male and female created he them; and blessed them, and called + their name Adam, in the day when they were created. + 3. And Adam lived an hundred and thirty years, and begat a son in + his own likeness, and after his image; and called his name Seth: + 4. And the days of Adam after he had begotten Seth were eight + hundred years: and he begat sons and daughters: + 5. And all the days that Adam lived were nine hundred and thirty + years: and he died. + 6. And Seth lived an hundred and five years, and begat Enos: + 7. And Seth lived after he begat Enos eight hundred and seven years, + and begat sons and daughters: + 8. And all the days of Seth were nine hundred and twelve years: and + he died. + 9. And Enos lived ninety years, and begat Cainan: + 10. And Enos lived after he begat Cainan eight hundred and fifteen + years, and begat sons and daughters: + 11. And all the days of Enos were nine hundred and five years: and + he died. + 12. And Cainan lived seventy years and begat Mahalaleel: + 13. And Cainan lived after he begat Mahalaleel eight hundred and + forty years, and begat sons and daughters: + 14. And all the days of Cainan were nine hundred and ten years: and + he died. + 15. And Mahalaleel lived sixty and five years, and begat Jared: + 16. And Mahalaleel lived after he begat Jared eight hundred and + thirty years, and begat sons and daughters: + 17. And all the days of Mahalaleel were eight hundred ninety and + five years: and he died. + 18. And Jared lived an hundred sixty and two years, and he begat + Enoch: + 19. And Jared lived after he begat Enoch eight hundred years, and + begat sons and daughters: + 20. And all the days of Jared were nine hundred sixty and two years: + and he died. + 21. And Enoch lived sixty and five years, and begat Methuselah: + 22. And Enoch walked with God after he begat Methuselah three + hundred years, and begat sons and daughters: + 23. And all the days of Enoch were three hundred sixty and five + years: + 24. And Enoch walked with God: and he was not; for God took him. + 25. And Methuselah lived an hundred eighty and seven years, and + begat Lamech. + 26. And Methuselah lived after he begat Lamech seven hundred eighty + and two years, and begat sons and daughters: + 27. And all the days of Methuselah were nine hundred sixty and nine + years: and he died. + 28. And Lamech lived an hundred eighty and two years, and begat a + son: + 29. And he called his name Noah, saying, This same shall comfort us + concerning our work and toil of our hands, because of the ground + which the LORD hath cursed. + 30. And Lamech lived after he begat Noah five hundred ninety and + five years, and begat sons and daughters: + 31. And all the days of Lamech were seven hundred seventy and seven + years: and he died. + 32. And Noah was five hundred years old: and Noah begat Shem, Ham, + and Japheth. + + And buffers begat buffers, and links begat links, and buffer pools + begat links to chains of buffer pools containing buffers, and lo the + buffers and links and pools of buffers and pools of links to chains of + pools of buffers were fruitful and they multiplied and the Operating + System looked down upon them and said that it was Good. + + + INTRODUCTION + ============ + + BGET is a comprehensive memory allocation package which is easily + configured to the needs of an application. BGET is efficient in + both the time needed to allocate and release buffers and in the + memory overhead required for buffer pool management. It + automatically consolidates contiguous space to minimise + fragmentation. BGET is configured by compile-time definitions, + Major options include: + + * A built-in test program to exercise BGET and + demonstrate how the various functions are used. + + * Allocation by either the "first fit" or "best fit" + method. + + * Wiping buffers at release time to catch code which + references previously released storage. + + * Built-in routines to dump individual buffers or the + entire buffer pool. + + * Retrieval of allocation and pool size statistics. + + * Quantisation of buffer sizes to a power of two to + satisfy hardware alignment constraints. + + * Automatic pool compaction, growth, and shrinkage by + means of call-backs to user defined functions. + + Applications of BGET can range from storage management in + ROM-based embedded programs to providing the framework upon which + a multitasking system incorporating garbage collection is + constructed. BGET incorporates extensive internal consistency + checking using the an ASSERT mechanism; all these checks can be + turned off by compiling with NDEBUG defined, yielding a version of + BGET with minimal size and maximum speed. + + The basic algorithm underlying BGET has withstood the test of + time; more than 25 years have passed since the first + implementation of this code. And yet, it is substantially more + efficient than the native allocation schemes of many operating + systems: the Macintosh and Microsoft Windows to name two, on which + programs have obtained substantial speed-ups by layering BGET as + an application level memory manager atop the underlying system's. + + BGET has been implemented on the largest mainframes and the lowest + of microprocessors. It has served as the core for multitasking + operating systems, multi-thread applications, embedded software in + data network switching processors, and a host of C programs. And + while it has accreted flexibility and additional options over the + years, it remains fast, memory efficient, portable, and easy to + integrate into your program. + + + BGET IMPLEMENTATION ASSUMPTIONS + =============================== + + BGET is written in as portable a dialect of C as possible. The + only fundamental assumption about the underlying hardware + architecture is that memory is allocated is a linear array which + can be addressed as a vector of C "char" objects. On segmented + address space architectures, this generally means that BGET should + be used to allocate storage within a single segment (although some + compilers simulate linear address spaces on segmented + architectures). On segmented architectures, then, BGET buffer + pools may not be larger than a segment, but since BGET allows any + number of separate buffer pools, there is no limit on the total + storage which can be managed, only on the largest individual + object which can be allocated. Machines with a linear address + architecture, such as the VAX, 680x0, Sparc, MIPS, or the Intel + 80386 and above in native mode, may use BGET without restriction. + + + GETTING STARTED WITH BGET + ========================= + + Although BGET can be configured in a multitude of fashions, there + are three basic ways of working with BGET. The functions + mentioned below are documented in the following section. Please + excuse the forward references which are made in the interest of + providing a roadmap to guide you to the BGET functions you're + likely to need. + + Embedded Applications + --------------------- + + Embedded applications typically have a fixed area of memory + dedicated to buffer allocation (often in a separate RAM address + space distinct from the ROM that contains the executable code). + To use BGET in such an environment, simply call bpool() with the + start address and length of the buffer pool area in RAM, then + allocate buffers with bget() and release them with brel(). + Embedded applications with very limited RAM but abundant CPU speed + may benefit by configuring BGET for BestFit allocation (which is + usually not worth it in other environments). + + Malloc() Emulation + ------------------ + + If the C library malloc() function is too slow, not present in + your development environment (for example, an a native Windows or + Macintosh program), or otherwise unsuitable, you can replace it + with BGET. Initially define a buffer pool of an appropriate size + with bpool()--usually obtained by making a call to the operating + system's low-level memory allocator. Then allocate buffers with + bget(), bgetz(), and bgetr() (the last two permit the allocation + of buffers initialised to zero and [inefficient] re-allocation of + existing buffers for compatibility with C library functions). + Release buffers by calling brel(). If a buffer allocation request + fails, obtain more storage from the underlying operating system, + add it to the buffer pool by another call to bpool(), and continue + execution. + + Automatic Storage Management + ---------------------------- + + You can use BGET as your application's native memory manager and + implement automatic storage pool expansion, contraction, and + optionally application-specific memory compaction by compiling + BGET with the BECtl variable defined, then calling bectl() and + supplying functions for storage compaction, acquisition, and + release, as well as a standard pool expansion increment. All of + these functions are optional (although it doesn't make much sense + to provide a release function without an acquisition function, + does it?). Once the call-back functions have been defined with + bectl(), you simply use bget() and brel() to allocate and release + storage as before. You can supply an initial buffer pool with + bpool() or rely on automatic allocation to acquire the entire + pool. When a call on bget() cannot be satisfied, BGET first + checks if a compaction function has been supplied. If so, it is + called (with the space required to satisfy the allocation request + and a sequence number to allow the compaction routine to be called + successively without looping). If the compaction function is able + to free any storage (it needn't know whether the storage it freed + was adequate) it should return a nonzero value, whereupon BGET + will retry the allocation request and, if it fails again, call the + compaction function again with the next-higher sequence number. + + If the compaction function returns zero, indicating failure to + free space, or no compaction function is defined, BGET next tests + whether a non-NULL allocation function was supplied to bectl(). + If so, that function is called with an argument indicating how + many bytes of additional space are required. This will be the + standard pool expansion increment supplied in the call to bectl() + unless the original bget() call requested a buffer larger than + this; buffers larger than the standard pool block can be managed + "off the books" by BGET in this mode. If the allocation function + succeeds in obtaining the storage, it returns a pointer to the new + block and BGET expands the buffer pool; if it fails, the + allocation request fails and returns NULL to the caller. If a + non-NULL release function is supplied, expansion blocks which + become totally empty are released to the global free pool by + passing their addresses to the release function. + + Equipped with appropriate allocation, release, and compaction + functions, BGET can be used as part of very sophisticated memory + management strategies, including garbage collection. (Note, + however, that BGET is *not* a garbage collector by itself, and + that developing such a system requires much additional logic and + careful design of the application's memory allocation strategy.) + + + BGET FUNCTION DESCRIPTIONS + ========================== + + Functions implemented in this file (some are enabled by certain of + the optional settings below): + + void bpool(void *buffer, bufsize len); + + Create a buffer pool of bytes, using the storage starting at + . You can call bpool() subsequently to contribute + additional storage to the overall buffer pool. + + void *bget(bufsize size); + + Allocate a buffer of bytes. The address of the buffer is + returned, or NULL if insufficient memory was available to allocate + the buffer. + + void *bgetz(bufsize size); + + Allocate a buffer of bytes and clear it to all zeroes. The + address of the buffer is returned, or NULL if insufficient memory + was available to allocate the buffer. + + void *bgetr(void *buffer, bufsize newsize); + + Reallocate a buffer previously allocated by bget(), changing its + size to and preserving all existing data. NULL is + returned if insufficient memory is available to reallocate the + buffer, in which case the original buffer remains intact. + + void brel(void *buf); + + Return the buffer , previously allocated by bget(), to the + free space pool. + + void bectl(int (*compact)(bufsize sizereq, int sequence), + void *(*acquire)(bufsize size), + void (*release)(void *buf), + bufsize pool_incr); + + Expansion control: specify functions through which the package may + compact storage (or take other appropriate action) when an + allocation request fails, and optionally automatically acquire + storage for expansion blocks when necessary, and release such + blocks when they become empty. If is non-NULL, whenever + a buffer allocation request fails, the function will be + called with arguments specifying the number of bytes (total buffer + size, including header overhead) required to satisfy the + allocation request, and a sequence number indicating the number of + consecutive calls on attempting to satisfy this + allocation request. The sequence number is 1 for the first call + on for a given allocation request, and increments on + subsequent calls, permitting the function to take + increasingly dire measures in an attempt to free up storage. If + the function returns a nonzero value, the allocation + attempt is re-tried. If returns 0 (as it must if it + isn't able to release any space or add storage to the buffer + pool), the allocation request fails, which can trigger automatic + pool expansion if the argument is non-NULL. At the time + the function is called, the state of the buffer + allocator is identical to that at the moment the allocation + request was made; consequently, the function may call + brel(), bpool(), bstats(), and/or directly manipulate the buffer + pool in any manner which would be valid were the application in + control. This does not, however, relieve the function + of the need to ensure that whatever actions it takes do not change + things underneath the application that made the allocation + request. For example, a function that released a buffer + in the process of being reallocated with bgetr() would lead to + disaster. Implementing a safe and effective mechanism + requires careful design of an application's memory architecture, + and cannot generally be easily retrofitted into existing code. + + If is non-NULL, that function will be called whenever an + allocation request fails. If the function succeeds in + allocating the requested space and returns a pointer to the new + area, allocation will proceed using the expanded buffer pool. If + cannot obtain the requested space, it should return NULL + and the entire allocation process will fail. + specifies the normal expansion block size. Providing an + function will cause subsequent bget() requests for buffers too + large to be managed in the linked-block scheme (in other words, + larger than minus the buffer overhead) to be satisfied + directly by calls to the function. Automatic release of + empty pool blocks will occur only if all pool blocks in the system + are the size given by . + + void bstats(bufsize *curalloc, bufsize *totfree, + bufsize *maxfree, long *nget, long *nrel); + + The amount of space currently allocated is stored into the + variable pointed to by . The total free space (sum of + all free blocks in the pool) is stored into the variable pointed + to by , and the size of the largest single block in the + free space pool is stored into the variable pointed to by + . The variables pointed to by and are + filled, respectively, with the number of successful (non-NULL + return) bget() calls and the number of brel() calls. + + void bstatse(bufsize *pool_incr, long *npool, + long *npget, long *nprel, + long *ndget, long *ndrel); + + Extended statistics: The expansion block size will be stored into + the variable pointed to by , or the negative thereof if + automatic expansion block releases are disabled. The number of + currently active pool blocks will be stored into the variable + pointed to by . The variables pointed to by and + will be filled with, respectively, the number of expansion + block acquisitions and releases which have occurred. The + variables pointed to by and will be filled with + the number of bget() and brel() calls, respectively, managed + through blocks directly allocated by the acquisition and release + functions. + + void bufdump(void *buf); + + The buffer pointed to by is dumped on standard output. + + void bpoold(void *pool, int dumpalloc, int dumpfree); + + All buffers in the buffer pool , previously initialised by a + call on bpool(), are listed in ascending memory address order. If + is nonzero, the contents of allocated buffers are + dumped; if is nonzero, the contents of free blocks are + dumped. + + int bpoolv(void *pool); + + The named buffer pool, previously initialised by a call on + bpool(), is validated for bad pointers, overwritten data, etc. If + compiled with NDEBUG not defined, any error generates an assertion + failure. Otherwise 1 is returned if the pool is valid, 0 if an + error is found. + + + BGET CONFIGURATION + ================== +*/ + +#define ASSERT(t) + +#define TestProg 20000 /* Generate built-in test program + if defined. The value specifies + how many buffer allocation attempts + the test program should make. */ +#undef TestProg + +#define SizeQuant 4 /* Buffer allocation size quantum: + all buffers allocated are a + multiple of this size. This + MUST be a power of two. */ + +#define BufDump 1 /* Define this symbol to enable the + bpoold() function which dumps the + buffers in a buffer pool. */ +#undef BufDump + +#define BufValid 1 /* Define this symbol to enable the + bpoolv() function for validating + a buffer pool. */ +//#undef BufValid + +#define DumpData 1 /* Define this symbol to enable the + bufdump() function which allows + dumping the contents of an allocated + or free buffer. */ +#undef DumpData + +#define BufStats 1 /* Define this symbol to enable the + bstats() function which calculates + the total free space in the buffer + pool, the largest available + buffer, and the total space + currently allocated. */ +#ifndef DEBUG +#ifndef INCLUDE_BGET_STATS +#undef BufStats +#endif +#endif + +#define FreeWipe 1 /* Wipe free buffers to a guaranteed + pattern of garbage to trip up + miscreants who attempt to use + pointers into released buffers. */ +#undef FreeWipe + +#define BestFit 1 /* Use a best fit algorithm when + searching for space for an + allocation request. This uses + memory more efficiently, but + allocation will be much slower. */ + +#define BECtl 1 /* Define this symbol to enable the + bectl() function for automatic + pool space control. */ +#undef BECtl + + +#ifdef lint +#define NDEBUG /* Exits in asserts confuse lint */ +/* LINTLIBRARY */ /* Don't complain about def, no ref */ +extern char *sprintf(); /* Sun includes don't define sprintf */ +#endif + +#include +#include +#include +#include + +/* Replaced #include with this local definition. This prevents + * calls to the C runtime from assert(). These had caused problems when + * building using the IAR Embedded Workbench toolchain with semihosting + * disabled. + */ + +#ifdef BufDump /* BufDump implies DumpData */ +#ifndef DumpData +#define DumpData 1 +#endif +#endif + +#ifdef DumpData +#include +#endif + +/* Declare the interface, including the requested buffer size type, + bufsize. */ + +#include "bget.h" + + +#define MemSize int /* Type for size arguments to memxxx() + functions such as memcmp(). */ + +/* Queue links */ + +struct qlinks { + struct bfhead *flink; /* Forward link */ + struct bfhead *blink; /* Backward link */ +}; + +/* Header in allocated and free buffers */ + +struct bhead { + bufsize prevfree; /* Relative link back to previous + free buffer in memory or 0 if + previous buffer is allocated. */ + bufsize bsize; /* Buffer size: positive if free, + negative if allocated. */ +}; +#define BH(p) ((struct bhead *) (p)) + +/* Header in directly allocated buffers (by acqfcn) */ + +struct bdhead { + bufsize tsize; /* Total size, including overhead */ + struct bhead bh; /* Common header */ +}; +#define BDH(p) ((struct bdhead *) (p)) + +/* Header in free buffers */ + +struct bfhead { + struct bhead bh; /* Common allocated/free header */ + struct qlinks ql; /* Links on free list */ +}; +#define BFH(p) ((struct bfhead *) (p)) + +static struct bfhead freelist = { /* List of free buffers */ + {0, 0}, + {&freelist, &freelist} +}; + +unsigned int g_LargestBlockSize = 0; + +#ifdef BufStats +bufsize totalloc = 0; /* Total space currently allocated */ +static long numget = 0, numrel = 0; /* Number of bget() and brel() calls */ +#ifdef BECtl +static long numpblk = 0; /* Number of pool blocks */ +static long numpget = 0, numprel = 0; /* Number of block gets and rels */ +static long numdget = 0, numdrel = 0; /* Number of direct gets and rels */ +#endif /* BECtl */ +#endif /* BufStats */ + +#ifdef BECtl + +/* Automatic expansion block management functions */ + +static int (*compfcn) _((bufsize sizereq, int sequence)) = NULL; +static void *(*acqfcn) _((bufsize size)) = NULL; +static void (*relfcn) _((void *buf)) = NULL; + +static bufsize exp_incr = 0; /* Expansion block size */ +static bufsize pool_len = 0; /* 0: no bpool calls have been made + -1: not all pool blocks are + the same size + >0: (common) block size for all + bpool calls made so far + */ +#endif + +/* Minimum allocation quantum: */ + +#define QLSize (sizeof(struct qlinks)) +#define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) + +#define V (void) /* To denote unwanted returned values */ + +/* End sentinel: value placed in bsize field of dummy block delimiting + end of pool block. The most negative number which will fit in a + bufsize, defined in a way that the compiler will accept. */ + +#define ESent ((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2)) + +/* BGET -- Allocate a buffer. */ + +void *bget( + bufsize requested_size) +{ + bufsize size = requested_size; + struct bfhead *b; +#ifdef BestFit + struct bfhead *best; +#endif + void *buf; +#ifdef BECtl + int compactseq = 0; +#endif + + ASSERT(size > 0); + + if (size < SizeQ) { /* Need at least room for the */ + size = SizeQ; /* queue links. */ + } +#ifdef SizeQuant +#if SizeQuant > 1 + size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); +#endif +#endif + + size += sizeof(struct bhead); /* Add overhead in allocated buffer + to size required. */ + +#ifdef BECtl + /* If a compact function was provided in the call to bectl(), wrap + a loop around the allocation process to allow compaction to + intervene in case we don't find a suitable buffer in the chain. */ + + while (1) { +#endif + b = freelist.ql.flink; +#ifdef BestFit + best = &freelist; +#endif + + + /* Scan the free list searching for the first buffer big enough + to hold the requested size buffer. */ + +#ifdef BestFit + g_LargestBlockSize = 0; + while (b != &freelist) { + if( ((bufsize) b->bh.bsize) > g_LargestBlockSize ) + { + g_LargestBlockSize = (bufsize) b->bh.bsize; + } + if (b->bh.bsize >= size) { + if ((best == &freelist) || (b->bh.bsize < best->bh.bsize)) { + best = b; + } + } + b = b->ql.flink; /* Link to next buffer */ + } + b = best; +#endif /* BestFit */ + + while (b != &freelist) { + if ((bufsize) b->bh.bsize >= size) { + + /* Buffer is big enough to satisfy the request. Allocate it + to the caller. We must decide whether the buffer is large + enough to split into the part given to the caller and a + free buffer that remains on the free list, or whether the + entire buffer should be removed from the free list and + given to the caller in its entirety. We only split the + buffer if enough room remains for a header plus the minimum + quantum of allocation. */ + + if ((b->bh.bsize - size) > (SizeQ + (sizeof(struct bhead)))) { + struct bhead *ba, *bn; + + ba = BH(((char *) b) + (b->bh.bsize - size)); + bn = BH(((char *) ba) + size); + ASSERT(bn->prevfree == b->bh.bsize); + /* Subtract size from length of free block. */ + b->bh.bsize -= size; + /* Link allocated buffer to the previous free buffer. */ + ba->prevfree = b->bh.bsize; + /* Plug negative size into user buffer. */ + ba->bsize = -(bufsize) size; + /* Mark buffer after this one not preceded by free block. */ + bn->prevfree = 0; + +#ifdef BufStats + totalloc += size; + numget++; /* Increment number of bget() calls */ +#endif + buf = (void *) ((((char *) ba) + sizeof(struct bhead))); + return buf; + } else { + struct bhead *ba; + + ba = BH(((char *) b) + b->bh.bsize); + ASSERT(ba->prevfree == b->bh.bsize); + + /* The buffer isn't big enough to split. Give the whole + shebang to the caller and remove it from the free list. */ + + ASSERT(b->ql.blink->ql.flink == b); + ASSERT(b->ql.flink->ql.blink == b); + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + +#ifdef BufStats + totalloc += b->bh.bsize; + numget++; /* Increment number of bget() calls */ +#endif + /* Negate size to mark buffer allocated. */ + b->bh.bsize = -(b->bh.bsize); + + /* Zero the back pointer in the next buffer in memory + to indicate that this buffer is allocated. */ + ba->prevfree = 0; + + /* Give user buffer starting at queue links. */ + buf = (void *) &(b->ql); + return buf; + } + } + b = b->ql.flink; /* Link to next buffer */ + } +#ifdef BECtl + + /* We failed to find a buffer. If there's a compact function + defined, notify it of the size requested. If it returns + TRUE, try the allocation again. */ + + if ((compfcn == NULL) || (!(*compfcn)(size, ++compactseq))) { + break; + } + } + + /* No buffer available with requested size free. */ + + /* Don't give up yet -- look in the reserve supply. */ + + if (acqfcn != NULL) { + if (size > exp_incr - sizeof(struct bhead)) { + + /* Request is too large to fit in a single expansion + block. Try to satisy it by a direct buffer acquisition. */ + + struct bdhead *bdh; + + size += sizeof(struct bdhead) - sizeof(struct bhead); + if ((bdh = BDH((*acqfcn)((bufsize) size))) != NULL) { + + /* Mark the buffer special by setting the size field + of its header to zero. */ + bdh->bh.bsize = 0; + bdh->bh.prevfree = 0; + bdh->tsize = size; +#ifdef BufStats + totalloc += size; + numget++; /* Increment number of bget() calls */ + numdget++; /* Direct bget() call count */ +#endif + buf = (void *) (bdh + 1); + return buf; + } + + } else { + + /* Try to obtain a new expansion block */ + + void *newpool; + + if ((newpool = (*acqfcn)((bufsize) exp_incr)) != NULL) { + bpool(newpool, exp_incr); + buf = bget(requested_size); /* This can't, I say, can't + get into a loop. */ + return buf; + } + } + } + + /* Still no buffer available */ + +#endif /* BECtl */ + + return NULL; +} + +/* BGETZ -- Allocate a buffer and clear its contents to zero. We clear + the entire contents of the buffer to zero, not just the + region requested by the caller. */ + +void *bgetz( + bufsize size) +{ + char *buf = (char *) bget(size); + + if (buf != NULL) { + struct bhead *b; + bufsize rsize; + + b = BH(buf - sizeof(struct bhead)); + rsize = -(b->bsize); + if (rsize == 0) { + struct bdhead *bd; + + bd = BDH(buf - sizeof(struct bdhead)); + rsize = bd->tsize - sizeof(struct bdhead); + } else { + rsize -= sizeof(struct bhead); + } + ASSERT(rsize >= size); + V memset(buf, 0, (MemSize) rsize); + } + return ((void *) buf); +} + +/* BGETR -- Reallocate a buffer. This is a minimal implementation, + simply in terms of brel() and bget(). It could be + enhanced to allow the buffer to grow into adjacent free + blocks and to avoid moving data unnecessarily. */ + +void *bgetr( + void *buf, + bufsize size) +{ + void *nbuf; + bufsize osize; /* Old size of buffer */ + struct bhead *b; + + if ((nbuf = bget(size)) == NULL) { /* Acquire new buffer */ + return NULL; + } + if (buf == NULL) { + return nbuf; + } + b = BH(((char *) buf) - sizeof(struct bhead)); + osize = -b->bsize; +#ifdef BECtl + if (osize == 0) { + /* Buffer acquired directly through acqfcn. */ + struct bdhead *bd; + + bd = BDH(((char *) buf) - sizeof(struct bdhead)); + osize = bd->tsize - sizeof(struct bdhead); + } else +#endif + osize -= sizeof(struct bhead); + ASSERT(osize > 0); + V memcpy((char *) nbuf, (char *) buf, /* Copy the data */ + (MemSize) ((size < osize) ? size : osize)); + brel(buf); + return nbuf; +} + +/* BREL -- Release a buffer. */ + +void brel( + void *buf) +{ + struct bfhead *b, *bn; + + b = BFH(((char *) buf) - sizeof(struct bhead)); +#ifdef BufStats + numrel++; /* Increment number of brel() calls */ +#endif + ASSERT(buf != NULL); + +#ifdef BECtl + if (b->bh.bsize == 0) { /* Directly-acquired buffer? */ + struct bdhead *bdh; + + bdh = BDH(((char *) buf) - sizeof(struct bdhead)); + ASSERT(b->bh.prevfree == 0); +#ifdef BufStats + totalloc -= bdh->tsize; + ASSERT(totalloc >= 0); + numdrel++; /* Number of direct releases */ +#endif /* BufStats */ +#ifdef FreeWipe + V memset((char *) buf, 0x55, + (MemSize) (bdh->tsize - sizeof(struct bdhead))); +#endif /* FreeWipe */ + ASSERT(relfcn != NULL); + (*relfcn)((void *) bdh); /* Release it directly. */ + return; + } +#endif /* BECtl */ + + /* Buffer size must be negative, indicating that the buffer is + allocated. */ + + if (b->bh.bsize >= 0) { + bn = NULL; + } + ASSERT(b->bh.bsize < 0); + + /* Back pointer in next buffer must be zero, indicating the + same thing: */ + + ASSERT(BH((char *) b - b->bh.bsize)->prevfree == 0); + +#ifdef BufStats + totalloc += b->bh.bsize; + ASSERT(totalloc >= 0); +#endif + + /* If the back link is nonzero, the previous buffer is free. */ + + if (b->bh.prevfree != 0) { + + /* The previous buffer is free. Consolidate this buffer with it + by adding the length of this buffer to the previous free + buffer. Note that we subtract the size in the buffer being + released, since it's negative to indicate that the buffer is + allocated. */ + + register bufsize size = b->bh.bsize; + + /* Make the previous buffer the one we're working on. */ + ASSERT(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); + b = BFH(((char *) b) - b->bh.prevfree); + b->bh.bsize -= size; + } else { + + /* The previous buffer isn't allocated. Insert this buffer + on the free list as an isolated free block. */ + + ASSERT(freelist.ql.blink->ql.flink == &freelist); + ASSERT(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + b->bh.bsize = -b->bh.bsize; + } + + /* Now we look at the next buffer in memory, located by advancing from + the start of this buffer by its size, to see if that buffer is + free. If it is, we combine this buffer with the next one in + memory, dechaining the second buffer from the free list. */ + + bn = BFH(((char *) b) + b->bh.bsize); + if (bn->bh.bsize > 0) { + + /* The buffer is free. Remove it from the free list and add + its size to that of our buffer. */ + + ASSERT(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); + ASSERT(bn->ql.blink->ql.flink == bn); + ASSERT(bn->ql.flink->ql.blink == bn); + bn->ql.blink->ql.flink = bn->ql.flink; + bn->ql.flink->ql.blink = bn->ql.blink; + b->bh.bsize += bn->bh.bsize; + + /* Finally, advance to the buffer that follows the newly + consolidated free block. We must set its backpointer to the + head of the consolidated free block. We know the next block + must be an allocated block because the process of recombination + guarantees that two free blocks will never be contiguous in + memory. */ + + bn = BFH(((char *) b) + b->bh.bsize); + } +#ifdef FreeWipe + V memset(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (b->bh.bsize - sizeof(struct bfhead))); +#endif + ASSERT(bn->bh.bsize < 0); + + /* The next buffer is allocated. Set the backpointer in it to point + to this buffer; the previous free buffer in memory. */ + + bn->bh.prevfree = b->bh.bsize; + +#ifdef BECtl + + /* If a block-release function is defined, and this free buffer + constitutes the entire block, release it. Note that pool_len + is defined in such a way that the test will fail unless all + pool blocks are the same size. */ + + if (relfcn != NULL && + ((bufsize) b->bh.bsize) == (pool_len - sizeof(struct bhead))) { + + ASSERT(b->bh.prevfree == 0); + ASSERT(BH((char *) b + b->bh.bsize)->bsize == ESent); + ASSERT(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); + /* Unlink the buffer from the free list */ + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + (*relfcn)(b); +#ifdef BufStats + numprel++; /* Nr of expansion block releases */ + numpblk--; /* Total number of blocks */ + ASSERT(numpblk == numpget - numprel); +#endif /* BufStats */ + } +#endif /* BECtl */ +} + +#ifdef BECtl + +/* BECTL -- Establish automatic pool expansion control */ + +void bectl( + int (*compact) _((bufsize sizereq, int sequence)), + void *(*acquire) _((bufsize size)), + void (*release) _((void *buf)), + bufsize pool_incr) +{ + compfcn = compact; + acqfcn = acquire; + relfcn = release; + exp_incr = pool_incr; +} +#endif + +/* BPOOL -- Add a region of memory to the buffer pool. */ + +void bpool( + void *buf, + bufsize len) +{ + struct bfhead *b = BFH(buf); + struct bhead *bn; + +#ifdef SizeQuant + len &= ~(SizeQuant - 1); +#endif +#ifdef BECtl + if (pool_len == 0) { + pool_len = len; + } else if (len != pool_len) { + pool_len = -1; + } +#ifdef BufStats + numpget++; /* Number of block acquisitions */ + numpblk++; /* Number of blocks total */ + ASSERT(numpblk == numpget - numprel); +#endif /* BufStats */ +#endif /* BECtl */ + + /* Since the block is initially occupied by a single free buffer, + it had better not be (much) larger than the largest buffer + whose size we can store in bhead.bsize. */ + + ASSERT(len - sizeof(struct bhead) <= -((bufsize) ESent + 1)); + + /* Clear the backpointer at the start of the block to indicate that + there is no free block prior to this one. That blocks + recombination when the first block in memory is released. */ + + b->bh.prevfree = 0; + + /* Chain the new block to the free list. */ + + ASSERT(freelist.ql.blink->ql.flink == &freelist); + ASSERT(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + + /* Create a dummy allocated buffer at the end of the pool. This dummy + buffer is seen when a buffer at the end of the pool is released and + blocks recombination of the last buffer with the dummy buffer at + the end. The length in the dummy buffer is set to the largest + negative number to denote the end of the pool for diagnostic + routines (this specific value is not counted on by the actual + allocation and release functions). */ + + len -= sizeof(struct bhead); + b->bh.bsize = (bufsize) len; +#ifdef FreeWipe + V memset(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (len - sizeof(struct bfhead))); +#endif + bn = BH(((char *) b) + len); + bn->prevfree = (bufsize) len; + /* Definition of ESent assumes two's complement! */ + ASSERT((~0) == -1); + bn->bsize = ESent; +} + +#ifdef BufStats + +/* BSTATS -- Return buffer allocation free space statistics. */ + +void bstats( + bufsize *curalloc, bufsize *totfree, bufsize *maxfree, + long *nget, long *nrel) +{ + struct bfhead *b = freelist.ql.flink; + + *nget = numget; + *nrel = numrel; + *curalloc = totalloc; + *totfree = 0; + *maxfree = -1; + while (b != &freelist) { + ASSERT(b->bh.bsize > 0); + *totfree += b->bh.bsize; + if (b->bh.bsize > *maxfree) { + *maxfree = b->bh.bsize; + } + b = b->ql.flink; /* Link to next buffer */ + } +} + +#ifdef BECtl + +/* BSTATSE -- Return extended statistics */ + +void bstatse( + bufsize *pool_incr, + long *npool, long *npget, long *nprel, long *ndget, long *ndrel) +{ + *pool_incr = (pool_len < 0) ? -exp_incr : exp_incr; + *npool = numpblk; + *npget = numpget; + *nprel = numprel; + *ndget = numdget; + *ndrel = numdrel; +} +#endif /* BECtl */ +#endif /* BufStats */ + +#ifdef DumpData + +/* BUFDUMP -- Dump the data in a buffer. This is called with the user + data pointer, and backs up to the buffer header. It will + dump either a free block or an allocated one. */ + +void bufdump( + void *buf) +{ + struct bfhead *b; + unsigned char *bdump; + bufsize bdlen; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + ASSERT(b->bh.bsize != 0); + if (b->bh.bsize < 0) { + bdump = (unsigned char *) buf; + bdlen = (-b->bh.bsize) - sizeof(struct bhead); + } else { + bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead)); + bdlen = b->bh.bsize - sizeof(struct bfhead); + } + + while (bdlen > 0) { + int i, dupes = 0; + bufsize l = bdlen; + char bhex[50], bascii[20]; + + if (l > 16) { + l = 16; + } + + for (i = 0; i < l; i++) { + V sprintf(bhex + i * 3, "%02X ", bdump[i]); + bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; + } + bascii[i] = 0; + V printf("%-48s %s\n", bhex, bascii); + bdump += l; + bdlen -= l; + while ((bdlen > 16) && (memcmp((char *) (bdump - 16), + (char *) bdump, 16) == 0)) { + dupes++; + bdump += 16; + bdlen -= 16; + } + if (dupes > 1) { + V printf( + " (%d lines [%d bytes] identical to above line skipped)\n", + dupes, dupes * 16); + } else if (dupes == 1) { + bdump -= 16; + bdlen += 16; + } + } +} +#endif + +#ifdef BufDump + +/* BPOOLD -- Dump a buffer pool. The buffer headers are always listed. + If DUMPALLOC is nonzero, the contents of allocated buffers + are dumped. If DUMPFREE is nonzero, free blocks are + dumped as well. If FreeWipe checking is enabled, free + blocks which have been clobbered will always be dumped. */ + +void bpoold( + void *buf, + int dumpalloc, int dumpfree) +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) { + bufsize bs = b->bh.bsize; + + if (bs < 0) { + bs = -bs; + V printf("Allocated buffer: size %6ld bytes.\n", (long) bs); + if (dumpalloc) { + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } + } else { + char *lerr = ""; + + ASSERT(bs > 0); + if ((b->ql.blink->ql.flink != b) || + (b->ql.flink->ql.blink != b)) { + lerr = " (Bad free list links)"; + } + V printf("Free block: size %6ld bytes.%s\n", + (long) bs, lerr); +#ifdef FreeWipe + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, + (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { + V printf( + "(Contents of above free block have been overstored.)\n"); + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } else +#endif + if (dumpfree) { + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + b = BFH(((char *) b) + bs); + } +} +#endif /* BufDump */ + +#ifdef BufValid + +/* BPOOLV -- Validate a buffer pool. If NDEBUG isn't defined, + any error generates an assertion failure. */ + +int bpoolv( + void *buf) +{ + struct bfhead *b = BFH(buf); + struct bfhead *bn; + while (b->bh.bsize != ESent) { + bufsize bs = b->bh.bsize; + + if (bs < 0) { + //buffer allocated + bs = -bs; + bn = BFH(((char *) b) + bs); + /* Suppressing "bh" unused warning due to undefined ASSERT(t) */ + (void) bn; + ASSERT(bn->bh.prevfree== 0); + } else { + //buffer free + ASSERT(bs > 0); + if (bs <= 0) { + return 0; + } + bn = BFH(((char *) b) + bs); + //verify next buffer prevfree have that size + ASSERT(bn->bh.prevfree == b->bh.bsize); + + + + + + if ((b->ql.blink->ql.flink != b) || + (b->ql.flink->ql.blink != b)) { + //V printf("Free block: size %6ld bytes. (Bad free list links)\n", (long) bs); + ASSERT(0); + return 0; + } +#ifdef FreeWipe + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, + (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { + V printf( + "(Contents of above free block have been overstored.)\n"); + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + ASSERT(0); + return 0; + } +#endif + } + b = BFH(((char *) b) + bs); + } + return 1; +} +#endif /* BufValid */ + + /***********************\ + * * + * Built-in test program * + * * + \***********************/ + +#ifdef TestProg + +#define Repeatable 1 /* Repeatable pseudorandom sequence */ + /* If Repeatable is not defined, a + time-seeded pseudorandom sequence + is generated, exercising BGET with + a different pattern of calls on each + run. */ +#define OUR_RAND /* Use our own built-in version of + rand() to guarantee the test is + 100% repeatable. */ + +#ifdef BECtl +#define PoolSize 300000 /* Test buffer pool size */ +#else +#define PoolSize 50000 /* Test buffer pool size */ +#endif +#define ExpIncr 32768 /* Test expansion block size */ +#define CompactTries 10 /* Maximum tries at compacting */ + +#define dumpAlloc 0 /* Dump allocated buffers ? */ +#define dumpFree 0 /* Dump free buffers ? */ + +#ifndef Repeatable +extern long time(); +#endif + +extern char *malloc(); +extern int free _((char *)); + +static char *bchain = NULL; /* Our private buffer chain */ +static char *bp = NULL; /* Our initial buffer pool */ + +#include + +#ifdef OUR_RAND + +static unsigned long int next = 1; + +/* Return next random integer */ + +int rand() +{ + next = next * 1103515245L + 12345; + return (unsigned int) (next / 65536L) % 32768L; +} + +/* Set seed for random generator */ + +void srand(seed) + unsigned int seed; +{ + next = seed; +} +#endif + +/* STATS -- Edit statistics returned by bstats() or bstatse(). */ + +static void stats(when) + char *when; +{ + bufsize cural, totfree, maxfree; + long nget, nfree; +#ifdef BECtl + bufsize pincr; + long totblocks, npget, nprel, ndget, ndrel; +#endif + + bstats(&cural, &totfree, &maxfree, &nget, &nfree); + V printf( + "%s: %ld gets, %ld releases. %ld in use, %ld free, largest = %ld\n", + when, nget, nfree, (long) cural, (long) totfree, (long) maxfree); +#ifdef BECtl + bstatse(&pincr, &totblocks, &npget, &nprel, &ndget, &ndrel); + V printf( + " Blocks: size = %ld, %ld (%ld bytes) in use, %ld gets, %ld frees\n", + (long)pincr, totblocks, pincr * totblocks, npget, nprel); + V printf(" %ld direct gets, %ld direct frees\n", ndget, ndrel); +#endif /* BECtl */ +} + +#ifdef BECtl +static int protect = 0; /* Disable compaction during bgetr() */ + +/* BCOMPACT -- Compaction call-back function. */ + +static int bcompact(bsize, seq) + bufsize bsize; + int seq; +{ +#ifdef CompactTries + char *bc = bchain; + int i = rand() & 0x3; + +#ifdef COMPACTRACE + V printf("Compaction requested. %ld bytes needed, sequence %d.\n", + (long) bsize, seq); +#endif + + if (protect || (seq > CompactTries)) { +#ifdef COMPACTRACE + V printf("Compaction gave up.\n"); +#endif + return 0; + } + + /* Based on a random cast, release a random buffer in the list + of allocated buffers. */ + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + return 1; + } + } + +#ifdef COMPACTRACE + V printf("Compaction bailed out.\n"); +#endif +#endif /* CompactTries */ + return 0; +} + +/* BEXPAND -- Expand pool call-back function. */ + +static void *bexpand(size) + bufsize size; +{ + void *np = NULL; + bufsize cural, totfree, maxfree; + long nget, nfree; + + /* Don't expand beyond the total allocated size given by PoolSize. */ + + bstats(&cural, &totfree, &maxfree, &nget, &nfree); + + if (cural < PoolSize) { + np = (void *) malloc((unsigned) size); + } +#ifdef EXPTRACE + V printf("Expand pool by %ld -- %s.\n", (long) size, + np == NULL ? "failed" : "succeeded"); +#endif + return np; +} + +/* BSHRINK -- Shrink buffer pool call-back function. */ + +static void bshrink(buf) + void *buf; +{ + if (((char *) buf) == bp) { +#ifdef EXPTRACE + V printf("Initial pool released.\n"); +#endif + bp = NULL; + } +#ifdef EXPTRACE + V printf("Shrink pool.\n"); +#endif + free((char *) buf); +} + +#endif /* BECtl */ + +/* Restrict buffer requests to those large enough to contain our pointer and + small enough for the CPU architecture. */ + +static bufsize blimit(bs) + bufsize bs; +{ + if (bs < sizeof(char *)) { + bs = sizeof(char *); + } + + /* This is written out in this ugly fashion because the + cool expression in sizeof(int) that auto-configured + to any length int befuddled some compilers. */ + + if (sizeof(int) == 2) { + if (bs > 32767) { + bs = 32767; + } + } else { + if (bs > 200000) { + bs = 200000; + } + } + return bs; +} + +int main() +{ + int i; + double x; + + /* Seed the random number generator. If Repeatable is defined, we + always use the same seed. Otherwise, we seed from the clock to + shake things up from run to run. */ + +#ifdef Repeatable + V srand(1234); +#else + V srand((int) time((long *) NULL)); +#endif + + /* Compute x such that pow(x, p) ranges between 1 and 4*ExpIncr as + p ranges from 0 to ExpIncr-1, with a concentration in the lower + numbers. */ + + x = 4.0 * ExpIncr; + x = log(x); + x = exp(log(4.0 * ExpIncr) / (ExpIncr - 1.0)); + +#ifdef BECtl + bectl(bcompact, bexpand, bshrink, (bufsize) ExpIncr); + bp = malloc(ExpIncr); + ASSERT(bp != NULL); + bpool((void *) bp, (bufsize) ExpIncr); +#else + bp = malloc(PoolSize); + ASSERT(bp != NULL); + bpool((void *) bp, (bufsize) PoolSize); +#endif + + stats("Create pool"); + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + + for (i = 0; i < TestProg; i++) { + char *cb; + bufsize bs = pow(x, (double) (rand() & (ExpIncr - 1))); + + ASSERT(bs <= (((bufsize) 4) * ExpIncr)); + bs = blimit(bs); + if (rand() & 0x400) { + cb = (char *) bgetz(bs); + } else { + cb = (char *) bget(bs); + } + if (cb == NULL) { +#ifdef EasyOut + break; +#else + char *bc = bchain; + + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + } + continue; + } +#endif + } + *((char **) cb) = (char *) bchain; + bchain = cb; + + /* Based on a random cast, release a random buffer in the list + of allocated buffers. */ + + if ((rand() & 0x10) == 0) { + char *bc = bchain; + int i = rand() & 0x3; + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + } + } + } + + /* Based on a random cast, reallocate a random buffer in the list + to a random size */ + + if ((rand() & 0x20) == 0) { + char *bc = bchain; + int i = rand() & 0x3; + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + char *newb; + + bs = pow(x, (double) (rand() & (ExpIncr - 1))); + bs = blimit(bs); +#ifdef BECtl + protect = 1; /* Protect against compaction */ +#endif + newb = (char *) bgetr((void *) fb, bs); +#ifdef BECtl + protect = 0; +#endif + if (newb != NULL) { + *((char **) bc) = newb; + } + } + } + } + } + stats("\nAfter allocation"); + if (bp != NULL) { + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + } + + while (bchain != NULL) { + char *buf = bchain; + + bchain = *((char **) buf); + brel((void *) buf); + } + stats("\nAfter release"); +#ifndef BECtl + if (bp != NULL) { + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + } +#endif + + return 0; +} +#endif diff --git a/examples/apps/cli/bget.h b/examples/apps/cli/bget.h new file mode 100755 index 0000000..643b908 --- /dev/null +++ b/examples/apps/cli/bget.h @@ -0,0 +1,49 @@ +/* + + Interface definitions for bget.c, the memory management package. + +*/ + +#ifndef __BGET_H__ +#define __BGET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PROTOTYPES + +#ifndef _ +#ifdef PROTOTYPES +#define _(x) x /* If compiler knows prototypes */ +#else +#define _(x) () /* It it doesn't */ +#endif /* PROTOTYPES */ +#endif + +#if !defined NULL + #define NULL ((void *) 0) +#endif + + +typedef long bufsize; +void bpool _((void *buffer, bufsize len)); +void *bget _((bufsize size)); +void *bgetz _((bufsize size)); +void *bgetr _((void *buffer, bufsize newsize)); +void brel _((void *buf)); +void bectl _((int (*compact)(bufsize sizereq, int sequence), + void *(*acquire)(bufsize size), + void (*release)(void *buf), bufsize pool_incr)); +void bstats _((bufsize *curalloc, bufsize *totfree, bufsize *maxfree, + long *nget, long *nrel)); +void bstatse _((bufsize *pool_incr, long *npool, long *npget, + long *nprel, long *ndget, long *ndrel)); +void bufdump _((void *buf)); +void bpoold _((void *pool, int dumpalloc, int dumpfree)); +int bpoolv _((void *pool)); + +#ifdef __cplusplus +} +#endif +#endif // __BGET_H__ diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index 5d13697..ea6e811 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -59,6 +59,12 @@ #include "bleStack_menu.h" #include "ti_ble_config.h" +#include "ti_dmm_application_policy.h" +#include +#include +#include +#include + #ifdef PTM_MODE #include "npi_task.h" // To allow RX event registration #include "npi_ble.h" // To enable transmission of messages to UART @@ -392,18 +398,14 @@ static TaskHandle_t BLEAPPTaskHandle = NULL; void bleAppTask_init() { - RegisterAssertCback(AssertHandler); - // initialize the ICall module - ICall_init(); - - // Start tasks of external images - Priority 5 - ICall_createRemoteTasks(); if (xTaskCreate(BleMain, "BleMain", BLEAPP_TASK_STACK_SIZE/sizeof(StackType_t), NULL, BLEAPP_TASK_PRIORITY, &BLEAPPTaskHandle)!=pdPASS) { otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM,"BLEAPP Failed to created\n"); while (1) ; } + + } static void BleMain(void * pvParameter) @@ -1865,7 +1867,7 @@ static uint8_t SimplePeripheral_removeConn(uint16_t connHandle) } // Destruct the clock object - Clock_destruct(pUpdateClock); + ClockP_destruct((ClockP_Struct *) pUpdateClock); // Free clock struct ICall_free(pUpdateClock); // Free ParamUpdateEventData @@ -1910,7 +1912,7 @@ static void SimplePeripheral_processParamUpdate(uint16_t connHandle) } // Deconstruct the clock object - Clock_destruct(connList[connIndex].pUpdateClock); + ClockP_destruct((ClockP_Struct *) connList[connIndex].pUpdateClock); // Free clock struct, only in case it is not NULL if (connList[connIndex].pUpdateClock != NULL) { @@ -2351,6 +2353,21 @@ static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, static void bleStack_init(void) { + RegisterAssertCback(AssertHandler); + // initialize the ICall module + ICall_init(); + vTaskPrioritySet(xTaskGetCurrentTaskHandle(), 5); + // Start tasks of external images - Priority 5 + ICall_createRemoteTasks(); + TaskHandle_t blehndl = ICall_getRemoteTaskHandle(0); + TaskHandle_t *blehndle2 = (TaskHandle_t*)blehndl; + DMMSch_registerClient(*blehndle2, DMMPolicy_StackRole_BlePeripheral); + DMMPolicy_updateStackState(DMMPolicy_StackRole_BlePeripheral, DMMPOLICY_BLE_IDLE); + vTaskPrioritySet(xTaskGetCurrentTaskHandle(), 3); + + + + bleStack_buildMenu(); //Register the current thread as an ICall dispatcher application @@ -2370,7 +2387,7 @@ static void bleStack_init(void) Util_constructQueue(&g_POSIX_appMsgQueue); // Create one-shot clock for internal periodic events. - //Wei + //Weiadv Util_constructClock(&clkPeriodic, (void *)SimplePeripheral_clockHandler, SP_PERIODIC_EVT_PERIOD, 0, false, (uint32_t)&argPeriodic); diff --git a/examples/apps/cli/ble_user_config.c b/examples/apps/cli/ble_user_config.c new file mode 100755 index 0000000..d5579bf --- /dev/null +++ b/examples/apps/cli/ble_user_config.c @@ -0,0 +1,560 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Texas Instruments Incorporated + * + * 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 user configurable variables for the BLE Application. + * + */ + +/******************************************************************************* + * INCLUDES + */ + +#include "ble_user_config.h" +#include "hal_types.h" +#ifndef FREERTOS +#include +#endif +#ifdef SYSCFG +#include "ti_ble_config.h" +#else +#include +#endif + +#ifndef CC23X0 +#include "ble_overrides.h" +#include "ti_radio_config.h" + +#include "ecc/ECCROMCC26XX.h" +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include + +#ifdef FREERTOS +#define Swi_restore SwiP_restore +#define Swi_disable SwiP_disable +#include +#else +#include +#endif +#include + +#ifndef CC23X0 +#if !defined(DeviceFamily_CC26X1) +#include +#if !defined(DeviceFamily_CC13X4) && !defined(DeviceFamily_CC26X4) +#include +#endif +#else +#include +#endif +#endif + +/******************************************************************************* + * MACROS + */ + +/******************************************************************************* + * CONSTANTS + */ + +// Tx Power +#define NUM_TX_POWER_VALUES (RF_BLE_TX_POWER_TABLE_SIZE - 1) + +#ifndef SYSCFG +// Default Tx Power Index +#if defined(CC13X2P) +#define DEFAULT_TX_POWER HCI_EXT_TX_POWER_0_DBM +#else // !CC13X2 +#define DEFAULT_TX_POWER HCI_EXT_TX_POWER_0_DBM +#endif // CC13X2 +#endif // SYSCFG + +// Override NOP +#define OVERRIDE_NOP 0xC0000001 + +/******************************************************************************* + * TYPEDEFS + */ + +/******************************************************************************* + * LOCAL VARIABLES + */ + +/********************************************************************* + * LOCAL FUNCTIONS + */ + +void driverTable_fnSpinlock(void); + +/******************************************************************************* + * GLOBAL VARIABLES + */ + +#ifndef CC23X0 +// Tx Power Table +txPwrTbl_t appTxPwrTbl = { (txPwrVal_t *) RF_BLE_txPowerTable, + NUM_TX_POWER_VALUES, // max + DEFAULT_TX_POWER }; // default +#endif +#if defined(CC13X2P) && defined(CC13X2P_2_LAUNCHXL) + +// Tx Power Backoff Values (txPwrBackoff1MPhy,txPwrBackoff2MPhy ,txPwrBackoffCoded) +const txPwrBackoffVal_t TxPowerBackoffTable[] = { + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 0 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 1 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 2 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 3 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 4 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 5 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 6 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 7 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 8 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 9 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 10 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 11 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 12 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 13 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 14 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 15 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 16 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 17 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 18 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 19 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 20 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 21 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 22 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 23 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 24 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 25 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 26 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 27 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 28 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 29 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 30 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 31 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 32 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 33 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_17_DBM_P4_9_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 34 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_18_DBM_P4_10_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 35 + { HCI_EXT_TX_POWER_P2_19_DBM, HCI_EXT_TX_POWER_P2_18_DBM_P4_10_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 36 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 37 + { HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM }, // max tx power for channel 38 + { HCI_EXT_TX_POWER_P2_14_DBM_P4_6_DBM, HCI_EXT_TX_POWER_P2_20_DBM, HCI_EXT_TX_POWER_P2_20_DBM } +}; // max tx power for channel 39 + +txPwrBackoffTbl_t appTxPwrBackoffTbl = { TxPowerBackoffTable }; + +#endif // defined(CC13X2P) && defined(CC13X2P_2_LAUNCHXL) + +// Antenna board configurations (example for a 12-antenna board) +// Maximum number of antennas +#define ANTENNA_TABLE_SIZE 12 +// BitMask of all the relevant GPIOs which needed for the antennas +#define ANTENNA_IO_MASK BV(27) | BV(28) | BV(29) | BV(30) + +// Antenna GPIO configuration (should be adapted to the antenna board design) +antennaIOEntry_t antennaTbl[ANTENNA_TABLE_SIZE] = { + 0, // antenna 0 GPIO configuration (all GPIOs in ANTENNA_IO_MASK are LOW) + BV(28), // antenna 1 + BV(29), // antenna 2 + BV(28) | BV(29), // antenna 3 + BV(30), // antenna 4 + BV(28) | BV(30), // antenna 5 + BV(27), // antenna 6 + BV(27) | BV(28), // antenna 7 + BV(27) | BV(29), // antenna 8 + BV(27) | BV(28) | BV(29), // antenna 9 + BV(27) | BV(30), // antenna 10 + BV(27) | BV(28) | BV(30) // antenna 11 +}; + +#ifdef RTLS_CTE +// Antenna properties passes to the stack +cteAntProp_t appCTEAntProp = { ANTENNA_IO_MASK, ANTENNA_TABLE_SIZE, antennaTbl }; +#endif + +#ifdef CC23X0 +ECCParams_CurveParams eccParams_NISTP256 = { .curveType = ECCParams_CURVE_TYPE_SHORT_WEIERSTRASS_AN3, + .length = ECCParams_NISTP256_LENGTH, + .prime = ECC_NISTP256_prime.byte, + .order = ECC_NISTP256_order.byte, + .a = ECC_NISTP256_a.byte, + .b = ECC_NISTP256_b.byte, + .generatorX = ECC_NISTP256_generatorX.byte, + .generatorY = ECC_NISTP256_generatorY.byte, + .cofactor = 1 }; +#elif !defined(DeviceFamily_CC26X1) +ECCParams_CurveParams eccParams_NISTP256 = { .curveType = ECCParams_CURVE_TYPE_SHORT_WEIERSTRASS_AN3, + .length = NISTP256_PARAM_SIZE_BYTES, + .prime = NISTP256_prime.byte, + .order = NISTP256_order.byte, + .a = NISTP256_a.byte, + .b = NISTP256_b.byte, + .generatorX = NISTP256_generator.x.byte, + .generatorY = NISTP256_generator.y.byte, + .cofactor = 1 }; +#else +ECCParams_CurveParams eccParams_NISTP256 = { .curveType = ECCParams_CURVE_TYPE_SHORT_WEIERSTRASS_AN3, + .length = ECC_NISTP256_PARAM_LENGTH_BYTES, + .prime = ECC_NISTP256_prime.byte, + .order = ECC_NISTP256_order.byte, + .a = ECC_NISTP256_a.byte, + .b = ECC_NISTP256_b.byte, + .generatorX = ECC_NISTP256_generatorX.byte, + .generatorY = ECC_NISTP256_generatorY.byte, + .cofactor = 1 }; +#endif + +#if defined(USE_COEX) +// 2 structures generated by the sysconfig RF for coexistence configuration +extern rfCoreHal_bleCoExConfig_t coexConfig; +extern RF_CoexOverride_BLEUseCases coexConfigBle; +// from coexConfig struct we will get the coex enable and coex type (3 or 1 wire) +// from coexConfigBle struct we will get the priority and rx request per use case: +// initiator, connected, Broadcaster and Observer. +coexUseCaseConfig_t coexSysConfig = { &coexConfig, &coexConfigBle }; +#endif + +#ifdef ICALL_JT +#include + +#ifndef CC23X0 +// RF Driver API Table +rfDrvTblPtr_t rfDriverTableBLE[] = { + (uint32) RF_open, + (uint32) driverTable_fnSpinlock, // RF_close +#ifdef RF_SINGLEMODE + (uint32) RF_postCmd, +#else // !RF_SINGLEMODE + (uint32) driverTable_fnSpinlock, // RF_postCmd +#endif // RF_SINGLEMODE + (uint32) driverTable_fnSpinlock, // RF_pendCmd +#ifdef RF_SINGLEMODE + (uint32) RF_runCmd, +#else // !RF_SINGLEMODE + (uint32) driverTable_fnSpinlock, // RF_runCmd +#endif // RF_SINGLEMODE + (uint32) RF_cancelCmd, + (uint32) RF_flushCmd, + (uint32) driverTable_fnSpinlock, // RF_yield + (uint32) RF_Params_init, + (uint32) RF_runImmediateCmd, + (uint32) RF_runDirectCmd, + (uint32) RF_ratCompare, + (uint32) driverTable_fnSpinlock, // RF_ratCapture + (uint32) RF_ratDisableChannel, + (uint32) RF_getCurrentTime, + (uint32) RF_getRssi, + (uint32) RF_getInfo, + (uint32) RF_getCmdOp, + (uint32) RF_control, + (uint32) driverTable_fnSpinlock, // RF_getTxPower + (uint32) RF_setTxPower, // RF_setTxPower + (uint32) driverTable_fnSpinlock, // RF_TxPowerTable_findPowerLevel + (uint32) driverTable_fnSpinlock, // RF_TxPowerTable_findValue +#ifndef RF_SINGLEMODE + (uint32) RF_scheduleCmd, + (uint32) RF_runScheduleCmd, + (uint32) driverTable_fnSpinlock, // RF_requestAccess +#endif // !RF_SINGLEMODE +}; + +cryptoDrvTblPtr_t cryptoDriverTableBLE[] = { (uint32) AESCCM_init, + (uint32) AESCCM_open, + (uint32) AESCCM_close, + (uint32) AESCCM_Params_init, + (uint32) AESCCM_Operation_init, + (uint32) AESCCM_oneStepEncrypt, + (uint32) AESCCM_oneStepDecrypt, + (uint32) AESECB_init, + (uint32) AESECB_open, + (uint32) AESECB_close, + (uint32) AESECB_Params_init, + (uint32) AESECB_Operation_init, + (uint32) AESECB_oneStepEncrypt, + (uint32) AESECB_oneStepDecrypt, + (uint32) CryptoKeyPlaintext_initKey, + (uint32) CryptoKeyPlaintext_initBlankKey }; + +// Swi APIs needed by BLE controller +rtosApiTblPtr_t rtosApiTable[] = { (uint32_t) Swi_disable, (uint32_t) Swi_restore }; +#endif +// BLE Stack Configuration Structure +const stackSpecific_t bleStackConfig = { .maxNumConns = MAX_NUM_BLE_CONNS, + .maxNumPDUs = MAX_NUM_PDU, + .maxPduSize = 0, + .maxNumPSM = L2CAP_NUM_PSM, + .maxNumCoChannels = L2CAP_NUM_CO_CHANNELS, + .maxWhiteListElems = MAX_NUM_WL_ENTRIES, + .maxResolvListElems = CFG_MAX_NUM_RL_ENTRIES, + .pfnBMAlloc = &pfnBMAlloc, + .pfnBMFree = &pfnBMFree, +#ifndef CC23X0 + .rfDriverParams.powerUpDurationMargin = RF_POWER_UP_DURATION_MARGIN, + .rfDriverParams.inactivityTimeout = RF_INACTIVITY_TIMEOUT, + .rfDriverParams.powerUpDuration = RF_POWER_UP_DURATION, + .rfDriverParams.pErrCb = &(RF_ERR_CB), +#endif + .eccParams = &eccParams_NISTP256, + .fastStateUpdateCb = NULL, + .bleStackType = 0, +#ifdef CC2652RB_LAUNCHXL + .extStackSettings = EXTENDED_STACK_SETTINGS | CC2652RB_OVERRIDE_USED, +#else + .extStackSettings = EXTENDED_STACK_SETTINGS, +#endif +#ifndef CC23X0 + .maxNumCteBuffers = MAX_NUM_CTE_BUFS, + .advReportIncChannel = ADV_RPT_INC_CHANNEL +#endif +}; + +uint16_t bleUserCfg_maxPduSize = MAX_PDU_SIZE; + +#ifdef OSAL_SNV_EXTFLASH +const extflashDrvTblPtr_t extflashDriverTable[] = { (uint32) ExtFlash_open, (uint32) ExtFlash_close, (uint32) ExtFlash_read, + (uint32) ExtFlash_write, (uint32) ExtFlash_erase }; +#endif // OSAL_SNV_EXTFLASH + +#ifndef CC23X0 +// Table for Driver can be found in icall_user_config.c +// if a driver is not to be used, then the pointer shoul dbe set to NULL, +// for this example, this is done in ble_user_config.h +const drvTblPtr_t driverTable = { + .rfDrvTbl = rfDriverTableBLE, + .eccDrvTbl = eccDriverTable, + .cryptoDrvTbl = cryptoDriverTableBLE, + .trngDrvTbl = trngDriverTable, + .rtosApiTbl = rtosApiTable, + .nvintfStructPtr = &nvintfFncStruct, +#ifdef OSAL_SNV_EXTFLASH + .extflashDrvTbl = extflashDriverTable, +#endif // OSAL_SNV_EXTFLASH +}; +#endif + +const boardConfig_t boardConfig = { +#ifndef CC23X0 + .rfFeModeBias = RF_FE_MODE_AND_BIAS, + .rfRegTbl = (regOverride_t *) pOverrides_bleCommon, + .rfRegTbl1M = (regOverride_t *) pOverrides_ble1Mbps, + .rfRegTbl2M = (regOverride_t *) pOverrides_ble2Mbps, + .rfRegTblCoded = (regOverride_t *) pOverrides_bleCoded, + .txPwrTbl = &appTxPwrTbl, +#if defined(CC13X2P) || defined(EM_CC1354P10_1_LP) +#if defined(CC13X2P_2_LAUNCHXL) + .txPwrBackoffTbl = &appTxPwrBackoffTbl, +#else + .txPwrBackoffTbl = NULL, +#endif // defined(CC13X2P_2_LAUNCHXL) +#if defined(EM_CC1354P10_1_LP) + .rfRegOverrideTxStdTblptr = NULL, + .rfRegOverrideTx20TblPtr = NULL, +#else + .rfRegOverrideTxStdTblptr = (regOverride_t *) pOverrides_bleTxStd, // Default PA + .rfRegOverrideTx20TblPtr = (regOverride_t *) pOverrides_bleTx20, // High power PA +#endif // EM_CC1354P10_1_LP +#endif // CC13X2P +#if defined(RTLS_CTE) + .rfRegOverrideCtePtr = (regOverride_t *) (pOverrides_bleCommon + BLE_STACK_OVERRIDES_OFFSET + CTE_OVERRIDES_OFFSET), + .cteAntennaPropPtr = &appCTEAntProp, +#else + .rfRegOverrideCtePtr = NULL, + .cteAntennaPropPtr = NULL, +#endif + .privOverrideOffset = BLE_STACK_OVERRIDES_OFFSET + PRIVACY_OVERRIDE_OFFSET, +#if defined(USE_COEX) + .coexUseCaseConfigPtr = &coexSysConfig, +#else + .coexUseCaseConfigPtr = NULL, +#endif +#endif +}; + +#else /* !(ICALL_JT) */ + +#ifndef CC23X0 +// RF Driver API Table +rfDrvTblPtr_t rfDriverTable[] = { + (uint32) RF_open, + (uint32) driverTable_fnSpinlock, // RF_close +#ifdef RF_SINGLEMODE + (uint32) RF_postCmd, +#else // !RF_SINGLEMODE + (uint32) driverTable_fnSpinlock, // RF_postCmd +#endif // RF_SINGLEMODE + (uint32) driverTable_fnSpinlock, // RF_pendCmd +#ifdef RF_SINGLEMODE + (uint32) RF_runCmd, +#else // !RF_SINGLEMODE + (uint32) driverTable_fnSpinlock, // RF_runCmd +#endif // RF_SINGLEMODE + (uint32) RF_cancelCmd, + (uint32) RF_flushCmd, + (uint32) driverTable_fnSpinlock, // RF_yield + (uint32) RF_Params_init, + (uint32) RF_runImmediateCmd, + (uint32) RF_runDirectCmd, + (uint32) RF_ratCompare(uint32) driverTable_fnSpinlock, // RF_ratCapture + (uint32) driverTable_fnSpinlock, // RF_ratDisableChannel + (uint32) RF_getCurrentTime, + (uint32) RF_getRssi, + (uint32) RF_getInfo, + (uint32) RF_getCmdOp, + (uint32) RF_control, + (uint32) driverTable_fnSpinlock, // RF_getTxPower + (uint32) RF_setTxPower, // RF_setTxPower + (uint32) driverTable_fnSpinlock, // RF_TxPowerTable_findPowerLevel + (uint32) driverTable_fnSpinlock, // RF_TxPowerTable_findValue +#ifndef RF_SINGLEMODE + (uint32) RF_scheduleCmd, + (uint32) RF_runScheduleCmd, + (uint32) driverTable_fnSpinlock // RF_requestAccess +#endif // !RF_SINGLEMODE +}; + +// ECC Driver API Table +eccDrvTblPtr_t eccDriverTable[] = { (uint32) ECDH_init, + (uint32) ECDH_Params_init, + (uint32) ECDH_open, + (uint32) ECDH_close, + (uint32) ECDH_OperationGeneratePublicKey_init, + (uint32) ECDH_OperationComputeSharedSecret_init, + (uint32) ECDH_generatePublicKey, + (uint32) ECDH_computeSharedSecret }; + +// Crypto Driver API Table +cryptoDrvTblPtr_t cryptoDriverTable[] = { (uint32) AESCCM_init, + (uint32) AESCCM_open, + (uint32) AESCCM_close, + (uint32) AESCCM_Params_init, + (uint32) AESCCM_Operation_init, + (uint32) AESCCM_oneStepEncrypt, + (uint32) AESCCM_oneStepDecrypt, + (uint32) AESECB_init, + (uint32) AESECB_open, + (uint32) AESECB_close, + (uint32) AESECB_Params_init, + (uint32) AESECB_Operation_init, + (uint32) AESECB_oneStepEncrypt, + (uint32) AESECB_oneStepDecrypt, + (uint32) CryptoKeyPlaintext_initKey, + (uint32) CryptoKeyPlaintext_initBlankKey }; + +trngDrvTblPtr_t trngDriverTable[] = { (uint32) TRNG_init, (uint32) TRNG_open, (uint32) TRNG_generateEntropy, (uint32) TRNG_close }; +#endif + +#endif /* ICALL_JT */ + +/******************************************************************************* + * @fn RegisterAssertCback + * + * @brief This routine registers the Application's assert handler. + * + * input parameters + * + * @param appAssertHandler - Application's assert handler. + * + * output parameters + * + * @param None. + * + * @return None. + */ +void RegisterAssertCback(assertCback_t appAssertHandler) +{ + appAssertCback = appAssertHandler; + +#ifdef EXT_HAL_ASSERT + // also set the Assert callback pointer used by halAssertHandlerExt + // Note: Normally, this pointer will be intialized by the stack, but in the + // event HAL_ASSERT is used by the Application, we initialize it + // directly here. + halAssertCback = appAssertHandler; +#endif // EXT_HAL_ASSERT + + return; +} + +/******************************************************************************* + * @fn driverTable_fnSpinLock + * + * @brief This routine is used to trap calls to unpopulated indexes of + * driver function pointer tables. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +void driverTable_fnSpinlock(void) +{ + volatile uint8 i = 1; + + while (i) + ; +} + +/******************************************************************************* + * @fn DefaultAssertCback + * + * @brief This is the Application default assert callback, in the event + * none is registered. + * + * input parameters + * + * @param assertCause - Assert cause as defined in hal_assert.h. + * @param assertSubcause - Optional assert subcause (see hal_assert.h). + * + * output parameters + * + * @param None. + * + * @return None. + */ +void DefaultAssertCback(uint8 assertCause, uint8 assertSubcause) +{ +#ifdef HAL_ASSERT_SPIN + driverTable_fnSpinlock(); +#endif // HAL_ASSERT_SPIN + + return; +} + +// Application Assert Callback Function Pointer +assertCback_t appAssertCback = DefaultAssertCback; + +/******************************************************************************* + */ diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 771af90..1c296ba 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -42,6 +42,7 @@ #include #include #include +#include "bget.h" //#include #include "bleAppTask.h" @@ -51,6 +52,11 @@ #include "ble_user_config.h" #include +#include +#include +#include "ti_dmm_application_policy.h" +#include + // BLE user defined configuration icall_userCfg_t user0Cfg = BLE_USER_CFG; #endif // USE_DEFAULT_USER_CFG @@ -67,10 +73,10 @@ static TaskHandle_t BLEAPPTaskHandle; #define BLEAPP_TASK_PRIORITY 4 #include -#define TOTAL_ICALL_HEAP_SIZE (0xf700) +#define TOTAL_ICALL_HEAP_SIZE (0xc700) -__attribute__((section(".heap"))) uint8_t GlobalHeapZoneBuffer[TOTAL_ICALL_HEAP_SIZE]; +__attribute__((section(".heap"))) uint8_t ucHeap[TOTAL_ICALL_HEAP_SIZE]; uint32_t heapSize = TOTAL_ICALL_HEAP_SIZE; void vApplicationStackOverflowHook(void) @@ -90,7 +96,7 @@ void vTaskCode(void *pvParameters) int main(void) { Board_init(); - bpool((void *) GlobalHeapZoneBuffer, TOTAL_ICALL_HEAP_SIZE); + bpool((void *) ucHeap, TOTAL_ICALL_HEAP_SIZE); GPIO_init(); @@ -107,7 +113,7 @@ int main(void) user0Cfg.appServiceInfo->timerTickPeriod = ICall_getTickPeriod(); user0Cfg.appServiceInfo->timerMaxMillisecond = ICall_getMaxMSecs(); -#if 1 +#if 0 /* Initialize ICall module */ ICall_init(); @@ -115,14 +121,34 @@ int main(void) ICall_createRemoteTasks(); #endif + + DMMPolicy_Params dmmPolicyParams; + DMMSch_Params dmmSchedulerParams; + + DMMPolicy_init(); + DMMPolicy_Params_init(&dmmPolicyParams); + dmmPolicyParams.numPolicyTableEntries = DMMPolicy_ApplicationPolicySize; + dmmPolicyParams.policyTable = DMMPolicy_ApplicationPolicyTable; + dmmPolicyParams.globalPriorityTable = globalPriorityTable_bleLthreadH; + DMMPolicy_open(&dmmPolicyParams); + + DMMSch_init(); + DMMSch_Params_init(&dmmSchedulerParams); + + memcpy(dmmSchedulerParams.stackRoles, DMMPolicy_ApplicationPolicyTable.stackRole, + sizeof(DMMPolicy_StackRole) * DMMPOLICY_NUM_STACKS); + dmmSchedulerParams.indexTable = DMMPolicy_ApplicationPolicyTable.indexTable; + DMMSch_open(&dmmSchedulerParams); + bleAppTask_init(); +#if 0 if (NULL == - xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, appStack, &appTaskBuffer)) + xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 4, appStack, &appTaskBuffer)) { while (1) ; } - - bleAppTask_init(); +#endif + vTaskStartScheduler(); // Should never get here. diff --git a/examples/apps/cli/icall_FreeRTOS.c b/examples/apps/cli/icall_FreeRTOS.c new file mode 100755 index 0000000..65c5c99 --- /dev/null +++ b/examples/apps/cli/icall_FreeRTOS.c @@ -0,0 +1,4119 @@ +/****************************************************************************** + @file icall_FreeRTOS.c + + @brief Indirect function Call dispatcher implementation on top of OS. + + This implementation uses heapmgr.h to implement a simple heap with low + memory overhead but large processing overhead.
+ The size of the heap is determined with HEAPMGR_SIZE macro, which can + be overridden with a compile option. + Note: The ICall layer (e.g. this file) is using TI internal implementation of POSIX. + For now, the ICall layer is not supports using outer POSIX on the application layer. + + Group: WCS, LPC, BTS + Target Device: cc13xx_cc26xx + + ****************************************************************************** + + Copyright (c) 2013-2023, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + + + *****************************************************************************/ + +#ifdef FREERTOS +#include +#include +#include "bget.h" +#endif + + +#ifdef FREERTOS +#include +#include +#include +#endif + + +#include +#include +#define Hwi_disable HwiP_disable +#define Hwi_restore HwiP_restore +#define Hwi_disableinterrupt HwiP_disableInterrupt +#define Hwi_enableinterrupt HwiP_enableInterrupt +#define Swi_restore SwiP_restore +#define Swi_disable SwiP_disable +#define BIOS_WAIT_FOREVER (~(0U)) +#define BIOS_NO_WAIT (0U) + +#include "osal.h" +#include "icall.h" +#include "icall_platform.h" +#include +#include + + + +#ifndef ICALL_FEATURE_SEPARATE_IMGINFO +#include +#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ + + +//typedef uint32_t * Task_Handle; + + +#ifndef Task_self +#define Task_self ICall_taskSelf +#endif + + +#ifndef ICALL_MAX_NUM_ENTITIES +/** + * Maximum number of entities that use ICall, including service entities + * and application entities. + * The value may be overridden by a compile option. + * Note that there are at least, + * Primitive service, Stack services along with potentially generic + * framework service for the stack thread. + */ +#define ICALL_MAX_NUM_ENTITIES 6 +#endif + +#ifndef ICALL_MAX_NUM_TASKS +/** + * Maximum number of threads which include entities. + * The value may be overridden by a compile option. + */ +#define ICALL_MAX_NUM_TASKS 2 +#endif + +/** + * @internal + * Service class value used to indicate an invalid (unused) entry + */ +#define ICALL_SERVICE_CLASS_INVALID_ENTRY 0x0000 + +/** + * @internal + * Service class value used to indicate an entry for an application entity + */ +#define ICALL_SERVICE_CLASS_APPLICATION ICALL_SERVICE_CLASS_MASK + +/** + * @internal + * Primitive service entity ID + */ +#define ICALL_PRIMITIVE_ENTITY_ID 0 + +/** + * @internal + * Accessor macro to get a header field (next) from a message pointer + */ +#define ICALL_MSG_NEXT(_p) (((ICall_MsgHdr *)(_p) - 1)->next) + +/** + * @internal + * Accessor macro to get a header field (dest_id) from a message pointer + */ +#define ICALL_MSG_DEST_ID(_p) (((ICall_MsgHdr *)(_p) - 1)->dest_id) + + +#ifndef ICALL_TIMER_TASK_STACK_SIZE +/** + * @internal + * Timer thread stack size + */ +#define ICALL_TIMER_TASK_STACK_SIZE (512) +#endif //ICALL_TIMER_TASK_STACK_SIZE + +/** + * @internal + * Creation of the synchronous object between application and service + */ + +#ifdef ICALL_EVENTS +#define ICALL_SYNC_HANDLE_CREATE() (Event_create(NULL, NULL)) +#else /* ICALL_EVENTS */ +#define ICALL_SYNC_HANDLE_CREATE() (Semaphore_create(0, NULL, NULL)) +#endif /* ICALL_EVENTS */ + + +/** + * @internal + * post the synchronous object between application and service + */ +#ifdef ICALL_EVENTS +#define ICALL_SYNC_HANDLE_POST(x) (Event_post(x, ICALL_MSG_EVENT_ID)) +#define ICALL_SYNC_HANDLE_POST_WM(x) (Event_post(x, ICALL_WAITMATCH_EVENT_ID)) +#else /* ICALL_EVENTS */ +#define ICALL_SYNC_HANDLE_POST(x) (Semaphore_post(x)) +#define ICALL_SYNC_HANDLE_POST_WM(x) (Semaphore_post(x)) /* Semaphore does not have event ID */ +#endif /* ICALL_EVENTS */ + + +/** + * @internal + * pend for the synchronous object between application and service + */ +#ifdef ICALL_EVENTS +#define ICALL_SYNC_HANDLE_PEND(x, t) (Event_pend(x, 0, ICALL_MSG_EVENT_ID ,t)) +#define ICALL_SYNC_HANDLE_PEND_WM(x, t) (Event_pend(x, 0, ICALL_WAITMATCH_EVENT_ID, t)) +#else /* ICALL_EVENTS */ +#define ICALL_SYNC_HANDLE_PEND(x, t) (Semaphore_pend(x, t)) +#define ICALL_SYNC_HANDLE_PEND_WM(x, t) (Semaphore_pend(x, t)) /* Semaphore does not have event ID */ +#endif /* ICALL_EVENTS */ + +/** + * @internal + * ticks + */ +#define CLOCK_TICKS_PERIOD (10) + + +/** + * @internal + * Data structure used to access critical section + * state variable. + * Without this data structure, C code will violate + * C89 or C99 strict aliasing rule. + */ +typedef union _icall_cs_state_union_t +{ + /** critical section variable as declared in the interface */ + ICall_CSState state; + /** @internal field used to access internal data */ + struct _icall_cs_state_aggr_t + { + /** field to store Swi_disable() return value */ + uint_least16_t swikey; + /** field to store Hwi_disable() return value */ + uint_least16_t hwikey; + } each; +} ICall_CSStateUnion; + +/** + * @internal Primitive service handler function type + */ +typedef ICall_Errno (*ICall_PrimSvcFunc)(ICall_FuncArgsHdr *); + +#ifdef ICALL_FEATURE_SEPARATE_IMGINFO +/* Image information shall be in separate module */ + +/** + * Array of entry function addresses of external images. + * + * Note that function address must be odd number for Thumb mode functions. + */ +extern const ICall_RemoteTaskEntry ICall_imgEntries[]; +/** + * Array of task priorities of external images. + * One task is created per image to start off the image entry function. + * Each element of this array correspond to the task priority of + * each entry function defined in @ref ICall_imgEntries. + */ +extern const int ICall_imgTaskPriorities[]; + +/** + * Array of task stack sizes of external images. + * One task is created per image to start off the image entry function. + * Each element of this array correspond to the task stack size of + * each entry function defined in @ref ICall_imgEntries. + */ +extern const size_t ICall_imgTaskStackSizes[]; + +/** + * Array of custom initialization parameters (pointers). + * Each initialization parameter (pointer) is passed to each corresponding + * image entry function defined in @ref ICall_imgEntries; + */ +extern const void *ICall_imgInitParams[]; + +/** + * Number of external images. + */ +extern const uint_least8_t ICall_numImages; + +#define icall_threadEntries ICall_imgEntries +#define ICall_threadPriorities ICall_imgTaskPriorities +#define ICall_threadStackSizes ICall_imgTaskStackSizes +#define ICall_getInitParams(_i) (ICall_imgInitParams[i]) +#define ICALL_REMOTE_THREAD_COUNT ICall_numImages +#else /* ICALL_FEATURE_SEPARATE_IMGINFO */ +/** + * @internal + * Array of entry function of external images. + */ +static const ICall_RemoteTaskEntry icall_threadEntries[] = ICALL_ADDR_MAPS; + +/** @internal external image count */ +#define ICALL_REMOTE_THREAD_COUNT \ + (sizeof(icall_threadEntries)/sizeof(icall_threadEntries[0])) + + +/** @internal thread priorities to be assigned to each remote thread */ +static const int ICall_threadPriorities[] = ICALL_TASK_PRIORITIES; + + +/** @internal thread stack max depth for each remote thread */ +static const size_t ICall_threadStackSizes[] = ICALL_TASK_STACK_SIZES; + +/** @internal initialization parameter (pointer) for each remote thread */ +#ifdef ICALL_CUSTOM_INIT_PARAMS +static const void *ICall_initParams[] = ICALL_CUSTOM_INIT_PARAMS; +#define ICall_getInitParams(_i) (ICall_initParams[i]) +#else /* ICALL_CUSTOM_INIT_PARAMS */ +#define ICall_getInitParams(_i) NULL +#endif /* ICALL_CUSTOM_INIT_PARAMS */ + +#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ + +/** @internal message queue */ +typedef void *ICall_MsgQueue; + +/** @internal data structure about a task using ICall module */ +typedef struct _icall_task_entry_t +{ + TaskHandle_t task; + ICall_SyncHandle syncHandle; + ICall_MsgQueue queue; +} ICall_TaskEntry; + +/** @internal data structure about an entity using ICall module */ +typedef struct _icall_entity_entry_t +{ + ICall_ServiceEnum service; + ICall_TaskEntry *task; + ICall_ServiceFunc fn; +} ICall_entityEntry; + +/** @internal storage to track all tasks using ICall module */ +static ICall_TaskEntry ICall_tasks[ICALL_MAX_NUM_TASKS]; + +/** @internal storage to track all entities using ICall module */ +static ICall_entityEntry ICall_entities[ICALL_MAX_NUM_ENTITIES]; + +#ifndef FREERTOS +extern mqd_t g_EventsQueueID; +#endif +/** + * @internal + * Wakeup schedule data structure definition + */ + +#ifdef FREERTOS +void ICALL_Task_restore(UBaseType_t *OriginalParam); +void ICALL_Task_disable(UBaseType_t *OriginalParam); +#else + +void ICALL_Task_restore(struct sched_param *OriginalParam); +void ICALL_Task_disable(struct sched_param *OriginalParam); +#endif +typedef struct _icall_schedule_t +{ + ClockP_Handle clockP; + ICall_TimerCback cback; + void *arg; +} ICall_ScheduleEntry; + + +/* For now critical sections completely disable hardware interrupts + * because they are used from ISRs in MAC layer implementation. + * If MAC layer implementation changes, critical section + * implementation may change to reduce overall interrupt latency. + */ +/* Enter critical section implementation. See header file for comment. */ +ICall_CSState ICall_enterCSImpl(void) +{ + + ICall_CSStateUnion cu; + cu.each.swikey = (uint_least16_t) Swi_disable(); + cu.each.hwikey = (uint_least16_t) Hwi_disable(); + return cu.state; +} +#ifdef FREERTOS +TaskHandle_t ICall_taskSelf(void) +#else +Task_Handle ICall_taskSelf(void) +#endif +{ + + TaskHandle_t task = NULL; +#ifdef FREERTOS + task = (TaskHandle_t) xTaskGetCurrentTaskHandle(); +#else + task = ; +#endif // FREERTOS + return (task); +} + +/* See header file for comment */ +ICall_EnterCS ICall_enterCriticalSection = ICall_enterCSImpl; + +/* leave critical section implementation. See header file for comment */ +void ICall_leaveCSImpl(ICall_CSState key) +{ + ICall_CSStateUnion *cu = (ICall_CSStateUnion *) &key; + Hwi_restore((uint32_t) cu->each.hwikey); + Swi_restore((uint32_t) cu->each.swikey); +} + +/* See header file for comment */ +ICall_LeaveCS ICall_leaveCriticalSection = ICall_leaveCSImpl; + +/* Implementing a simple heap using heapmgr.h template. + * This simple heap depends on critical section implementation + * and hence the template is used after critical section definition. */ +void *ICall_heapMalloc(uint32_t size); +void *ICall_heapRealloc(void *blk, uint32_t size); +void ICall_heapFree(void *blk); + +#define HEAPMGR_INIT ICall_heapInit +#define HEAPMGR_MALLOC ICall_heapMalloc +#define HEAPMGR_FREE ICall_heapFree +#define HEAPMGR_REALLOC ICall_heapRealloc +#define HEAPMGR_GETSTATS ICall_heapGetStats +#define HEAPMGR_MALLOC_LIMITED ICall_heapMallocLimited + +void ICall_heapMgrGetMetrics(uint32_t *pBlkMax, + uint32_t *pBlkCnt, + uint32_t *pBlkFree, + uint32_t *pMemAlo, + uint32_t *pMemMax, + uint32_t *pMemUB); +#ifdef HEAPMGR_METRICS +#define HEAPMGR_GETMETRICS ICall_heapMgrGetMetrics +#endif + +#define HEAPMGR_LOCK() \ + do { ICall_heapCSState = ICall_enterCSImpl(); } while (0) +#define HEAPMGR_UNLOCK() \ + do { ICall_leaveCSImpl(ICall_heapCSState); } while (0) +#define HEAPMGR_IMPL_INIT() +/* Note that a static variable can be used to contain critical section + * state since heapmgr.h template ensures that there is no nested + * lock call. */ + +#if defined(HEAPMGR_CONFIG) && ((HEAPMGR_CONFIG == 0) || (HEAPMGR_CONFIG == 0x80)) +#include +#elif defined(HEAPMGR_CONFIG) && ( (HEAPMGR_CONFIG == 1) || (HEAPMGR_CONFIG == 0x81)) +#include +#elif defined(HEAPMGR_CONFIG) && ( (HEAPMGR_CONFIG == 2) || (HEAPMGR_CONFIG == 0x82)) +#include +#elif defined(FREERTOS) +#include "TI_heap_wrapper.h" +#else +static ICall_CSState ICall_heapCSState; +#include +#endif + +/** + * @internal Searches for a task entry within @ref ICall_tasks. + * @param taskhandle OS task handle + * @return Pointer to task entry when found, or NULL. + */ +static ICall_TaskEntry *ICall_searchTask(TaskHandle_t taskhandle) +{ + size_t i; + ICall_CSState key; + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) + { + if (!ICall_tasks[i].task) + { + /* Empty slot */ + break; + } + if ((TaskHandle_t)taskhandle == (TaskHandle_t)ICall_tasks[i].task) + { + ICall_leaveCSImpl(key); + return &ICall_tasks[i]; + } + } + ICall_leaveCSImpl(key); + return NULL; +} + +/** + * @internal Searches for a task entry within @ref ICall_tasks or + * build an entry if the entry table is empty. + * @param taskhandle OS task handle + * @return Pointer to task entry when found, or NULL. + */ + +static ICall_TaskEntry *ICall_newTask(TaskHandle_t taskhandle) +{ + size_t i; + ICall_CSState key; + + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) + { + if (!ICall_tasks[i].task) + { + /* Empty slot */ + ICall_TaskEntry *taskentry = &ICall_tasks[i]; + taskentry->task = taskhandle; + taskentry->queue = NULL; + +#ifdef FREERTOS + taskentry->syncHandle = xQueueCreate(20, sizeof(uint32_t)); +#endif + + if (taskentry->syncHandle == 0) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + } + + ICall_leaveCSImpl(key); + return taskentry; + } + if (taskhandle == (TaskHandle_t)ICall_tasks[i].task) + { + ICall_leaveCSImpl(key); + return &ICall_tasks[i]; + } + } + ICall_leaveCSImpl(key); + return NULL; +} + +/* See header file for comments. */ +ICall_EntityID ICall_searchServiceEntity(ICall_ServiceEnum service) +{ + size_t i; + ICall_CSState key; + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Empty slot */ + break; + } + if (service == ICall_entities[i].service) + { + ICall_leaveCSImpl(key); + return (ICall_EntityID) i; + } + } + ICall_leaveCSImpl(key); + return ICALL_INVALID_ENTITY_ID; +} + +/** + * @internal Searches for a service entity entry. + * @param service service id + * @return Pointer to entity entry of the service or + * NULL when none found. + */ +static ICall_entityEntry * +ICall_searchService(ICall_ServiceEnum service) +{ + ICall_EntityID entity = ICall_searchServiceEntity(service); + if (entity == ICALL_INVALID_ENTITY_ID) + { + return NULL; + } + return &ICall_entities[entity]; +} + +/* Dispatcher implementation. See ICall_dispatcher declaration + * for comment. */ +static ICall_Errno ICall_dispatch(ICall_FuncArgsHdr *args) +{ + ICall_entityEntry *entity; + + entity = ICall_searchService(args->service); + if (!entity) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + if (!entity->fn) + { + return ICALL_ERRNO_INVALID_FUNCTION; + } + + return entity->fn(args); +} + +/* See header file for comments */ +ICall_Dispatcher ICall_dispatcher = ICall_dispatch; + +/* Static instance of ICall_RemoteTaskArg to pass to + * remote task entry function. + * See header file for comments */ +static const ICall_RemoteTaskArg ICall_taskEntryFuncs = +{ + ICall_dispatch, + ICall_enterCSImpl, + ICall_leaveCSImpl +}; + +/** + * @internal Thread entry function wrapper that complies with + * OS. + * @param arg0 actual entry function + * @param arg1 ignored + */ +TaskHandle_t RemoteTask = NULL; + +//pthread_t RemoteTask; + +struct argsForPosixTaskStart +{ + void *arg0; + void *arg1; +}; +struct argsForPosixTaskStart POSIX_args; + +typedef void (*TaskFunction_t)( void * ); + +static void ICall_taskEntry(void *arg) + +{ + void * arg0 = ((struct argsForPosixTaskStart *)(arg))->arg0; + void * arg1 = ((struct argsForPosixTaskStart *)(arg))->arg1; + + ICall_CSState key; + key = ICall_enterCSImpl(); + if (ICall_newTask(ICall_taskSelf()) == NULL) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + } + ICall_leaveCSImpl(key); + + /* Attempt to yield prior to running task */ + taskYIELD(); + + ICall_RemoteTaskEntry entryfn = (ICall_RemoteTaskEntry) arg0; + + entryfn(&ICall_taskEntryFuncs, (void *) arg1); + + //return NULL; +} + +#ifndef ICALL_JT +/* forward reference */ +static void ICall_initPrim(void); +#endif /* ICALL_JT */ + +/* See header file for comments. */ +void ICall_init(void) +{ + size_t i; + + for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) + { + ICall_tasks[i].task = NULL; + ICall_tasks[i].queue = NULL; + } + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + ICall_entities[i].service = ICALL_SERVICE_CLASS_INVALID_ENTRY; + } + +#ifndef ICALL_JT + /* Initialize primitive service */ + ICall_initPrim(); +#else + /* Initialize heap */ +#ifndef FREERTOS + ICall_heapInit(); +#endif //FREERTOS +#endif +} + + +/* See header file for comments */ +void ICall_createRemoteTasksAtRuntime(ICall_RemoteTask_t *remoteTaskTable, uint8_t nbElems) +{ + size_t i; + /* ICALL_Task_disable is a cheap locking mechanism to lock tasks + * which may attempt to access the service call dispatcher + * till all services are registered. + */ + UBaseType_t OriginalParam; + ICALL_Task_disable(&OriginalParam); + for (i = 0; i < nbElems; i++) + { +#ifdef FREERTOS + BaseType_t xReturned; + + /* Pass the args via external sturct (POSIX use only single arg) */ + POSIX_args.arg0 = (void*)remoteTaskTable[i].startupEntry; + POSIX_args.arg1 = (void*)remoteTaskTable[i].ICall_imgInitParam; + + xReturned = xTaskCreate( + ICall_taskEntry, /* Function that implements the task. */ + "x", /* Text name for the task. */ + remoteTaskTable[i].imgTaskStackSize / sizeof(uint32_t), /* Stack size in words, not bytes. */ + ( void * ) &POSIX_args, /* Parameter passed into the task. */ + remoteTaskTable[i].imgTaskPriority, /* Priority at which the task is created. */ + &RemoteTask ); /* Used to pass out the created task's handle. */ + + if(xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) + { + /* Creation of FreeRTOS task failed */ + while(1); + } + } + ICALL_Task_restore(&OriginalParam); +#endif +} + +/* See header file for comments */ +void ICall_createRemoteTasks(void) +{ + size_t i; + ICall_RemoteTask_t remoteTaskTable[ICALL_REMOTE_THREAD_COUNT]; + + for (i = 0; i < ICALL_REMOTE_THREAD_COUNT; i++) + { + remoteTaskTable[i].imgTaskPriority = ICall_threadPriorities[i]; + remoteTaskTable[i].imgTaskStackSize = ICall_threadStackSizes[i]; + remoteTaskTable[i].startupEntry = icall_threadEntries[i]; + remoteTaskTable[i].ICall_imgInitParam = (void *) ICall_getInitParams(i); + } + ICall_createRemoteTasksAtRuntime(remoteTaskTable, ICALL_REMOTE_THREAD_COUNT); +} + + + +#ifdef FREERTOS +void ICALL_Task_disable(UBaseType_t *OriginalParam) + +#else +void ICALL_Task_disable(struct sched_param *OriginalParam) +#endif +{ + +#ifdef FREERTOS + TaskStatus_t pxTaskStatus; + vTaskGetInfo(ICall_taskSelf(), &pxTaskStatus, pdFALSE, eInvalid); + *OriginalParam = pxTaskStatus.uxCurrentPriority; + + vTaskPrioritySet(ICall_taskSelf(), configMAX_PRIORITIES - 1); +#endif + + +} +#ifdef FREERTOS +void ICALL_Task_restore(UBaseType_t *OriginalParam) +#else +void ICALL_Task_restore(struct sched_param *OriginalParam) +#endif +{ + +#ifdef FREERTOS + vTaskPrioritySet(ICall_taskSelf(), *OriginalParam); + +#else + pthread_t pthreadID = pthread_self(); + pthread_setschedparam(pthreadID, 0, OriginalParam); +#endif +} + + +/* See header file for comments */ +ICall_TaskHandle ICall_getRemoteTaskHandle(uint8 index) +{ + TaskHandle_t *task = NULL; + + + UBaseType_t OriginalParam; + ICALL_Task_disable(&OriginalParam); + + if (index < ICALL_MAX_NUM_TASKS) + { + task = &ICall_tasks[index].task; + } + + ICALL_Task_restore(&OriginalParam); + + return((ICall_TaskHandle)task); +} + +/* Primitive service implementation follows */ + +#ifndef ICALL_JT +/** + * @internal Enrolls a service + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when service id is already + * registered by another entity.
+ * @ref ICALL_ERRNO_NO_RESOURCE when maximum number of services + * are already registered. + */ +static ICall_Errno ICall_primEnroll(ICall_EnrollServiceArgs *args) +{ + size_t i; + ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + /* Note that certain service does not handle a message + * and hence, taskentry might be NULL. + */ + if (taskentry == NULL) + { + return ICALL_ERRNO_INVALID_PARAMETER; + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = args->service; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = args->fn; + args->entity = (ICall_EntityID) i; + args->msgSyncHdl = taskentry->syncHandle; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + else if (args->service == ICall_entities[i].service) + { + /* Duplicate service enrollment */ + ICall_leaveCSImpl(key); + return ICALL_ERRNO_INVALID_PARAMETER; + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return ICALL_ERRNO_NO_RESOURCE; + +} + +/** + * @internal Registers an application + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + */ +static ICall_Errno ICall_primRegisterApp(ICall_RegisterAppArgs *args) +{ + size_t i; + ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + if (!taskentry) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = ICALL_SERVICE_CLASS_APPLICATION; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = NULL; + args->entity = (ICall_EntityID) i; + args->msgSyncHdl = taskentry->syncHandle; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return ICALL_ERRNO_NO_RESOURCE; +} + +/** + * @internal Allocates memory block for a message. + * @param args arguments + */ +static ICall_Errno ICall_primAllocMsg(ICall_AllocArgs *args) +{ + ICall_MsgHdr *hdr = + (ICall_MsgHdr *) ICall_heapMalloc(sizeof(ICall_MsgHdr) + args->size); + + if (!hdr) + { + return ICALL_ERRNO_NO_RESOURCE; + } + hdr->len = args->size; + hdr->next = NULL; + hdr->dest_id = ICALL_UNDEF_DEST_ID; + args->ptr = (void *) (hdr + 1); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Frees the memory block allocated for a message. + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS + */ +static ICall_Errno ICall_primFreeMsg(ICall_FreeArgs *args) +{ + ICall_MsgHdr *hdr = (ICall_MsgHdr *) args->ptr - 1; + ICall_heapFree(hdr); + return ICALL_ERRNO_SUCCESS; +} + +/** + * Allocates a memory block. + * Note that this function is for use by ICall implementation. + * + * @param size size in bytes + * @return pointer to the allocated memory block or NULL + */ +void *ICall_mallocImpl(uint_fast16_t size) +{ + return ICall_heapMalloc(size); +} + +/** + * Frees a memory block. + * Note that this function is for use by ICall implementation. + * + * @param ptr pointer to the memory block + */ +void ICall_freeImpl(void *ptr) +{ + ICall_heapFree(ptr); +} + +/** + * @internal Allocates a memory block + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when memory block cannot + * be allocated. + */ +static ICall_Errno ICall_primMalloc(ICall_AllocArgs *args) +{ + args->ptr = ICall_heapMalloc(args->size); + if (args->ptr == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Frees a memory block + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS + */ +static ICall_Errno ICall_primFree(ICall_FreeArgs *args) +{ + ICall_heapFree(args->ptr); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +/** + * @internal Queues a message to a message queue. + * @param q_ptr message queue + * @param msg_ptr message pointer + */ +static void ICall_msgEnqueue( ICall_MsgQueue *q_ptr, void *msg_ptr ) +{ + void *list; + ICall_CSState key; + + // Hold off interrupts + key = ICall_enterCSImpl(); + + ICALL_MSG_NEXT( msg_ptr ) = NULL; + // If first message in queue + if ( *q_ptr == NULL ) + { + *q_ptr = msg_ptr; + } + else + { + // Find end of queue + for ( list = *q_ptr; ICALL_MSG_NEXT( list ) != NULL; + list = ICALL_MSG_NEXT( list ) ); + + // Add message to end of queue + ICALL_MSG_NEXT( list ) = msg_ptr; + } + + // Re-enable interrupts + ICall_leaveCSImpl(key); +} + +/** + * @internal Dequeues a message from a message queue + * @param q_ptr message queue pointer + * @return Dequeued message pointer or NULL if none. + */ +static void *ICall_msgDequeue( ICall_MsgQueue *q_ptr ) +{ + void *msg_ptr = NULL; + ICall_CSState key; + + // Hold off interrupts + key = ICall_enterCSImpl(); + + if ( *q_ptr != NULL ) + { + // Dequeue message + msg_ptr = *q_ptr; + *q_ptr = ICALL_MSG_NEXT( msg_ptr ); + ICALL_MSG_NEXT( msg_ptr ) = NULL; + ICALL_MSG_DEST_ID( msg_ptr ) = ICALL_UNDEF_DEST_ID; + } + + // Re-enable interrupts + ICall_leaveCSImpl(key); + + return msg_ptr; +} + +/** + * @internal Prepends a list of messages to a message queue + * @param q_ptr message queue pointer + * @param head message list to prepend + */ +static void ICall_msgPrepend( ICall_MsgQueue *q_ptr, ICall_MsgQueue head ) +{ + void *msg_ptr = NULL; + ICall_CSState key; + + // Hold off interrupts + key = ICall_enterCSImpl(); + + if ( head != NULL ) + { + /* Find the end of the queue */ + msg_ptr = head; + while (ICALL_MSG_NEXT( msg_ptr ) != NULL) + { + msg_ptr = ICALL_MSG_NEXT( msg_ptr ); + } + ICALL_MSG_NEXT(msg_ptr) = *q_ptr; + *q_ptr = head; + } + + // Re-enable interrupts + ICall_leaveCSImpl(key); +} + +#ifndef ICALL_JT +/** + * @internal Sends a message to an entity. + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when either src + * or dest is not a valid entity id or when + * dest is an entity id of an entity that does + * not receive a message + * (e.g., ICall primitive service entity). + */ +static ICall_Errno ICall_primSend(ICall_SendArgs *args) +{ + ICall_CSState key; + ICall_MsgHdr *hdr = (ICall_MsgHdr *) args->msg - 1; + + if (args->dest.entityId >= ICALL_MAX_NUM_ENTITIES || + args->src >= ICALL_MAX_NUM_ENTITIES) + { + return ICALL_ERRNO_INVALID_PARAMETER; + } + key = ICall_enterCSImpl(); + if (!ICall_entities[args->dest.entityId].task) + { + ICall_leaveCSImpl(key); + return ICALL_ERRNO_INVALID_PARAMETER; + } + + ICall_leaveCSImpl(key); + /* Note that once the entry is valid, + * the value does not change and hence it is OK + * to leave the critical section. + */ + + hdr->srcentity = args->src; + hdr->dstentity = args->dest.entityId; + hdr->format = args->format; + ICall_msgEnqueue(&ICall_entities[args->dest.entityId].task->queue, args->msg); + ICALL_SYNC_HANDLE_POST(ICall_entities[args->dest.entityId].task->syncHandle); + + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Retrieves a message, queued to receive queue of the calling thread. + * + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when a message was successfully + * retrieved.
+ * @ref ICALL_ERRNO_NOMSG when no message was queued to + * the receive queue at the moment.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread + * does not have a received queue associated with it. + * This happens when neither ICall_enrollService() nor + * ICall_registerApp() was ever called from the calling + * thread. + */ +static ICall_Errno ICall_primFetchMsg(ICall_FetchMsgArgs *args) +{ + Task_Handle taskhandle = Task_self(); + ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); + ICall_MsgHdr *hdr; + + if (!taskentry) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + /* Successful */ + args->msg = ICall_msgDequeue(&taskentry->queue); + + if (args->msg == NULL) + { + return ICALL_ERRNO_NOMSG; + } + hdr = (ICall_MsgHdr *) args->msg - 1; + args->src.entityId = hdr->srcentity; + args->dest = hdr->dstentity; + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + + +/** + * @internal + * Transforms and entityId into a serviceId. + * @param entityId entity id + * @param servId pointer to a variable to store + * the resultant service id + * @return @ICALL_ERRNO_SUCCESS if the transformation was successful. + * @ICALL_ERRNO_INVALID_SERVICE if no matching service + * is found for the entity id. + */ +static ICall_Errno ICall_primEntityId2ServiceId(ICall_EntityID entityId, + ICall_ServiceEnum *servId) +{ + if (entityId >= ICALL_MAX_NUM_ENTITIES || + ICall_entities[entityId].service == + ICALL_SERVICE_CLASS_INVALID_ENTRY || + ICall_entities[entityId].service == + ICALL_SERVICE_CLASS_APPLICATION) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + *servId = ICall_entities[entityId].service; + return ICALL_ERRNO_SUCCESS; +} + +#ifndef ICALL_JT +/** + * @internal Transforms and entityId into a serviceId. + * @param args arguments + * @return return values corresponding to those of ICall_entityId2ServiceId() + */ +static ICall_Errno ICall_primE2S(ICall_EntityId2ServiceIdArgs *args) +{ + return ICall_primEntityId2ServiceId(args->entityId, &args->servId); +} + +/** + * @internal Sends a message to a registered server. + * @param args arguments corresponding to those of ICall_sendServiceMsg(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_SERVICE when the 'dest' + * is unregistered service.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the 'src' + * is not a valid entity id or when 'dest' is + * is a service that does not receive a message + * (such as ICall primitive service). + */ +static ICall_Errno ICall_primSendServiceMsg(ICall_SendArgs *args) +{ + ICall_EntityID dstentity = ICall_searchServiceEntity(args->dest.servId); + + if (dstentity == ICALL_INVALID_ENTITY_ID) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + args->dest.entityId = dstentity; + return ICall_primSend(args); +} + +/** + * @internal Retrieves a message received at the message queue + * associated with the calling thread. + * + * Note that this function should be used by an application + * which does not expect any message from non-server entity. + * + * @param args arguments corresponding to those of ICall_fetchServiceMsg() + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and a message was retrieved.
+ * @ref ICALL_ERRNO_NOMSG when there is no queued message + * at the moment.
+ * @ref ICALL_ERRNO_CORRUPT_MSG when a message queued in + * front of the thread's receive queue was not sent by + * a server. Note that in this case, the message is + * not retrieved but thrown away.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is + * called from a thread which has not registered + * an entity, either through ICall_enrollService() + * or through ICall_registerApp(). + */ +static ICall_Errno ICall_primFetchServiceMsg(ICall_FetchMsgArgs *args) +{ + ICall_ServiceEnum servId; + ICall_Errno errno = ICall_primFetchMsg(args); + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(args->src.entityId, &servId) != + ICALL_ERRNO_SUCCESS) + { + /* Source entity ID cannot be translated to service id */ + ICall_freeMsg(args->msg); + return ICALL_ERRNO_CORRUPT_MSG; + } + args->src.servId = servId; + +#ifdef ICALL_EVENTS + /* + * Because Events are binary flags, the task's queue must be checked for + * any remaining messages. If there are the ICall event flag must be + * re-posted due to it being cleared on the last pend. + */ + ICall_primRepostSync(); +#endif //ICALL_EVENTS + } + return errno; +} +#endif /* ICALL_JT */ +/** + * @internal + * Converts milliseconds to number of ticks. + * @param msecs milliseconds + * @param ticks pointer to a variable to store the resultant number of ticks + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when conversion failed + * as the input goes out of range for the output data type. + */ +static ICall_Errno ICall_msecs2Ticks(uint_fast32_t msecs, uint32_t *ticks) +{ + uint_fast64_t intermediate = msecs; + + /*convert to microSec*/ + intermediate *= 1000; + /*divide with the ticks perios*/ + intermediate /= ICall_getTickPeriod(); + if (intermediate >= ((uint_fast64_t) 1 << (sizeof(uint32_t)*8 - 1))) + { + /* Out of range. + * Note that we use only half of the range so that client can + * determine whether the time has passed or time has yet to come. + */ + return ICALL_ERRNO_INVALID_PARAMETER; + } + *ticks = (uint32_t) intermediate; + return ICALL_ERRNO_SUCCESS; +} + +#ifndef ICALL_JT +/** + * @internal + * Waits for a signal to the synchronization object associated with the calling + * thread. + * + * Note that the synchronization object associated with a thread is signaled + * when a message is queued to the message receive queue of the thread + * or when ICall_signal() function is called onto the synchronization object. + * + * @param args arguments corresponding to those of ICall_wait(). + * @return @ref ICALL_ERRNO_SUCCESS when the synchronization object is + * signaled.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the synchronization object being signaled.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the milliseconds + * is greater than the value of ICall_getMaxMSecs(). + */ +static ICall_Errno ICall_primWait(ICall_WaitArgs *args) +{ + Task_Handle taskhandle = Task_self(); + ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); + uint32_t timeout; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || + threadtype == BIOS_ThreadType_Swi) + { + /* Blocking call is not allowed from Hwi or Swi. + * Note that though theoretically, Swi or lower priority Hwi may block + * on an event to be generated by a higher priority Hwi, it is not a + * safe practice and hence it is disabled. + */ + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + if (!taskentry) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + /* Successful */ + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + + if (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) + { + return ICALL_ERRNO_SUCCESS; + } + + return ICALL_ERRNO_TIMEOUT; +} + +/** + * @internal signals a synchronziation object. + * @param args arguments corresponding to those of ICall_signal() + * @return return value corresponding to those of ICall_signal() + */ +static ICall_Errno ICall_primSignal(ICall_SignalArgs *args) +{ + ICALL_SYNC_HANDLE_POST(args->syncHandle); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal aborts program + * @param args arguments corresponding to those of ICall_abort() + * @return return value corresponding to those of ICall_abort() + */ +static ICall_Errno ICall_primAbort(ICall_FuncArgsHdr *args) +{ + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Enables an interrupt. + * @param args arguments corresponding to those of ICall_enableint() + * @return return values corresponding to those of ICall_enableint() + */ +static ICall_Errno ICall_primEnableint(ICall_intNumArgs *args) +{ + Hwi_enableinterrupt(args->intnum); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Disables an interrupt. + * @param args arguments corresponding to those of ICall_disableint() + * @return return values corresponding to those of ICall_disableint() + */ +static ICall_Errno ICall_primDisableint(ICall_intNumArgs *args) +{ + Hwi_disableinterrupt(args->intnum); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Enables master interrupt and context switching. + * @param args arguments corresponding to those of ICall_enableMint() + * @return return values corresponding to those of ICall_enableMint() + */ +static ICall_Errno ICall_primEnableMint(ICall_FuncArgsHdr *args) +{ + Hwi_enable(); + Swi_enable(); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Disables master interrupt and context switching. + * @param args arguments corresponding to those of ICall_disableMint() + * @return return values corresponding to those of ICall_disableMint() + */ +static ICall_Errno ICall_primDisableMint(ICall_FuncArgsHdr *args) +{ + Swi_disable(); + Hwi_disable(); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal registers an interrupt service routine + * @param args arguments corresponding to those of ICall_registerISR() + * @return return values corresponding to those of ICall_registerISR() + */ +static ICall_Errno ICall_primRegisterISR(ICall_RegisterISRArgs *args) +{ + Hwi_Params hwiParams; + + Hwi_Params_init(&hwiParams); + hwiParams.priority = 0xE0; // default all registered ints to lowest priority + + if (Hwi_create( args->intnum, + (void (*)((void *)))args->isrfunc, + &hwiParams, + NULL) == NULL) + { + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal registers an interrupt service routine + * @param args arguments corresponding to those of ICall_registerISR_Ext() + * @return return values corresponding to those of ICall_registerISR_ext() + */ +static ICall_Errno ICall_primRegisterISR_Ext(ICall_RegisterISRArgs_Ext *args) +{ + Hwi_Params hwiParams; + + Hwi_Params_init(&hwiParams); + hwiParams.priority = args->intPriority; + + if (Hwi_create( args->intnum, + (void (*)((void *)))args->isrfunc, + &hwiParams, + NULL) == NULL) + { + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Gets tick counter value + * @param args arguments corresponding to those of ICall_getTicks() + * @return return values corresponding to those of ICall_getTicks() + */ +static ICall_Errno ICall_primGetTicks(ICall_Getuint32_tArgs *args) +{ + args->value = Clock_getTicks(); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +/** + * @internal + * Clock event handler function. + * This function is used to implement the wakeup scheduler. + * + * @param arg an @ref ICall_ScheduleEntry + */ + +static void ICall_clockFunc(uintptr_t arg) +{ + ICall_ScheduleEntry *entry = (ICall_ScheduleEntry *) arg; + + entry->cback(entry->arg); +} + +#ifndef ICALL_JT +/** + * @internal + * Set up or restart a timer. + * + * @param args arguments corresponding to those of ICall_setTimer() + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER if timer designated by the + * timer ID value was not set up before. + * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + */ +static ICall_Errno ICall_primSetTimer(ICall_SetTimerArgs *args) +{ + ICall_ScheduleEntry *entry; + + if (args->timerid == ICALL_INVALID_TIMER_ID) + { + Clock_Params params; + + /* Create a new timer */ + entry = ICall_heapMalloc(sizeof(ICall_ScheduleEntry)); + if (entry == NULL) + { + /* allocation failed */ + return ICALL_ERRNO_NO_RESOURCE; + } + Clock_Params_init(¶ms); + params.startFlag = FALSE; + params.period = 0; + params.arg = ((void *)) entry; + entry->clock = Clock_create(ICall_clockFunc, + args->timeout, + ¶ms, NULL); + if (!entry->clock) + { + /* abort */ + ICall_abort(); + ICall_heapFree(entry); + return ICALL_ERRNO_NO_RESOURCE; + } + entry->cback = args->cback; + entry->arg = args->arg; + args->timerid = (ICall_TimerID) entry; + } + else + { + ICall_CSState key; + + entry = (ICall_ScheduleEntry *) args->timerid; + + /* Critical section is entered to disable interrupts that might cause call + * to callback due to race condition */ + key = ICall_enterCriticalSection(); + Clock_stop(entry->clock); + entry->arg = args->arg; + ICall_leaveCriticalSection(key); + } + + Clock_setTimeout(entry->clock, args->timeout); + Clock_start(entry->clock); + + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal + * Set up or restart a timer. + * + * @param args arguments corresponding to those of ICall_setTimerMSecs() + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when msecs is greater than + * maximum value supported. + * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + */ +static ICall_Errno ICall_primSetTimerMSecs(ICall_SetTimerArgs *args) +{ + uint32_t ticks; + /* Convert to tick time */ + ICall_Errno errno = ICall_msecs2Ticks(args->timeout, &ticks); + + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + args->timeout = ticks; + return ICall_primSetTimer(args); +} + +/** + * @internal + * Stops a timer. + * + * @param args arguments corresponding to those of ICall_stopTimer() + * + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER + * if id is @ref ICALL_INVALID_TIMER_ID. + */ +static ICall_Errno ICall_primStopTimer(ICall_StopTimerArgs *args) +{ + ICall_ScheduleEntry *entry = (ICall_ScheduleEntry *) args->timerid; + + if (args->timerid == ICALL_INVALID_TIMER_ID) + { + return ICALL_ERRNO_INVALID_PARAMETER; + } + + Clock_stop(entry->clock); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Gets tick period + * @param args arguments corresponding to those of ICall_getTickPeriod() + * @return return values corresponding to those of ICall_getTickPeriod() + */ +static ICall_Errno ICall_primGetTickPeriod(ICall_Getuint32_tArgs *args) +{ + args->value = Clock_tickPeriod; + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Gets maximum period supported + * @param args arguments corresponding to those of ICall_getMaxMSecs() + * @return return values corresponding to those of ICall_getMaxMSecs() + */ +static ICall_Errno ICall_primGetMaxMSecs(ICall_Getuint32_tArgs *args) +{ + uint_fast64_t tmp = ((uint_fast64_t) 0x7ffffffful) * Clock_tickPeriod; + tmp /= 1000; + if (tmp >= 0x80000000ul) + { + tmp = 0x7ffffffful; + } + args->value = (uint_least32_t) tmp; + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal + * Waits for a message that matches comparison + * + * @param args arguments corresponding to those of ICall_waitMatch(). + * @return @ref ICALL_ERRNO_SUCCESS when the synchronization object is + * signaled.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the milliseconds + * is greater than the value of ICall_getMaxMSecs(). + */ +static ICall_Errno ICall_primWaitMatch(ICall_WaitMatchArgs *args) +{ + Task_Handle taskhandle = Task_self(); + ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); + ICall_MsgQueue prependQueue = NULL; +#ifndef ICALL_EVENTS + uint_fast16_t consumedCount = 0; +#endif + uint32_t timeout; + uint_fast32_t timeoutStamp; + ICall_Errno errno; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || + threadtype == BIOS_ThreadType_Swi) + { + /* Blocking call is not allowed from Hwi or Swi. + * Note that though theoretically, Swi or lower priority Hwi may block + * on an event to be generated by a higher priority Hwi, it is not a + * safe practice and hence it is disabled. + */ + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + if (!taskentry) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + /* Successful */ + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + + errno = ICALL_ERRNO_TIMEOUT; + timeoutStamp = Clock_getTicks() + timeout; + while (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) + { + ICall_FetchMsgArgs fetchArgs; + ICall_ServiceEnum servId; + errno = ICall_primFetchMsg(&fetchArgs); + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(fetchArgs.src.entityId, &servId) == + ICALL_ERRNO_SUCCESS) + { + if (args->matchFn(servId, fetchArgs.dest, fetchArgs.msg)) + { + /* Matching message found*/ + args->servId = servId; + args->dest = fetchArgs.dest; + args->msg = fetchArgs.msg; + errno = ICALL_ERRNO_SUCCESS; + break; + } + } + /* Message was received but it wasn't expected one. + * Add to the prepend queue */ + ICall_msgEnqueue(&prependQueue, fetchArgs.msg); +#ifdef ICALL_EVENTS + /* Event are binary semaphore, so if several messsages are posted while + * we are processing one, it's possible that some of them are 'missed' and + * not processed. Sending a event to ourself force this loop to run until + * all the messages in the queue are processed. + */ + ICALL_SYNC_HANDLE_POST(taskentry->syncHandle); +#endif + } + + /* Prepare for timeout exit */ + errno = ICALL_ERRNO_TIMEOUT; + +#ifndef ICALL_EVENTS + /* Keep the decremented semaphore count */ + consumedCount++; +#endif /* ICALL_EVENTS */ + if (timeout != BIOS_WAIT_FOREVER && + timeout != BIOS_NO_WAIT) + { + /* Readjust timeout */ + uint32_t newTimeout = timeoutStamp - Clock_getTicks(); + if (newTimeout == 0 || newTimeout > timeout) + { + break; + } + timeout = newTimeout; + } + } + +#ifdef ICALL_EVENTS + /* + * Because Events are binary semaphores, the task's queue must be checked for + * any remaining messages. If there are, the ICall event flag must be + * re-posted due to it being cleared on the last pend. + */ + ICall_primRepostSync(); +#endif //ICALL_EVENTS + + /* Prepend retrieved irrelevant messages */ + ICall_msgPrepend(&taskentry->queue, prependQueue); +#ifndef ICALL_EVENTS + /* Re-increment the consumed semaphores */ + for (; consumedCount > 0; consumedCount--) + { + Semaphore_post(taskentry->syncHandle); + } +#endif /* ICALL_EVENTS */ + return errno; +} + +/** + * @internal + * Retrieves an entity ID of an entity associated with the calling thread. + * + * @param args arguments corresponding to those of ICall_getEntityId(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when no entity was associated + * with the calling thread. + */ +static ICall_Errno ICall_primGetEntityId(ICall_GetEntityIdArgs *args) +{ + Task_Handle taskhandle = Task_self(); + ICall_CSState key; + size_t i; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || + threadtype == BIOS_ThreadType_Swi) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + if (ICall_entities[i].task->task == taskhandle) + { + /* Found */ + args->entity = i; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + ICall_leaveCSImpl(key); + return ICALL_ERRNO_UNKNOWN_THREAD; +} + +/** + * @internal + * Checks whether the calling thread provides the designated service. + * + * @param args arguments corresponding to those of ICall_threadServes(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread is + * unrecognized. + * @ref ICALL_ERRNO_INVALID_SERVICE if the service id is not enrolled + * by any thread. + */ +static ICall_Errno ICall_primThreadServes(ICall_ThreadServesArgs *args) +{ + Task_Handle taskhandle; + ICall_CSState key; + size_t i; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || + threadtype == BIOS_ThreadType_Swi) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + taskhandle = Task_self(); + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + else if (ICall_entities[i].service == args->servId) + { + args->result = (uint_fast8_t) + (ICall_entities[i].task->task == taskhandle); + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + ICall_leaveCSImpl(key); + return ICALL_ERRNO_INVALID_SERVICE; +} + +/** + * @internal + * Creates an RTOS task. + * + * @param args arguments corresponding to those of ICall_createTask(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. + */ +static ICall_Errno ICall_primCreateTask(ICall_CreateTaskArgs *args) +{ + /* Task_Params is a huge structure. + * To reduce stack usage, heap is used instead. + * This implies that ICall_createTask() must be called before heap + * space may be exhausted. + */ + Task_Params *params = (Task_Params *) ICall_heapMalloc(sizeof(Task_Params)); + Task_Handle task; + + if (params == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + + Task_Params_init(params); + params->priority = args->priority; + params->stackSize = args->stacksize; + params->arg0 = args->arg; + + task = Task_create((Task_FuncPtr) args->entryfn, params, NULL); + ICall_heapFree(params); + + if (task == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +#ifdef ICALL_RTOS_EVENT_API +/** + * @internal + * Creates an event. + * + * @param args arguments corresponding to those of ICall_createEvent(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. + */ +static ICall_Errno ICall_primCreateEvent(ICall_CreateEventArgs *args) +{ + args->event = Event_create(NULL, NULL); + + if (args->event == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_EVENT_API */ +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * @internal + * Creates a semaphore. + * + * @param args arguments corresponding to those of ICall_createSemaphore(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. + */ +static ICall_Errno ICall_primCreateSemaphore(ICall_CreateSemaphoreArgs *args) +{ + /* Semaphore_Params is a huge structure. + * To reduce stack usage, heap is used instead. + * This implies that ICall_createSemaphore() must be called before heap + * space may be exhausted. + */ + Semaphore_Params *semParams = + (Semaphore_Params *) ICall_heapMalloc(sizeof(Semaphore_Params)); + + if (semParams == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + + Semaphore_Params_init(semParams); + if (args->mode == ICALL_SEMAPHORE_MODE_BINARY) + { + semParams->mode = Semaphore_Mode_BINARY; + } + + args->sem = Semaphore_create(args->initcount, semParams, NULL); + ICall_heapFree(semParams); + + if (args->sem == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ +#ifdef ICALL_RTOS_EVENT_API +/** + * @internal + * Waits on a ICALL_MSG_EVENT_ID. + * + * @param args arguments corresponding to those of ICall_waitEvent(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_TIMEOUT when timeout occurred. + */ +static ICall_Errno ICall_primWaitEvent(ICall_WaitEventArgs *args) +{ + uint32_t timeout; + + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + + if (Event_pend(args->event, 0, ICALL_MSG_EVENT_ID, timeout)) + { + return ICALL_ERRNO_SUCCESS; + } + return ICALL_ERRNO_TIMEOUT; +} +#endif /* ICALL_RTOS_EVENT_API */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * @internal + * Waits on a semaphore. + * + * @param args arguments corresponding to those of ICall_waitSemaphore(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_TIMEOUT when timeout occurred. + */ +static ICall_Errno ICall_primWaitSemaphore(ICall_WaitSemaphoreArgs *args) +{ + uint32_t timeout; + + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + if (Semaphore_pend(args->sem, timeout)) + { + return ICALL_ERRNO_SUCCESS; + } + return ICALL_ERRNO_TIMEOUT; +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * @internal signals a semaphore + * @param args arguments corresponding to those of ICall_signal() + * @return return value corresponding to those of ICall_signal() + */ +static ICall_Errno ICall_primPostSemaphore(ICall_SignalArgs *args) +{ + Semaphore_post(args->syncHandle); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_EVENT_API */ +#ifdef ICALL_RTOS_EVENT_API +/** + * @internal signals an event + * @param args arguments corresponding to those of ICall_signal() + * @return return value corresponding to those of ICall_signal() + */ +static ICall_Errno ICall_primPostEvent(ICall_SignalEventsArgs *args) +{ + Event_post(args->syncHandle, args->events); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_EVENT_API */ +/** + * @internal Primitive service function ID to handler function map + */ +#ifndef ICALL_JT +static const struct _icall_primsvcfunc_map_entry_t +{ +#ifdef COVERAGE_TEST + size_t id; +#endif /* COVERAGE_TEST */ + ICall_PrimSvcFunc func; +} ICall_primSvcFuncs[] = +{ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENROLL, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primEnroll + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_REGISTER_APP, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primRegisterApp + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_MSG_ALLOC, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primAllocMsg + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_MSG_FREE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFreeMsg + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_MALLOC, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primMalloc + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_FREE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFree + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SEND_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSend + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_FETCH_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFetchMsg + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SEND_SERV_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSendServiceMsg + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_FETCH_SERV_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFetchServiceMsg + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWait + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SIGNAL, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSignal + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ABORT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primAbort + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENABLE_int, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primEnableint + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_DISABLE_int, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primDisableint + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENABLE_Mint, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primEnableMint + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_DISABLE_Mint, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primDisableMint + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_REGISTER_ISR, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primRegisterISR + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_TICKS, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetTicks + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SET_TIMER_MSECS, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSetTimerMSecs + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_TICK_PERIOD, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetTickPeriod + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_MAX_MILLISECONDS, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetMaxMSecs + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENTITY2SERVICE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primE2S + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_UPD_ACTIVITY_COUNTER, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrUpdActivityCounter + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_REGISTER_NOTIFY, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrRegisterNotify + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_MATCH, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWaitMatch + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_ENTITY_ID, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetEntityId + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SET_TIMER, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSetTimer + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_STOP_TIMER, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primStopTimer + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_CONFIG_AC_ACTION, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrConfigACAction + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_REQUIRE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrRequire + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_DISPENSE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrDispense + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_THREAD_SERVES, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primThreadServes + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_IS_STABLE_XOSC_HF, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrIsStableXOSCHF + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_GET_TRANSITION_STATE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrGetTransitionState + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_TASK, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primCreateTask + }, + +#ifdef ICALL_RTOS_SEMAPHORE_API + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_SEMAPHORE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primCreateSemaphore + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWaitSemaphore + }, + +#else /* ICALL_RTOS_SEMAPHORE_API */ + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, +#endif /* COVERAGE_TEST */ + NULL + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, +#endif /* COVERAGE_TEST */ + NULL + }, +#endif /* ICALL_RTOS_SEMAPHORE_API */ + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SWITCH_XOSC_HF, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrSwitchXOSCHF + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_GET_XOSC_STARTUP_TIME, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrGetXOSCStartupTime + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_REGISTER_ISR_EXT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primRegisterISR_Ext + }, + +#ifdef ICALL_RTOS_SEMAPHORE_API + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_SEMAPHORE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primPostSemaphore + }, +#else /*ICALL_RTOS_SEMAPHORE_API */ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_SEMAPHORE, +#endif /* COVERAGE_TEST */ + NULL + }, /* ICALL_RTOS_SEMAPHORE_API */ +#endif + +#ifdef ICALL_RTOS_EVENT_API + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_EVENT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primCreateEvent + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_EVENT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWaitEvent + }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_EVENT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primPostEvent + }, +#else /*ICALL_RTOS_EVENT_API */ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_EVENT, +#endif /* COVERAGE_TEST */ + NULL + }, + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_EVENT, +#endif /* COVERAGE_TEST */ + NULL + }, /* ICALL_RTOS_EVENT_API */ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_EVENT, +#endif /* COVERAGE_TEST */ + NULL + }, /* ICALL_RTOS_EVENT_API */ +#endif /* ICALL_RTOS_EVENT_API */ +}; +/** + * @internal + * Primitive service registered handler function + * @param args arguments + * @return error code + */ +static ICall_Errno ICall_primService(ICall_FuncArgsHdr *args) +{ + if (args->func >= sizeof(ICall_primSvcFuncs)/sizeof(ICall_primSvcFuncs[0])) + { + return ICALL_ERRNO_INVALID_FUNCTION; + } + return ICall_primSvcFuncs[args->func].func(args); +} + +/** + * @internal Enrolls primitive service + */ +static void ICall_initPrim(void) +{ + ICall_entities[0].service = ICALL_SERVICE_CLASS_PRIMITIVE; + ICall_entities[0].fn = ICall_primService; + + /* Initialize heap */ + ICall_heapInit(); + + /* TODO: Think about freezing permanently allocated memory blocks + * for optimization. + * Now that multiple stack images may share the same heap. + * kick cannot be triggered by a single stack image. + * Hence, maybe there should be an alternative API to + * permanently allocate memory blocks, such as + * by allocating the blocks at the end of the heap space. */ +} +#endif /* ICALL_JT */ + +#ifdef COVERAGE_TEST +/** + * @internal + * Verification function for ICall implementation + */ +void ICall_verify(void) +{ + size_t i; + for (i = 0; i < sizeof(ICall_primSvcFuncs)/sizeof(ICall_primSvcFuncs[0]); i++) + { + if (i != ICall_primSvcFuncs[i].id) + { + ICall_abort(); + } + } +} +#endif /* COVERAGE_TEST */ + + +#ifdef ICALL_JT +/** + * Registers an application. + * Note that this function must be called from the thread + * from which ICall_wait() function will be called. + * + * @param entity pointer to a variable to store entity id assigned + * to the application. + * @param msgsem pointer to a variable to store the synchronous object handle + * associated with the calling thread. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + */ +ICall_Errno ICall_registerApp(ICall_EntityID *entity, + ICall_SyncHandle *msgSyncHdl) +{ + + size_t i; + ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + if (!taskentry) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = ICALL_SERVICE_CLASS_APPLICATION; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = NULL; + *entity = (ICall_EntityID) i; + *msgSyncHdl = taskentry->syncHandle; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_NO_RESOURCE); +} + +/** + * Allocates memory block for a message. + * @param size size of the message body in bytes. + * @return pointer to the start of the message body of the newly + * allocated memory block, or NULL if the allocation + * failed. + */ +void *ICall_allocMsg(size_t size) +{ + ICall_MsgHdr *hdr = + (ICall_MsgHdr *) ICall_heapMalloc(sizeof(ICall_MsgHdr) + size); + + if (!hdr) + { + return NULL; + } + hdr->len = size; + hdr->next = NULL; + hdr->dest_id = ICALL_UNDEF_DEST_ID; + return ((void *) (hdr + 1)); + +} + +/** + * Frees the memory block allocated for a message. + * @param msg pointer to the start of the message body + * which was returned from ICall_allocMsg(). + */ +void ICall_freeMsg(void *msg) +{ + ICall_MsgHdr *hdr = (ICall_MsgHdr *) msg - 1; + ICall_heapFree(hdr); +} + +/** + * Sends a message to a registered server. + * @param src Entity id of the sender of the message + * @param dest Service id + * @param format Message format: + * @ref ICALL_MSG_FORMAT_KEEP, + * @ref ICALL_MSG_FORMAT_1ST_CHAR_TASK_ID or + * @ref ICALL_MSG_FORMAT_3RD_CHAR_TASK_ID. + * Message format indicates whether and which + * field of the message must be transformed + * into a implementation specific sender + * identity for an external image.
+ * When a service message interface is defined, + * it may contain a field that is not understood + * by the client but only understood by + * the system on the server's side. + * The format provides an information to the + * messaging system on such a server + * so that it can generically tag necessary + * information to the message. + * @param msg pointer to the message body to send.
+ * Note that if message is successfully sent, + * the caller should not reference the message any + * longer.
+ * However, if the function fails, the caller + * still owns the reference to the message. + * That is, caller may attempt another send, + * or may free the memory block, etc. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_SERVICE when the 'dest' + * is unregistered service.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the 'src' + * is an out of range entity id or when 'dest' is + * is a service that does not receive a message + * (such as ICall primitive service).
+ * Note that as far as 'src' is within the range, + * this function won't notice the 'src' entity id + * as invalid. + */ + + +ICall_Errno +ICall_sendServiceMsg(ICall_EntityID src, + ICall_ServiceEnum dest, + ICall_MSGFormat format, void *msg) +{ + ICall_EntityID dstentity = ICall_searchServiceEntity(dest); + + if (dstentity == ICALL_INVALID_ENTITY_ID) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + return (ICall_send(src, dstentity, format, msg)); +} + +/** + * Retrieves a message received at the message queue + * associated with the calling thread. + * + * Note that this function should be used by an application + * which does not expect any message from non-server entity. + * + * @param src pointer to a variable to store the service id + * of the registered server which sent the retrieved + * message + * @param dest pointer to a variable to store the entity id + * of the destination of the message. + * @param msg pointer to a pointer variable to store the + * starting address of the message body being + * retrieved. + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and a message was retrieved.
+ * @ref ICALL_ERRNO_NOMSG when there is no queued message + * at the moment.
+ * @ref ICALL_ERRNO_CORRUPT_MSG when a message queued in + * front of the thread's receive queue was not sent by + * a server. Note that in this case, the message is + * not retrieved but thrown away.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is + * called from a thread which has not registered + * an entity, either through ICall_enrollService() + * or through ICall_registerApp(). + */ +ICall_Errno +ICall_fetchServiceMsg(ICall_ServiceEnum *src, + ICall_EntityID *dest, + void **msg) +{ + ICall_ServiceEnum servId; + ICall_Errno errno = ICall_fetchMsg((ICall_EntityID*)src, dest, msg); + + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(*src, &servId) != + ICALL_ERRNO_SUCCESS) + { + /* Source entity ID cannot be translated to service id */ + ICall_freeMsg(*msg); + return ICALL_ERRNO_CORRUPT_MSG; + } + *src = servId; + } + return (errno); + +} +#if 0 +void convertMilliToTimepec(struct timespec *timeoutPosix,uint32_t timeout) +{ + timeoutPosix->tv_sec = (timeout / 1000); + timeout = timeout % 1000; + + /* 1 millisecond = 1 000 000 nanoseconds */ + timeoutPosix->tv_nsec = timeout * 1000000; +} +#endif + + +/** + * Waits for a signal to the semaphore associated with the calling thread. + * + * Note that the semaphore associated with a thread is signaled + * when a message is queued to the message receive queue of the thread + * or when ICall_signal() function is called onto the semaphore. + * + * @param milliseconds timeout period in milliseconds. + * @return @ref ICALL_ERRNO_SUCCESS when the semaphore is signaled.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled. + */ +ICall_Errno ICall_wait(uint_fast32_t milliseconds) +{ + TaskHandle_t taskhandle = Task_self(); + ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); + uint32_t timeout; + uint32_t event; + + int16_t retVal = 0; + + if (!taskentry) + { + return (ICALL_ERRNO_UNKNOWN_THREAD); + } + /* Successful */ + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + +#ifdef FREERTOS + if (HwiP_inISR()) { + xQueueReceiveFromISR(taskentry->syncHandle, (char*)&event, NULL); + } + else { + xQueueReceive(taskentry->syncHandle, (char*)&event, milliseconds*100); + } +#endif + if(retVal != (-1)) + { + return (ICALL_ERRNO_SUCCESS); + } + + return (ICALL_ERRNO_TIMEOUT); +} + +/** + * Signals a semaphore. + * @param msgsem handle of a synchronous object to signal + * @return @ref ICALL_ERRNO_SUCCESS + */ +ICall_Errno ICall_signal(ICall_SyncHandle msgSyncHdl) +{ + /* 0x80000000 is an internal Event_ID */ + uint32_t msg_ptr = 0x80000000; + ICall_Errno status = ICALL_ERRNO_NOMSG; + +#ifdef FREERTOS + uint8_t status1; + if (HwiP_inISR()) { + status1 = xQueueSendFromISR(msgSyncHdl, (char*)&msg_ptr, NULL); + } + else { + status1 = xQueueSend(msgSyncHdl, (char*)&msg_ptr, 0); + } + + if (status1 != pdTRUE) { + + while(1); + } +#endif + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Registers a service entity + * @param service service id of the enrolling service + * @param fn handler function which handles function + * calls to the service. + * @param entity pointer to a variable to store the assigned entity id + * @param msgsem pointer to a variable to store the synchronous object handle + * associated with the calling thread. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when service id is already + * registered by another entity.
+ * @ref ICALL_ERRNO_NO_RESOURCE when maximum number of services + * are already registered. + */ +ICall_Errno +ICall_enrollService(ICall_ServiceEnum service, + ICall_ServiceFunc fn, + ICall_EntityID *entity, + ICall_SyncHandle *msgSyncHdl) +{ + size_t i; + ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + /* Note that certain service does not handle a message + * and hence, taskentry might be NULL. + */ + if (taskentry == NULL) + { + return (ICALL_ERRNO_INVALID_PARAMETER); + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = service; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = fn; + *entity = (ICall_EntityID) i; + *msgSyncHdl = taskentry->syncHandle; + + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_SUCCESS); + } + else if (service == ICall_entities[i].service) + { + /* Duplicate service enrollment */ + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_INVALID_PARAMETER); + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_NO_RESOURCE); + +} +#ifdef FREERTOS + +/** + * Allocates a memory block. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ + +void *ICall_heapMalloc(uint32_t size) +{ + void* ret = NULL; + ret = malloc(size); + return ret; +} + +/** + * Frees an allocated memory block. + * @param msg pointer to a memory block to free. + */ +void ICall_heapFree(void *msg) +{ + free(msg); +} + + +/** + * Allocates a memory block, but check if enough memory will be left after the allocation. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ + +void *ICall_heapMallocLimited(uint_least16_t size) +{ + return malloc(size); +} + +/** + * Get Statistic on Heap. + * @param stats pointer to a heapStats_t structure. + */ + +/* Statistics currently are not supported via ICall apis. + * Please consider to use bget statistics (or any of your internal heap statistics) */ +void ICall_heapGetStats(ICall_heapStats_t *pStats) +{ +} + +#endif // FREERTOS +/** + * Allocates a memory block. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ +void *ICall_malloc(uint_least16_t size) +{ + return (ICall_heapMalloc(size)); +} + +/** + * Frees an allocated memory block. + * @param msg pointer to a memory block to free. + */ +void ICall_free(void *msg) +{ + ICall_heapFree(msg); +} + +/** + * Allocates a memory block, but check if enough memory will be left after the allocation. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ + +void *ICall_mallocLimited(uint_least16_t size) +{ + return (ICall_heapMallocLimited(size)); +} + +/** + * Get Statistic on Heap. + * @param stats pointer to a heapStats_t structure. + */ +void ICall_getHeapStats(ICall_heapStats_t *pStats) +{ + ICall_heapGetStats(pStats); +} + + +#ifdef HEAPMGR_METRICS +/** + * @brief obtain heap usage metrics + * @param pBlkMax pointer to a variable to store max cnt of all blocks ever seen at once + * @param pBlkCnt pointer to a variable to store current cnt of all blocks + * @param pBlkFree pointer to a variable to store current cnt of free blocks + * @param pMemAlo pointer to a variable to store current total memory allocated + * @param pMemMax pointer to a variable to store max total memory ever allocated at once + * @param pMemUB pointer to a variable to store the upper bound of memory usage + */ +void ICall_getHeapMgrGetMetrics(uint32_t *pBlkMax, + uint32_t *pBlkCnt, + uint32_t *pBlkFree, + uint32_t *pMemAlo, + uint32_t *pMemMax, + uint32_t *pMemUB) +{ + ICall_heapMgrGetMetrics( pBlkMax, + pBlkCnt, + pBlkFree, + pMemAlo, + pMemMax, + pMemUB); +} + +#endif +/** + * Sends a message to an entity. + * @param src entity id of the sender + * @param dest entity id of the destination of the message. + * @param format message format. See ICall_sendServiceMsg(). + * @param msg pointer to the message body. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when either src + * or dest is not a valid entity id or when + * dest is an entity id of an entity that does + * not receive a message + * (e.g., ICall primitive service entity). + */ +ICall_Errno ICall_send(ICall_EntityID src, + ICall_EntityID dest, + ICall_MSGFormat format, + void *msg) +{ + ICall_CSState key; + ICall_MsgHdr *hdr = (ICall_MsgHdr *) msg - 1; + + if (dest >= ICALL_MAX_NUM_ENTITIES || + src >= ICALL_MAX_NUM_ENTITIES) + { + return (ICALL_ERRNO_INVALID_PARAMETER); + } + key = ICall_enterCSImpl(); + if (!ICall_entities[dest].task) + { + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_INVALID_PARAMETER); + } + + ICall_leaveCSImpl(key); + /* Note that once the entry is valid, + * the value does not change and hence it is OK + * to leave the critical section. + */ + + hdr->srcentity = src; + hdr->dstentity = dest; + hdr->format = format; + + ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg); +/* 0x80000000 is an internal event number */ + uint32_t msg_ptr = 0x80000000; +#ifdef FREERTOS + uint8_t status; + + if (HwiP_inISR()) { + status = xQueueSendFromISR(ICall_entities[dest].task->syncHandle, (char*)&msg_ptr, NULL); + } + else { + status = xQueueSend(ICall_entities[dest].task->syncHandle, (char*)&msg_ptr, 0); + } + + if (status != pdPASS) + { + while(1); + } +#endif + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Retrieves a message, queued to receive queue of the calling thread. + * + * @param src pointer to a variable to store the sender entity id + * of the received message. + * @param dest pointer to a variable to store the destination entity id + * of the received message. + * @param msg pointer to a pointer variable to store the starting + * address of a received message body. + * @return @ref ICALL_ERRNO_SUCCESS when a message was successfully + * retrieved.
+ * @ref ICALL_ERRNO_NOMSG when no message was queued to + * the receive queue at the moment.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread + * does not have a received queue associated with it. + * This happens when neither ICall_enrollService() nor + * ICall_registerApp() was ever called from the calling + * thread. + */ +ICall_Errno ICall_fetchMsg(ICall_EntityID *src, + ICall_EntityID *dest, + void **msg) +{ + void *msgTemp; + TaskHandle_t taskhandle = Task_self(); + ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); + ICall_MsgHdr *hdr; + + if (!taskentry) + { + return (ICALL_ERRNO_UNKNOWN_THREAD); + } + /* Successful */ + msgTemp = ICall_msgDequeue(&taskentry->queue); + + if (msgTemp == NULL) + { + return (ICALL_ERRNO_NOMSG); + } + hdr = (ICall_MsgHdr *) msgTemp - 1; + *src = hdr->srcentity; + *dest = hdr->dstentity; + *msg = msgTemp; + return (ICALL_ERRNO_SUCCESS); + +} + +/** + * Transforms and entityId into a serviceId. + * Note that this function is useful in case an application + * waits for messages from both a server and another application, + * in which case, the application can only use ICall_fetchMsg(), + * not ICall_fetchServiceMsg() because the latter will return + * @ref ICALL_ERRNO_CORRUPT_MSG when a message sent by the other + * application is about to be fetched.
+ * This function, then, is useful to retrieve service id + * matching the source entity id in case the source entity + * id is not that of the other application. + * + * @param entityId entity id + * @param servId pointer to a variable to store + * the resultant service id + * @return @ref ICALL_ERRNO_SUCCESS if the transformation was successful.
+ * @ref ICALL_ERRNO_INVALID_SERVICE if no matching service + * is found for the entity id. + */ +ICall_Errno ICall_entityId2ServiceId(ICall_EntityID entityId, + ICall_ServiceEnum *servId) +{ + return ICall_primEntityId2ServiceId(entityId, servId); +} + +/** + * Aborts. + * + * This is preferred over C runtime abort() function, + * in an external image since the C runtime abort() is only + * guaranteed in a root image which contains the C runtime + * entry function that is executed upon startup. + */ +ICall_Errno +ICall_abort(void) +{ +#ifdef HALNODEBUG +#elif defined(EXT_HAL_ASSERT) + HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_ABORT); +#else + { + volatile uint8_t j=1; + while(j); + } +#endif /* EXT_HAL_ASSERT */ + ICALL_HOOK_ABORT_FUNC(); + return(ICALL_ERRNO_SUCCESS); +} + +/** + * Enables interrupt. + * @param intnum interrupt number + * @return @ref ICALL_ERRNO_SUCCESS. + */ +ICall_Errno +ICall_enableint(int intnum) +{ + Hwi_enableinterrupt(intnum); + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Disables interrupt + * @param intnum interrupt number + * @return @ref ICALL_ERRNO_SUCCESS + */ +ICall_Errno +ICall_disableint(int intnum) +{ + Hwi_disableinterrupt(intnum); + return (ICALL_ERRNO_SUCCESS); +} + + + +/** + * Gets the current tick counter value. + * @return current tick counter value + */ +uint_fast32_t +ICall_getTicks(void) +{ + return (ClockP_getSystemTicks()); +} + +/** + * Gets the tick period. + * @return tick period in microseconds. + */ +uint_fast32_t +ICall_getTickPeriod(void) +{ + return CLOCK_TICKS_PERIOD; +} + +/** + * Gets the maximum timeout period supported by + * ICall_setTimerMSecs() function. + * + * @return maximum timeout period in milliseconds + */ +uint_fast32_t +ICall_getMaxMSecs(void) +{ + + uint_fast64_t tmp = ((uint_fast64_t) 0x7ffffffful) * (ICall_getTickPeriod()); + tmp /= 1000; + if (tmp >= 0x80000000ul) + { + tmp = 0x7ffffffful; + } + return ((uint_least32_t) tmp); +} + +/** + * Set up or restart a timer. + * Note that the timer setup initially by this function may be restarted + * using ICall_setTimer() function as well. + * + * @param msecs timeout period in milliseconds after which callback function + * shall be called. + * @param cback callback function pointer + * @param arg argument to pass to the callback function + * @param id pointer to the timer ID. + * If a new timer must be set up, the value of the timer ID + * must be set to @ref ICALL_INVALID_TIMER_ID when making this + * call and when the function returns successfully, the variable + * will be assigned a new timer ID value. + * The value other than @ref ICALL_INVALID_TIMER_ID shall be + * regarded as a request to restart the earlier set timer. + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when msecs is greater than + * maximum value supported;
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + * + * @see ICall_getMaxMSecs() + */ +ICall_Errno +ICall_setTimerMSecs(uint_fast32_t msecs, + ICall_TimerCback cback, + void *arg, + ICall_TimerID *id) +{ + uint32_t ticks; + uint32_t timeout; + /* Convert to tick time */ + ICall_Errno errno = ICall_msecs2Ticks(msecs, &ticks); + + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + timeout = ticks; + ICall_setTimer(timeout, cback, arg, id); + + return (errno); +} + +/** + * Set up or restart a timer. + * Note that the timer setup initially by this function may be restarted + * using ICall_setTimerMSecs() function as well. + * + * @param ticks timeout period in ticks after which the callback function + * shall be called. + * @param cback callback function pointer + * @param arg argument to pass to the callback function + * @param id pointer to the timer ID. + * If a new timer must be set up, the value of the timer ID + * must be set to @ref ICALL_INVALID_TIMER_ID when making this + * call and when the function returns successfully, the variable + * will be assigned a new timer ID value. + * The value other than @ref ICALL_INVALID_TIMER_ID shall be + * regarded as a request to restart the earlier set timer. + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + * + * @see ICall_getTickPeriod() + */ + + +ICall_Errno +ICall_setTimer(uint32_t ticks, + ICall_TimerCback cback, + void *arg, + ICall_TimerID *id) +{ + + ICall_ScheduleEntry *entry; + + if (*id == ICALL_INVALID_TIMER_ID) + { + ClockP_Params params; + + /* Create a new timer */ + entry = ICall_heapMalloc(sizeof(ICall_ScheduleEntry)); + if (entry == NULL) + { + /* allocation failed */ + return (ICALL_ERRNO_NO_RESOURCE); + } + ClockP_Params_init(¶ms); + params.startFlag = FALSE; + params.period = 0; + params.arg = (uintptr_t) entry; + + entry->clockP = ClockP_create(ICall_clockFunc, + ticks, + ¶ms); + if (!entry->clockP) + { + /* abort */ + ICall_abort(); + ICall_heapFree(entry); + return (ICALL_ERRNO_NO_RESOURCE); + } + entry->cback = cback; + entry->arg = arg; + *id = (ICall_TimerID) entry; + } + else + { + ICall_CSState key; + + entry = (ICall_ScheduleEntry *) *id; + + /* Critical section is entered to disable interrupts that might cause call + * to callback due to race condition */ + key = ICall_enterCriticalSection(); + ClockP_stop(entry->clockP); + entry->arg = arg; + ICall_leaveCriticalSection(key); + } + ClockP_setTimeout(entry->clockP, ticks); + + ClockP_start(entry->clockP); + + return (ICALL_ERRNO_SUCCESS); + +} + +/** + * Stops a timer. + * + * @param id timer ID. + */ +void +ICall_stopTimer(ICall_TimerID id) +{ + ICall_ScheduleEntry *entry = (ICall_ScheduleEntry *) id; + + if (id == ICALL_INVALID_TIMER_ID) + { + return; + } + + ClockP_stop(entry->clockP); +} + +/** + * Increments or decrements power activity counter. + * + * When power activity counter is greater than zero, + * the device shall stay in the active power state. + * The caller has to make sure that it decrements the counter + * as many times as it has incremented the counter + * when there is no activity that requires the active power state. + * It is recommended that each client increments the counter by just one, + * but it is not mandated to be so. + * + * @param incFlag TRUE to indicate incrementing the counter.
+ * FALSE to indicate decrementing the counter. + * @return @ref TRUE if power is required.
+ * @ref FALSE if power is not required.
+ */ +bool +ICall_pwrUpdActivityCounter(bool incFlag) +{ + ICall_PwrUpdActivityCounterArgs args; + args.incFlag = incFlag; + ICallPlatform_pwrUpdActivityCounter(&args); + return (args.pwrRequired); +} + +/** + * Configures power constraint/dependency set/release actions upon + * activity counter change. + * + * When activity counter value drops to zero, all constraints and + * dependencies configured by this function shall be released.
+ * When activity counter value increments to one, all constraints + * and dependencies configured by this function shall be set. + * + * @param bitmap a bitmap of constraint or dependency flags.
+ * The flag definition is specific to each platform. + * For instance, see ICallCC26xxDefs.h. + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid + * flag in the bitmap is detected.
+ */ +ICall_Errno +ICall_pwrConfigACAction(ICall_PwrBitmap_t bitmap) +{ + ICall_PwrBitmapArgs args; + args.bitmap = bitmap; + return (ICallPlatform_pwrConfigACAction(&args)); +} + +/** + * Sets power constraints and dependencies. + * + * @param bitmap a bitmap of constraint or dependency flags.
+ * The flag definition is specific to each platform. + * For instance, see ICallCC26xxDefs.h. + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid + * flag in the bitmap is detected.
+ */ +ICall_Errno +ICall_pwrRequire(ICall_PwrBitmap_t bitmap) +{ + ICall_PwrBitmapArgs args; + args.bitmap = bitmap; + return (ICallPlatform_pwrRequire(&args)); +} + +/** + * Releases power constraints and dependencies. + * + * @param bitmap a bitmap of constraint or dependency flags.
+ * The flag definition is specific to each platform. + * For instance, see ICallCC26xxDefs.h. + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid + * flag in the bitmap is detected.
+ */ +ICall_Errno +ICall_pwrDispense(ICall_PwrBitmap_t bitmap) +{ + ICall_PwrBitmapArgs args; + args.bitmap = bitmap; + return (ICallPlatform_pwrDispense(&args)); +} + +/** + * Checks whether HF XOSC is stable. + * This function must be called after HF XOSC is turned on + * (through power dependency). + * + * @return TRUE when HF XOSC is stable.
+ * FALSE when HF XOSC is not stable.
+ */ +bool +ICall_pwrIsStableXOSCHF(void) +{ + ICall_GetBoolArgs args; + (void) ICallPlatform_pwrIsStableXOSCHF(&args); + return (args.value); +} + +/** + * Switch clock source to HF XOSC. + * This function must be called after HF XOSC is stable. + * + * @return @ref ICALL_ERRNO_SUCCESS + */ +ICall_Errno +ICall_pwrSwitchXOSCHF(void) +{ + ICall_FuncArgsHdr args; + return (ICallPlatform_pwrSwitchXOSCHF(&args)); +} + +/** + * Gets the estimated crystal oscillator startup time. + * + * @return estimated crystal oscillator startup time + */ +uint32_t +ICall_pwrGetXOSCStartupTime(uint_fast32_t timeUntilWakeupInMs) +{ + ICall_PwrGetXOSCStartupTimeArgs args; + args.timeUntilWakeupInMs = timeUntilWakeupInMs; + (void) ICallPlatform_pwrGetXOSCStartupTime(&args); + return (args.value); +} + +/** + * Registers a power state transition notify function. + * + * The registered notify function shall be called when the power state + * changes. + * + * @param fn notify function pointer + * @param obj pointer to data object to be passed to notify function.
+ * This pointer must not be NULL and can point to an aggregate type + * containing the @ref ICall_PwrNotifyData. + * The object must not be released. + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_NO_RESOURCE when registration failed
+ */ +ICall_Errno +ICall_pwrRegisterNotify(ICall_PwrNotifyFn fn, ICall_PwrNotifyData *obj) +{ + ICall_PwrRegisterNotifyArgs args; + args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE; + args.hdr.func = ICALL_PRIMITIVE_FUNC_PWR_REGISTER_NOTIFY; + args.fn = fn; + args.obj = obj; + return (ICallPlatform_pwrRegisterNotify(&args)); +} + +/** + * Retrieves power transition state. + * + * @return Implementation specific transition state when successful
+ * Zero when the function is not implemented.
+ */ +uint_fast8_t +ICall_pwrGetTransitionState(void) +{ + ICall_PwrGetTransitionStateArgs args; + ICall_Errno errno; + + errno = ICallPlatform_pwrGetTransitionState(&args); + + if (errno == ICALL_ERRNO_SUCCESS) + { + return (args.state); + } + return (0); +} + +/** + * Creates a new RTOS task. + * + * @param entryfn task entry function. + * @param priority task priority as understood by the underlying RTOS + * @param stacksize stack size as understood by the underlying RTOS + * @param arg argument to pass to the task entry function + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_NO_RESOURCE when creation failed
+ */ + + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * Creates a semaphore. + * + * @param mode Semaphore mode
+ * @ref ICALL_SEMAPHORE_MODE_COUNTING, or
+ * @ref ICALL_SEMAPHORE_MODE_BINARY + * @param initcount initial count value + * @return created semaphore when successful
+ * NULL when creation failed
+ */ +ICall_Semaphore +ICall_createSemaphore(uint_fast8_t mode, int initcount) +{ + /* Semaphore_Params is a huge structure. + * To reduce stack usage, heap is used instead. + * This implies that ICall_createSemaphore() must be called before heap + * space may be exhausted. + */ + ICall_Semaphore sem; + Semaphore_Params *semParams = + (Semaphore_Params *) ICall_heapMalloc(sizeof(Semaphore_Params)); + + if (semParams == NULL) + { + return (NULL); + } + + Semaphore_Params_init(semParams); + if (mode == ICALL_SEMAPHORE_MODE_BINARY) + { + semParams->mode = Semaphore_Mode_BINARY; + } + + sem = Semaphore_create(args->initcount, semParams, NULL); + ICall_heapFree(semParams); + + return (sem); + +} +#endif + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * Post on a semaphore + * + * @param sem semaphore. + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + */ +ICall_Errno +ICall_postSemaphore(ICall_Semaphore sem) +{ + Semaphore_post(sem); + return (ICALL_ERRNO_SUCCESS); +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ + +#ifdef ICALL_RTOS_EVENTS_API +/** + * Creates a event. + * + * @return created event when successful
+ * NULL when creation failed
+ */ +ICall_Event +ICall_createEvent(void) +{ + ICall_Event event = Event_create(NULL, NULL); + return (event); + + + ICall_CreateEventArgs args; + ICall_Errno errno; + + args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE; + args.hdr.func = ICALL_PRIMITIVE_FUNC_CREATE_EVENT; + errno = ICall_dispatcher(&args.hdr); + if (errno == ICALL_ERRNO_SUCCESS) + { + return (args.event); + } + return (NULL); +} + +/** + * Post on an event + * + * @param event event. + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + */ +ICall_Errno +ICall_postEvent(ICall_Event event, uint32_t events) +{ + Event_post(event, events); + return (ICALL_ERRNO_SUCCESS); +} +/** + * Waits on a event for ICALL_MSG_EVENT_ID + * + * @param event event. + * @param milliseconds timeout in milliseconds + * or @ref ICALL_TIMEOUT_FOREVER to wait forever + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and event was received.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the event being signaled. + */ +ICall_Errno +ICall_waitEvent(ICall_Event event, uint_fast32_t milliseconds) +{ + uint32_t timeout; + + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + + if (Event_pend(event, 0, ICALL_MSG_EVENT_ID, timeout)) + { + return (ICALL_ERRNO_SUCCESS); + } + return (ICALL_ERRNO_TIMEOUT); +} +#endif /* ICALL_RTOS_EVENTS_API */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * Waits on a semaphore + * + * @param sem semaphore. + * @param milliseconds timeout in milliseconds + * or @ref ICALL_TIMEOUT_FOREVER to wait forever + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and semaphore was acquired.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled. + */ +ICall_Errno +ICall_waitSemaphore(ICall_Semaphore sem, uint_fast32_t milliseconds) +{ + uint32_t timeout; + + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + if (Semaphore_pend(sem, timeout)) + { + return (ICALL_ERRNO_SUCCESS); + } + return (ICALL_ERRNO_TIMEOUT); +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ + + +#if 0 +/* Util function that take time in ticks and convert it into ms - relate to system clock (returns system clock + converted ms) */ +static void AbsoluteTimeInMilliPlusTimer(uint_least32_t timeout,struct timespec *tsTimer) +{ + + clock_gettime(CLOCK_REALTIME, tsTimer); + + tsTimer->tv_sec += (timeout / 1000); + tsTimer->tv_nsec += (timeout % 1000) * 1000000; +} +#endif + +/** + * Waits for and retrieves a message received at the message queue + * associated with the calling thread, which matches a certain condition. + * + * @param milliseconds timeout period in milliseconds. + * @param matchFn pointer to a function that would return TRUE when + * the message matches its condition. + * @param src pointer to a variable to store the service id + * of the registered server which sent the retrieved + * message, or NULL if not interested in storing service id. + * @param dest pointer to a variable to store the entity id + * of the destination of the message, + * of NULL if not interested in storing the destination entity id. + * @param msg pointer to a pointer variable to store the + * starting address of the message body being + * retrieved. The pointer must not be NULL. + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and a message was retrieved.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled. + * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is + * called from a thread which has not registered + * an entity, either through ICall_enrollService() + * or through ICall_registerApp(). + */ +ICall_Errno +ICall_waitMatch(uint_least32_t milliseconds, + ICall_MsgMatchFn matchFn, + ICall_ServiceEnum *src, + ICall_EntityID *dest, + void **msg) +{ + TaskHandle_t taskhandle = Task_self(); + ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); + ICall_MsgQueue prependQueue = NULL; +#ifndef ICALL_EVENTS + uint_fast16_t consumedCount = 0; +#endif + uint32_t timeout; + uint_fast32_t timeoutStamp; + ICall_Errno errno; + + if (!taskentry) + { + return (ICALL_ERRNO_UNKNOWN_THREAD); + } + /* Successful */ + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + + errno = ICALL_ERRNO_TIMEOUT; + + timeoutStamp = ICall_getTicks() + timeout; + +#ifdef ICALL_LITE + + uint32_t events; + +#ifdef FREERTOS + if (HwiP_inISR()) { +while(1); + } + //TODO: Investigate ICALL Wait tick period (Last parameter) + while( xQueueReceive(taskentry->syncHandle, (char*)&events, milliseconds*1000) == pdPASS ) +#endif +#else /* !ICALL_LITE */ + while (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) +#endif /* ICALL_LITE */ + { + ICall_EntityID fetchSrc; + ICall_EntityID fetchDst; + ICall_ServiceEnum servId; + void *fetchMsg; + errno = ICall_fetchMsg(&fetchSrc, &fetchDst, &fetchMsg); + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(fetchSrc, &servId) == + ICALL_ERRNO_SUCCESS) + { + if (matchFn(servId, fetchDst, fetchMsg)) + { + /* Matching message found*/ + if (src != NULL) + { + *src = servId; + } + if (dest != NULL) + { + *dest = fetchDst; + } + *msg = fetchMsg; + errno = ICALL_ERRNO_SUCCESS; + break; + } + } + /* Message was received but it wasn't expected one. + * Add to the prepend queue */ + ICall_msgEnqueue(&prependQueue, fetchMsg); +#ifdef ICALL_EVENTS + /* Event are binary semaphore, so if several messsages are posted while + * we are processing one, it's possible that some of them are 'missed' and + * not processed. Sending a event to ourself force this loop to run until + * all the messages in the queue are processed. + */ +#ifdef ICALL_LITE + /* 0x20000000 is an internal Event_ID */ + uint32_t msg_ptr = (0x20000000); //Event_Id_29; + +#ifdef FREERTOS + uint8_t status; + if (HwiP_inISR()) { + status = xQueueSendFromISR(taskentry->syncHandle, (char*)&msg_ptr, NULL); + } + else { + status = xQueueSend(taskentry->syncHandle, (char*)&msg_ptr, 0); + } + + if (status != pdTRUE) { + + while(1); + } +#endif + + +#else /* !ICALL_LITE */ + ICALL_SYNC_HANDLE_POST(taskentry->syncHandle); +#endif /* ICALL_LITE*/ +#endif /* ICALL_EVENTS */ + } + + /* Prepare for timeout exit */ + errno = ICALL_ERRNO_TIMEOUT; + +#ifndef ICALL_EVENTS + /* Keep the decremented semaphore count */ + consumedCount++; +#endif /* ICALL_EVENTS */ + if (timeout != BIOS_WAIT_FOREVER && + timeout != BIOS_NO_WAIT) + { + /* Readjust timeout */ + uint32_t newTimeout = timeoutStamp - ICall_getTicks(); + + if (newTimeout == 0 || newTimeout > timeout) + { + break; + } + timeout = newTimeout; + } + } + + + /* Prepend retrieved irrelevant messages */ + ICall_msgPrepend(&taskentry->queue, prependQueue); +#ifndef ICALL_EVENTS + /* Re-increment the consumed semaphores */ + for (; consumedCount > 0; consumedCount--) + { + Semaphore_post(taskentry->syncHandle); + } +#endif /* ICALL_EVENTS */ + return (errno); +} + +/** + * Retrieves an entity ID of (arbitrary) one of the entities registered + * from the calling thread. + * + * Note that, if multiple entities were registered from the same thread, + * this function shall arbitrarily pick one of the entities. + * + * @return A valid entity ID or @ref ICALL_INVALID_ENTITY_ID + * when no entity was registered from the calling thread. + */ +ICall_EntityID +ICall_getEntityId(void) +{ + ICall_EntityID id; + TaskHandle_t taskhandle = Task_self(); + ICall_CSState key; + size_t i; + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + if (ICall_entities[i].task->task == (TaskHandle_t)taskhandle) + { + /* Found */ + id = i; + ICall_leaveCSImpl(key); + return (id); + } + } + ICall_leaveCSImpl(key); + return ICALL_INVALID_ENTITY_ID; + +} + +/** + * Checks whether the calling thread provides the designated service. + * + * @param service Service enumeration value for the service. + * + * @return Non-zero if the current thread provides the designated service. + * Zero, otherwise. + */ +uint_fast8_t +ICall_threadServes(ICall_ServiceEnum service) +{ + uint_fast8_t res = 0; + TaskHandle_t taskhandle; + ICall_CSState key; + size_t i; + taskhandle = Task_self(); + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + else if (ICall_entities[i].service == service) + { + res = (uint_fast8_t) + (ICall_entities[i].task->task == taskhandle); + } + } + ICall_leaveCSImpl(key); + return (res); +} + +/** + * Retrieves an internal ID understood only by a service entity, + * corresponding to an ICall entity ID. + * + * This function is used when a message body includes a field indicating a + * software entity and the destination of the message has its own internal + * message routing mechanism with its own entity enumeration system. + * + * @param service Service enumeration value for the service. + * Currently @ref ICALL_SERVICE_CLASS_BLE_MSG is supported. + * @param entity ICall entity ID. + * + * @return Stack specific 8 bit ID or 0xFF when failed. + */ +uint_fast8_t +ICall_getLocalMsgEntityId(ICall_ServiceEnum service, ICall_EntityID entity) +{ + ICall_GetLocalMsgEntityIdArgs args; + ICall_Errno errno; + args.hdr.service = service; + args.hdr.func = ICALL_MSG_FUNC_GET_LOCAL_MSG_ENTITY_ID; + args.entity = entity; + errno = ICall_dispatcher(&args.hdr); + if (errno == ICALL_ERRNO_SUCCESS) + { + return (args.localId); + } + return (0xFF); +} + +#endif /* ICALL_JT */ + +#ifdef ICALL_LITE + /******************************************************************************* + * @fn matchLiteCS + */ +static bool matchLiteCS(ICall_ServiceEnum src, + ICall_EntityID dest, const void *msg) +{ + (void) src; + (void) dest; + ICall_LiteCmdStatus *pMsg = (ICall_LiteCmdStatus *)msg; + return (pMsg->cmdId == ICALL_LITE_DIRECT_API_DONE_CMD_ID); +} + /******************************************************************************* + * @fn icall_directAPI + * see headers for details. + */ +uint32_t icall_directAPI( uint8_t service , icall_lite_id_t id, ... ) +{ + va_list argp; + uint32_t res; + icallLiteMsg_t liteMsg; + + // The following will push all parameter in the runtime stack. + // This need to be call before any other local declaration of variable.... + va_start(argp, id); + + // Todo - add string for every icall API function, instead of printing function address + BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : icall_directAPI to BLE func=0x%x, status=%d\n", id, 0); + // Create the message that will be send to the requested service.. + liteMsg.hdr.len = sizeof(icallLiteMsg_t); + liteMsg.hdr.next = NULL; + liteMsg.hdr.dest_id = ICALL_UNDEF_DEST_ID; + liteMsg.msg.directAPI = id; + liteMsg.msg.pointerStack = (uint32_t*)(*((uint32_t*)(&argp))); + ICall_sendServiceMsg(ICall_getEntityId(), service, + ICALL_MSG_FORMAT_DIRECT_API_ID, &(liteMsg.msg)); + + // Since stack needs to always have a higher priority than the thread calling + // the API, when we reach this point the API has been executed by the stack. + // This implies the following: + // - API are not called in critical section or in section where task + // switching is disabled + // It is possible that the stack is blocking on this API, in this case a + // sync object needs to be used in order for this call to resume only when + // the API has been process in full. + { + ICall_Errno errno; + void *pCmdStatus = NULL; + + errno = ICall_waitMatch(ICALL_TIMEOUT_PREDEFINE, matchLiteCS, NULL, NULL, + (void **)&pCmdStatus); + if (errno == ICALL_ERRNO_TIMEOUT) + { +#ifdef HALNODEBUG +#elif defined(EXT_HAL_ASSERT) + HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_TIMEOUT); +#else /* !EXT_HAL_ASSERT */ + ICall_abort(); +#endif /* EXT_HAL_ASSERT */ + } + else if (errno == ICALL_ERRNO_SUCCESS) + { + if (pCmdStatus) + { + ICall_freeMsg(pCmdStatus); + } + } + else + { +#ifdef HALNODEBUG +#else /* ! HALNODEBUG */ + ICall_abort(); +#endif /* HALNODEBUG */ + } + } + + // The return parameter is set in the runtime stack, at the location of the + // first parameter. + res = liteMsg.msg.pointerStack[0]; + + va_end(argp); + + return (res); +} + + /******************************************************************************* + * @fn ICall_sendServiceComplete + * see headers for details. + */ +ICall_Errno ICall_sendServiceComplete(ICall_EntityID src, + ICall_EntityID dest, + ICall_MSGFormat format, + void *msg) +{ + ICall_CSState key; + ICall_MsgHdr *hdr = (ICall_MsgHdr *) msg - 1; + + if (dest >= ICALL_MAX_NUM_ENTITIES || + src >= ICALL_MAX_NUM_ENTITIES) + { + return (ICALL_ERRNO_INVALID_PARAMETER); + } + key = ICall_enterCSImpl(); + if (!ICall_entities[dest].task) + { + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_INVALID_PARAMETER); + } + + ICall_leaveCSImpl(key); + /* Note that once the entry is valid, + * the value does not change and hence it is OK + * to leave the critical section. + */ + + hdr->srcentity = src; + hdr->dstentity = dest; + hdr->format = format; + ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg); + + /* 0x20000000 is an internal Event_ID */ + uint32_t msg_ptr = (0x20000000); //Event_Id_29; +#ifdef FREERTOS + uint8_t status; + if (HwiP_inISR()) { + status = xQueueSendFromISR(ICall_entities[dest].task->syncHandle, (char*)&msg_ptr, NULL); + } + else { + status = xQueueSend(ICall_entities[dest].task->syncHandle, (char*)&msg_ptr, 0); + } + + if (status != pdTRUE) { + + while(1); + } +#endif + return (ICALL_ERRNO_SUCCESS); +} +#endif /* ICALL_LITE*/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c85620..8a3d618 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,7 @@ if(TI_SIMPLELINK_KERNEL STREQUAL "freertos") ${TI_SIMPLELINK_SDK_DIR}/source/ti ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx +# ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/npi/stack/ ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/rcosc ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/controller/cc26xx/inc @@ -260,13 +261,38 @@ set(USR_COMPILE_DEFINITIONS "ICALL_MAX_NUM_TASKS=3" "OSAL_CBTIMER_NUM_TASKS=1" "ONE_BLE_LIB_SIZE_OPTIMIZATION" + "FLASH_ONLY_BUILD" # the following are from ti_build_config.opt "HOST_CONFIG=PERIPHERAL_CFG" "USE_AE" + + "GAP_BOND_MGR" "HCI_TL_NONE" "FREERTOS" +#"BROADCASTER_CFG=0x1" +#"OBSERVER_CFG=0x2" +"PERIPHERAL_CFG=0x4" +#"CERTRAL_CFG=0x8" +"ADV_NCONN_CFG=0x2" +"SCAN_CFG=0x4" +"INIT_CFG=0x08" +"ADV_CFG=ADV_NCONN_CFG+ADV_CONN_CFG" +"LINK_CFG=ADV_CONN_CFG+INIT_CFG" +"FULL_CFG=INIT_CFG+SCAN_CFG+ADV_NCONN_CFG+ADV_CONN_CFG" +"L2CAP_COC_CFG=0x80" +"HOST_V41_MASK=0x80" +"CTRL_V41_MASK=0x7F" +"SCAN_REQ_RPT_CFG=0x2" +"PHY_2MBS_CFG=0x1" +"PHY_LR_CFG=0x02" +"HCD_NC_ADV_CFG=0x04" +"AE_CFG=0x08" +"PERIODIC_ADV_CFG=0x10" +"CHAN_ALGO2_CFG=0x40" +#"EXTENDED_STACK_SETTINGS_DEFAULT=0x0" +#"MASTER_GUARD_TIME_ENABLE=0x01" ) target_compile_definitions(openthread-cc13xx_cc26xx diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index f08706d..b48f4a3 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -125,6 +125,7 @@ /* Required by TI driver implementations */ #define configSUPPORT_STATIC_ALLOCATION 1 +#define configAPPLICATION_ALLOCATED_HEAP 1 /* Constants that build features in or out. */ #define configUSE_MUTEXES 1 diff --git a/src/openthread.syscfg b/src/openthread.syscfg index b03913d..4b26b9e 100755 --- a/src/openthread.syscfg +++ b/src/openthread.syscfg @@ -44,6 +44,7 @@ const SPI = scripting.addModule("/ti/drivers/SPI"); const SPI1 = SPI.addInstance(); const TRNG = scripting.addModule("/ti/drivers/TRNG"); const TRNG1 = TRNG.addInstance(); +const TRNG2 = TRNG.addInstance(); const UART2 = scripting.addModule("/ti/drivers/UART2"); const Watchdog = scripting.addModule("/ti/drivers/Watchdog"); const Watchdog1 = Watchdog.addInstance(); @@ -108,6 +109,9 @@ dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; dmm.policyArray[0].custom1.$name = "ti_dmm_policy_stack_dmm_stack_custom0"; dmm.policyArray[0].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble0"; dmm.policyArray[0].blePeripheral.weight = 1; +dmm.numApplicationStates = 2; +dmm.applicationState0 = "ANY"; +dmm.applicationState1 = "DMMPOLICY_BLE_IDLE"; AESCCM1.$name = "CONFIG_AESCCM_0"; @@ -155,7 +159,7 @@ SPI1.spi.pociPin.$assign = "boosterpack.6"; SPI1.spi.picoPin.$assign = "boosterpack.23"; SPI1.spi.csnPin.$assign = "boosterpack.25"; -TRNG1.$name = "CONFIG_TRNG_THREAD"; +TRNG2.$name = "CONFIG_TRNG_THREAD"; Watchdog1.$name = "CONFIG_WATCHDOG0"; Watchdog1.watchdog.$assign = "WDT0"; diff --git a/third_party/freertos/CMakeLists.txt b/third_party/freertos/CMakeLists.txt index 2ee0167..05b6252 100644 --- a/third_party/freertos/CMakeLists.txt +++ b/third_party/freertos/CMakeLists.txt @@ -43,7 +43,7 @@ set(FREERTOS_SRCS if(TI_SIMPLELINK_ISA STREQUAL "m4f") set(FREERTOS_PORT_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/MemMang/heap_4.c +# ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/MemMang/heap_4.c ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/GCC/ARM_CM4F/port.c ) @@ -53,7 +53,7 @@ if(TI_SIMPLELINK_ISA STREQUAL "m4f") elseif(TI_SIMPLELINK_ISA STREQUAL "m33f") set(FREERTOS_PORT_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/MemMang/heap_4.c +# ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/MemMang/heap_4.c ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/GCC/ARM_CM33_NTZ/non_secure/port.c ${CMAKE_CURRENT_SOURCE_DIR}/repo/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c ) From 8d63d9d79a182ae254aef2c080f7f4bbb2e3c2ab Mon Sep 17 00:00:00 2001 From: Stuart Baker Date: Mon, 5 Feb 2024 16:02:55 -0600 Subject: [PATCH 17/19] Apply R&D updates to enable working BLE connections. --- examples/apps/cli/CMakeLists.txt | 11 ++-- examples/apps/cli/bleAppTask.c | 91 ++++++++++++++++---------------- src/CMakeLists.txt | 53 +++++++++++-------- 3 files changed, 84 insertions(+), 71 deletions(-) diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 3fa6f75..0ef157f 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -34,6 +34,9 @@ set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}/openthread/src/core ${PROJECT_SOURCE_DIR}/examples/apps/cli + ${PROJECT_SOURCE_DIR}/examples/../src/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/dmm_thread_ts_remote_display/source/ + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/ # JJM include paths for ICall module ${TI_SIMPLELINK_SDK_DIR}/source/ti ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/inc/ @@ -64,13 +67,13 @@ set(COMMON_SOURCES bget.c TI_heap_wrapper.c ble_user_config.c - icall_FreeRTOS.c + #icall_FreeRTOS.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/dmm_priority_ble_thread.c - ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/util.c - #${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/util.c -# ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c + #${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/util.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/util.c + ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/menu/two_btn_menu.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index ea6e811..e8cc710 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -210,7 +210,7 @@ typedef struct { uint16_t connHandle; // Connection Handle spClockEventData_t* pParamUpdateEventData; - Clock_Struct* pUpdateClock; // pointer to clock struct + ClockP_Struct* pUpdateClock; // pointer to clock struct int8_t rssiArr[SP_MAX_RSSI_STORE_DEPTH]; uint8_t rssiCntr; int8_t rssiAvg; @@ -273,14 +273,15 @@ mqd_t g_POSIX_appMsgQueue; // Queue object used for app messages //Wei -//static Queue_Struct appMsgQueue; static QueueHandle_t appMsgQueueHandle; +QueueHandle_t appEventsQueueID; +QueueHandle_t appMsgQueueID; // Clock instance for internal periodic events. Only one is needed since // GattServApp will handle notifying all connected GATT clients -static Clock_Struct clkPeriodic; +static ClockP_Struct clkPeriodic; // Clock instance for RPA read events. -static Clock_Struct clkRpaRead; +static ClockP_Struct clkRpaRead; // Memory to pass periodic event ID to clock handler spClockEventData_t argPeriodic = @@ -307,7 +308,7 @@ uint8_t autoConnect = AUTOCONNECT_DISABLE; // Advertising handles static uint8 advHandleLegacy; -static uint8 advHandleLongRange; +//static uint8 advHandleLongRange; // Address mode static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE; @@ -334,7 +335,7 @@ static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId); static void SimplePeripheral_performPeriodicTask(void); static void SimplePeripheral_updateRPA(void); //Wei -static void SimplePeripheral_clockHandler(void *arg); +static void SimplePeripheral_clockHandler(uintptr_t arg); //static void SimplePeripheral_clockHandler(UArg arg); static void SimplePeripheral_passcodeCb(uint8_t *pDeviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, @@ -425,7 +426,7 @@ static void BleMain(void * pvParameter) // message is queued to the message receive queue of the thread //Wei - mq_receive(syncEvent, (char*)&events, sizeof(uint32_t), NULL); + xQueueReceive(syncEvent, (char*)&events, portMAX_DELAY); //events = Event_pend(syncEvent, Event_Id_NONE, SP_ALL_EVENTS, // ICALL_TIMEOUT_FOREVER); @@ -462,23 +463,22 @@ static void BleMain(void * pvParameter) // If RTOS queue is not empty, process app message. if (events & SP_QUEUE_EVT) { - //Wei - spEvt_t *pMsg; - do { - pMsg = (spEvt_t *)Util_dequeueMsg(g_POSIX_appMsgQueue); - if (NULL != pMsg) - { - // Process message. - SimplePeripheral_processAppMsg(pMsg); + spEvt_t *pMsg; + do { + pMsg = (spEvt_t *)Util_dequeueMsg(appMsgQueueID); + if (NULL != pMsg) + { + // Process message. + SimplePeripheral_processAppMsg(pMsg); - // Free the space from the message. - ICall_free(pMsg); - } - else - { - break; - } - }while(1); + // Free the space from the message. + ICall_free(pMsg); + } + else + { + break; + } + } while(1); //while (!Queue_empty(appMsgQueueHandle)) //{ // spEvt_t *pMsg = (spEvt_t *)Util_dequeueMsg(appMsgQueueHandle); @@ -844,6 +844,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) //Wei SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); +#if 0 BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- call GapAdv_create set=%d,%d\n", 1, 0); // Create Advertisement set #2 and assign handle status = GapAdv_create(&SimplePeripheral_advCallback, &advParams2, @@ -868,7 +869,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) status = GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); //Wei SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); - +#endif // Display device address Display_printf(dispHandle, SP_ROW_IDA, 0, "%s Addr: %s", (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID", @@ -881,7 +882,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) // Create one-shot clock for RPA check event. //Wei - Util_constructClock(&clkRpaRead,(void*)SimplePeripheral_clockHandler, READ_RPA_PERIOD, 0, true, (uint32_t)&argRpaRead); + Util_constructClock(&clkRpaRead,(void*)SimplePeripheral_clockHandler, READ_RPA_PERIOD, 0, true, (uintptr_t)&argRpaRead); // Util_constructClock(&clkRpaRead, SimplePeripheral_clockHandler, // READ_RPA_PERIOD, 0, true, // (void *)&argRpaRead); @@ -921,12 +922,12 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) { // Start advertising since there is room for more connections GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); - GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); } else { // Stop advertising since there is no room for more connections - GapAdv_disable(advHandleLongRange); + //GapAdv_disable(advHandleLongRange); GapAdv_disable(advHandleLegacy); } break; @@ -958,7 +959,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : GAP msg: status=%d, opcode=%s\n", 0, "GAP_LINK_TERMINATED_EVENT"); // Start advertising since there is room for more connections GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); - GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); // Clear remaining lines Display_clearLine(dispHandle, SP_ROW_CONNECTION); @@ -1178,7 +1179,7 @@ static void SimplePeripheral_updateRPA(void) * @return None. */ //Wei -static void SimplePeripheral_clockHandler(void *arg) +static void SimplePeripheral_clockHandler(uintptr_t arg) { spClockEventData_t *pData = (spClockEventData_t *)arg; @@ -1591,7 +1592,7 @@ static status_t SimplePeripheral_enqueueMsg(uint8_t event, void *pData) pMsg->pData = pData; // Enqueue the message. - success = Util_enqueueMsg(g_POSIX_appMsgQueue, syncEvent, (uint8_t *)pMsg); + success = Util_enqueueMsg(appMsgQueueID, syncEvent, (uint8_t *)pMsg); return (success) ? SUCCESS : FAILURE; } @@ -1638,14 +1639,14 @@ bool SimplePeripheral_doAutoConnect(uint8_t index) { if (autoConnect != AUTOCONNECT_GROUP_A) { - GapAdv_disable(advHandleLongRange); + //GapAdv_disable(advHandleLongRange); GapAdv_disable(advHandleLegacy); advData1[2] = 'G'; advData1[3] = 'A'; - advData2[2] = 'G'; - advData2[3] = 'A'; + //advData2[2] = 'G'; + //advData2[3] = 'A'; GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); - GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); autoConnect = AUTOCONNECT_GROUP_A; } Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group A"); @@ -1654,14 +1655,14 @@ bool SimplePeripheral_doAutoConnect(uint8_t index) { if (autoConnect != AUTOCONNECT_GROUP_B) { - GapAdv_disable(advHandleLongRange); + //GapAdv_disable(advHandleLongRange); GapAdv_disable(advHandleLegacy); advData1[2] = 'G'; advData1[3] = 'B'; - advData2[2] = 'G'; - advData2[3] = 'B'; + //advData2[2] = 'G'; + //advData2[3] = 'B'; GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); - GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); autoConnect = AUTOCONNECT_GROUP_B; } Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group B"); @@ -1670,14 +1671,14 @@ bool SimplePeripheral_doAutoConnect(uint8_t index) { if (autoConnect) { - GapAdv_disable(advHandleLongRange); + //GapAdv_disable(advHandleLongRange); GapAdv_disable(advHandleLegacy); advData1[2] = 'S'; advData1[3] = 'P'; - advData2[2] = 'S'; - advData2[3] = 'P'; + //advData2[2] = 'S'; + //advData2[3] = 'P'; GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); - GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); + //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); autoConnect = AUTOCONNECT_DISABLE; } Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect disabled"); @@ -1721,7 +1722,7 @@ static uint8_t SimplePeripheral_addConn(uint16_t connHandle) // Create a clock object and start connList[i].pUpdateClock - = (Clock_Struct*) ICall_malloc(sizeof(Clock_Struct)); + = (ClockP_Struct*) ICall_malloc(sizeof(ClockP_Struct)); if (connList[i].pUpdateClock) { @@ -1856,7 +1857,7 @@ static uint8_t SimplePeripheral_removeConn(uint16_t connHandle) if(connIndex != MAX_NUM_BLE_CONNS) { - Clock_Struct* pUpdateClock = connList[connIndex].pUpdateClock; + ClockP_Struct* pUpdateClock = connList[connIndex].pUpdateClock; if (pUpdateClock != NULL) { @@ -2384,7 +2385,7 @@ static void bleStack_init(void) // Create an RTOS queue for message from profile to be sent to app. //Wei //appMsgQueueHandle = Util_constructQueue(&appMsgQueue); - Util_constructQueue(&g_POSIX_appMsgQueue); + Util_constructQueue(&appMsgQueueID); // Create one-shot clock for internal periodic events. //Weiadv diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8a3d618..91e42d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -271,28 +271,37 @@ set(USR_COMPILE_DEFINITIONS "GAP_BOND_MGR" "HCI_TL_NONE" "FREERTOS" -#"BROADCASTER_CFG=0x1" -#"OBSERVER_CFG=0x2" -"PERIPHERAL_CFG=0x4" -#"CERTRAL_CFG=0x8" -"ADV_NCONN_CFG=0x2" -"SCAN_CFG=0x4" -"INIT_CFG=0x08" -"ADV_CFG=ADV_NCONN_CFG+ADV_CONN_CFG" -"LINK_CFG=ADV_CONN_CFG+INIT_CFG" -"FULL_CFG=INIT_CFG+SCAN_CFG+ADV_NCONN_CFG+ADV_CONN_CFG" -"L2CAP_COC_CFG=0x80" -"HOST_V41_MASK=0x80" -"CTRL_V41_MASK=0x7F" -"SCAN_REQ_RPT_CFG=0x2" -"PHY_2MBS_CFG=0x1" -"PHY_LR_CFG=0x02" -"HCD_NC_ADV_CFG=0x04" -"AE_CFG=0x08" -"PERIODIC_ADV_CFG=0x10" -"CHAN_ALGO2_CFG=0x40" -#"EXTENDED_STACK_SETTINGS_DEFAULT=0x0" -#"MASTER_GUARD_TIME_ENABLE=0x01" +BROADCASTER_CFG=0x01 +OBSERVER_CFG=0x02 +PERIPHERAL_CFG=0x04 +CENTRAL_CFG=0x08 + +ADV_NCONN_CFG=0x01 +ADV_CONN_CFG=0x02 +SCAN_CFG=0x04 +INIT_CFG=0x08 + +ADV_CFG=ADV_NCONN_CFG+ADV_CONN_CFG +LINK_CFG=ADV_CONN_CFG+INIT_CFG +FULL_CFG=INIT_CFG+SCAN_CFG+ADV_NCONN_CFG+ADV_CONN_CFG + +L2CAP_COC_CFG=0x80 +HOST_V41_MASK=0x80 + +CTRL_V41_MASK=0x7F + +SCAN_REQ_RPT_CFG=0x02 + +PHY_2MBPS_CFG=0x01 +PHY_LR_CFG=0x02 +HDC_NC_ADV_CFG=0x04 +AE_CFG=0x08 +PERIODIC_ADV_CFG=0x10 +AOA_AOD_CFG=0x20 +CHAN_ALGO2_CFG=0x40 + +EXTENDED_STACK_SETTINGS_DEFAULT=0x00 +MASTER_GUARD_TIME_ENABLE=0x01 ) target_compile_definitions(openthread-cc13xx_cc26xx From 90d7880bdd3d2a52ec72920fe9b63c5b3ed63137 Mon Sep 17 00:00:00 2001 From: Ryan-Brownf11 Date: Tue, 21 May 2024 15:55:25 -0500 Subject: [PATCH 18/19] Support CC2674R10, switch UART configuration from BLE to UART, and enable Coexistence --- boards.cmake | 6 + examples/apps/cli/CMakeLists.txt | 12 +- examples/apps/cli/bleAppTask.c | 220 +- examples/apps/cli/freertos_main.c | 16 +- script/build | 6 +- src/CC2674.syscfg | 206 ++ src/CMakeLists.txt | 24 +- src/dmm_scheduler.c | 1891 +++++++++++++++++ ...enthread.syscfg => openthread_orig.syscfg} | 74 +- src/spi_periph.c | 3 + src/system.c | 6 +- src/uart.c | 2 +- .../mbedtls/mbedtls-config-cc13x4_cc26x4.h | 4 +- .../ti_simplelink_sdk/repo_cc13xx_cc26xx | 2 +- 14 files changed, 2307 insertions(+), 165 deletions(-) create mode 100755 src/CC2674.syscfg create mode 100644 src/dmm_scheduler.c rename src/{openthread.syscfg => openthread_orig.syscfg} (81%) diff --git a/boards.cmake b/boards.cmake index b084b5a..ed25010 100644 --- a/boards.cmake +++ b/boards.cmake @@ -38,6 +38,7 @@ set(TI_BOARD_VALUES "LP_CC2652R7" "LP_CC2652RB" "LP_CC2652RSIP" + "CC2674R10" ) set_property(CACHE TI_SIMPLELINK_BOARD PROPERTY STRINGS ${TI_BOARD_VALUES}) @@ -106,6 +107,11 @@ elseif(TI_SIMPLELINK_BOARD STREQUAL "LP_EM_CC1354P10_6") set(TI_SIMPLELINK_DEVICE "cc13x4_cc26x4" ) set(TI_SIMPLELINK_FAMILY "cc13x4_cc26x4" ) set(TI_SIMPLELINK_ISA "m33f" ) + +elseif(TI_SIMPLELINK_BOARD STREQUAL "CC2674R10") + set(TI_SIMPLELINK_DEVICE "cc13x4_cc26x4" ) + set(TI_SIMPLELINK_FAMILY "cc13x4_cc26x4" ) + set(TI_SIMPLELINK_ISA "m33f" ) else() if(TI_PLATFORM STREQUAL "cc13xx_cc26xx" diff --git a/examples/apps/cli/CMakeLists.txt b/examples/apps/cli/CMakeLists.txt index 0ef157f..8df882d 100644 --- a/examples/apps/cli/CMakeLists.txt +++ b/examples/apps/cli/CMakeLists.txt @@ -63,7 +63,7 @@ set(COMMON_SOURCES cli_uart.cpp main.c bleAppTask.c - bleStackMenu.c + #bleStackMenu.c bget.c TI_heap_wrapper.c ble_user_config.c @@ -75,8 +75,8 @@ set(COMMON_SOURCES ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/util.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/rom/agama_r1/rom_init.c - ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/menu/two_btn_menu.c - ${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c + #${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/menu/two_btn_menu.c + #${TI_SIMPLELINK_SDK_DIR}/source/ti/display/Display.c ${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack_flash/common/cc26xx/board_key.c ${TI_SIMPLELINK_SDK_DIR}/kernel/nortos/dpl/SystemP_nortos.c #${TI_SIMPLELINK_SDK_DIR}/source/ti/ble5stack/common/cc26xx/freertos/bget.c @@ -92,9 +92,9 @@ else() message(FATAL_ERROR "Unsuported TI_SIMPLELINK_KERNEL: ${TI_SIMPLELINK_KERNEL}") endif() -#if(OT_FTD) -# include(ftd.cmake) -#endif() +if(OT_FTD) + include(ftd.cmake) +endif() if(OT_MTD) include(mtd.cmake) diff --git a/examples/apps/cli/bleAppTask.c b/examples/apps/cli/bleAppTask.c index e8cc710..c500bad 100644 --- a/examples/apps/cli/bleAppTask.c +++ b/examples/apps/cli/bleAppTask.c @@ -24,7 +24,7 @@ //#include //#include -#include +//#include //Wei /* add freertos code */ @@ -66,9 +66,9 @@ #include #ifdef PTM_MODE -#include "npi_task.h" // To allow RX event registration -#include "npi_ble.h" // To enable transmission of messages to UART -#include "icall_hci_tl.h" // To allow ICall HCI Transport Layer +//#include "npi_task.h" // To allow RX event registration +//#include "npi_ble.h" // To enable transmission of messages to UART +//#include "icall_hci_tl.h" // To allow ICall HCI Transport Layer #endif // PTM_MODE @@ -228,7 +228,7 @@ typedef struct mqd_t g_EventsQueueID; // Display Interface -Display_Handle dispHandle = NULL; +//Display_Handle dispHandle = NULL; // Task configuration //Wei @@ -366,8 +366,8 @@ static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, static void SimplePeripheral_connEvtCB(Gap_ConnEventRpt_t *pReport); static void SimplePeripheral_processConnEvt(Gap_ConnEventRpt_t *pReport); #ifdef PTM_MODE -void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg); // Declaration -static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len); // Declaration +//void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg); // Declaration +//static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len); // Declaration #endif // PTM_MODE /********************************************************************* @@ -549,14 +549,14 @@ static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) { if (pMyMsg->cmdStatus == HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE) { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, - "PHY Change failure, peer does not support this"); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, +// "PHY Change failure, peer does not support this"); } else { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, - "PHY Update Status Event: 0x%x", - pMyMsg->cmdStatus); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, +// "PHY Update Status Event: 0x%x", +// pMyMsg->cmdStatus); } SimplePeripheral_updatePHYStat(HCI_LE_SET_PHY, (uint8_t *)pMsg); @@ -580,18 +580,18 @@ static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) { if (pPUC->status != SUCCESS) { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, - "PHY Change failure"); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, +// "PHY Change failure"); } else { // Only symmetrical PHY is supported. // rxPhy should be equal to txPhy. - Display_printf(dispHandle, SP_ROW_STATUS_2, 0, - "PHY Updated to %s", - (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_1M) ? "1M" : - (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_2M) ? "2M" : - (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_CODED) ? "CODED" : "Unexpected PHY Value"); +// Display_printf(dispHandle, SP_ROW_STATUS_2, 0, +// "PHY Updated to %s", +// (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_1M) ? "1M" : +// (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_2M) ? "2M" : +// (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_CODED) ? "CODED" : "Unexpected PHY Value"); } SimplePeripheral_updatePHYStat(HCI_BLE_PHY_UPDATE_COMPLETE_EVENT, (uint8_t *)pMsg); @@ -613,7 +613,7 @@ static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) #ifdef PTM_MODE // Check for NPI Messages - hciPacket_t *pBuf = (hciPacket_t *)pMsg; +/* hciPacket_t *pBuf = (hciPacket_t *)pMsg; // Serialized HCI Event if (pBuf->hdr.event == HCI_CTRL_TO_HOST_EVENT) @@ -647,7 +647,7 @@ static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) default: break; } - } + }*/ #endif // PTM_MODE return (safeToDealloc); @@ -669,12 +669,12 @@ static uint8_t SimplePeripheral_processGATTMsg(gattMsgEvent_t *pMsg) // The app is informed in case it wants to drop the connection. // Display the opcode of the message that caused the violation. - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); } else if (pMsg->method == ATT_MTU_UPDATED_EVENT) { // MTU size updated - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); } // Free message payload. Needed only for ATT Protocol messages @@ -803,7 +803,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) // Set Device Info Service Parameter DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId); - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Initialized"); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Initialized"); BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_DEVICE_INIT_DONE_EVENT", 0); // Setup and start Advertising @@ -816,7 +816,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) //Wei if ( status != SUCCESS ) { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Failed to create the GAP Adv (%d:0x%02x)", status, status); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Failed to create the GAP Adv (%d:0x%02x)", status, status); vTaskDelay(pdMS_TO_TICKS(500)); } SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); @@ -871,9 +871,9 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) SIMPLEPERIPHERAL_ASSERT(status == SUCCESS); #endif // Display device address - Display_printf(dispHandle, SP_ROW_IDA, 0, "%s Addr: %s", - (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID", - Util_convertBdAddr2Str(pPkt->devAddr)); +// Display_printf(dispHandle, SP_ROW_IDA, 0, "%s Addr: %s", +// (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID", +// Util_convertBdAddr2Str(pPkt->devAddr)); if (addrMode > ADDRMODE_RANDOM) { @@ -887,7 +887,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) // READ_RPA_PERIOD, 0, true, // (void *)&argRpaRead); } - tbm_setItemStatus(&spMenuMain, SP_ITEM_AUTOCONNECT, TBM_ITEM_NONE); +// tbm_setItemStatus(&spMenuMain, SP_ITEM_AUTOCONNECT, TBM_ITEM_NONE); } break; @@ -900,8 +900,8 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_LINK_ESTABLISHED_EVENT", 0); // Display the amount of current connections uint8_t numActive = linkDB_NumActive(); - Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d", - (uint16_t)numActive); +// Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d", +// (uint16_t)numActive); if (pPkt->hdr.status == SUCCESS) { @@ -909,11 +909,11 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) SimplePeripheral_addConn(pPkt->connectionHandle); // Display the address of this connection - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connected to %s", - Util_convertBdAddr2Str(pPkt->devAddr)); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connected to %s", +// Util_convertBdAddr2Str(pPkt->devAddr)); // Enable connection selection option - tbm_setItemStatus(&spMenuMain, SP_ITEM_SELECT_CONN,SP_ITEM_AUTOCONNECT); +// tbm_setItemStatus(&spMenuMain, SP_ITEM_SELECT_CONN,SP_ITEM_AUTOCONNECT); // Start Periodic Clock. Util_startClock(&clkPeriodic); @@ -939,9 +939,9 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) // Display the amount of current connections uint8_t numActive = linkDB_NumActive(); - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Device Disconnected!"); - Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d", - (uint16_t)numActive); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Device Disconnected!"); +// Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d", +// (uint16_t)numActive); // Remove the connection from the list and disable RSSI if needed SimplePeripheral_removeConn(pPkt->connectionHandle); @@ -953,7 +953,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) Util_stopClock(&clkPeriodic); // Disable Connection Selection option - tbm_setItemStatus(&spMenuMain, SP_ITEM_AUTOCONNECT, SP_ITEM_SELECT_CONN); +// tbm_setItemStatus(&spMenuMain, SP_ITEM_AUTOCONNECT, SP_ITEM_SELECT_CONN); } BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : GAP msg: status=%d, opcode=%s\n", 0, "GAP_LINK_TERMINATED_EVENT"); @@ -962,7 +962,7 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); // Clear remaining lines - Display_clearLine(dispHandle, SP_ROW_CONNECTION); +// Display_clearLine(dispHandle, SP_ROW_CONNECTION); break; } @@ -1008,15 +1008,15 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) if(pPkt->status == SUCCESS) { // Display the address of the connection update - Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Link Param Updated: %s", - Util_convertBdAddr2Str(linkInfo.addr)); +// Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Link Param Updated: %s", +// Util_convertBdAddr2Str(linkInfo.addr)); } else { // Display the address of the connection update failure - Display_printf(dispHandle, SP_ROW_STATUS_2, 0, - "Link Param Update Failed 0x%x: %s", pPkt->opcode, - Util_convertBdAddr2Str(linkInfo.addr)); +// Display_printf(dispHandle, SP_ROW_STATUS_2, 0, +// "Link Param Update Failed 0x%x: %s", pPkt->opcode, +// Util_convertBdAddr2Str(linkInfo.addr)); } // Check if there are any queued parameter updates @@ -1043,16 +1043,16 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg) linkDB_GetInfo(pPkt->connectionHandle, &linkInfo); // Display the address of the connection update failure - Display_printf(dispHandle, SP_ROW_STATUS_2, 0, - "Peer Device's Update Request Rejected 0x%x: %s", pPkt->opcode, - Util_convertBdAddr2Str(linkInfo.addr)); +// Display_printf(dispHandle, SP_ROW_STATUS_2, 0, +// "Peer Device's Update Request Rejected 0x%x: %s", pPkt->opcode, +// Util_convertBdAddr2Str(linkInfo.addr)); break; } #endif default: - Display_clearLines(dispHandle, SP_ROW_STATUS_1, SP_ROW_STATUS_2); +// Display_clearLines(dispHandle, SP_ROW_STATUS_1, SP_ROW_STATUS_2); break; } } @@ -1099,13 +1099,13 @@ static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId) case SIMPLEPROFILE_CHAR1: SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue); - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 1: %d", (uint16_t)newValue); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 1: %d", (uint16_t)newValue); break; case SIMPLEPROFILE_CHAR3: SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue); - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 3: %d", (uint16_t)newValue); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 3: %d", (uint16_t)newValue); break; default: @@ -1163,8 +1163,8 @@ static void SimplePeripheral_updateRPA(void) if (memcmp(pRpaNew, rpa, B_ADDR_LEN)) { // If the RPA has changed, update the display - Display_printf(dispHandle, SP_ROW_RPA, 0, "RP Addr: %s", - Util_convertBdAddr2Str(pRpaNew)); +// Display_printf(dispHandle, SP_ROW_RPA, 0, "RP Addr: %s", +// Util_convertBdAddr2Str(pRpaNew)); memcpy(rpa, pRpaNew, B_ADDR_LEN); } } @@ -1246,7 +1246,7 @@ static void SimplePeripheral_handleKeys(uint8_t keys) // Check if the key is still pressed. Workaround for possible bouncing. if (GPIO_read(CONFIG_GPIO_BTN1) == 0) { - tbm_buttonLeft(); +// tbm_buttonLeft(); } } else if (keys & KEY_RIGHT) @@ -1254,7 +1254,7 @@ static void SimplePeripheral_handleKeys(uint8_t keys) // Check if the key is still pressed. Workaround for possible bouncing. if (GPIO_read(CONFIG_GPIO_BTN2) == 0) { - tbm_buttonRight(); +// tbm_buttonRight(); } } } @@ -1285,7 +1285,7 @@ bool SimplePeripheral_doSetConnPhy(uint8 index) uint8_t connIndex = SimplePeripheral_getConnIndex(menuConnHandle); if (connIndex >= MAX_NUM_BLE_CONNS) { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); return FALSE; } @@ -1301,8 +1301,8 @@ bool SimplePeripheral_doSetConnPhy(uint8 index) SimplePeripheral_setPhy(menuConnHandle, 0, phy[index], phy[index], 0); - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "PHY preference: %s", - TBM_GET_ACTION_DESC(&spMenuConnPhy, index)); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "PHY preference: %s", +// TBM_GET_ACTION_DESC(&spMenuConnPhy, index)); } else { @@ -1348,13 +1348,13 @@ static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData) { case GAP_EVT_ADV_START_AFTER_ENABLE: BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- GAP_EVT_ADV_START_AFTER_ENABLE", 0); - Display_printf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d Enabled", - *(uint8_t *)(pEventData->pBuf)); +// Display_printf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d Enabled", +// *(uint8_t *)(pEventData->pBuf)); break; case GAP_EVT_ADV_END_AFTER_DISABLE: - Display_doPrintf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d Disabled", - *(uint8_t *)(pEventData->pBuf)); +// Display_doPrintf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d Disabled", +// *(uint8_t *)(pEventData->pBuf)); break; case GAP_EVT_ADV_START: @@ -1368,8 +1368,8 @@ static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData) #ifndef Display_DISABLE_ALL GapAdv_setTerm_t *advSetTerm = (GapAdv_setTerm_t *)(pEventData->pBuf); - Display_printf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d disabled after conn %d", - advSetTerm->handle, advSetTerm->connHandle ); +// Display_printf(dispHandle, SP_ROW_ADVSTATE, 0, "Adv Set %d disabled after conn %d", +// advSetTerm->handle, advSetTerm->connHandle ); #endif } break; @@ -1467,39 +1467,39 @@ static void SimplePeripheral_processPairState(spPairStateData_t *pPairData) switch (state) { case GAPBOND_PAIRING_STATE_STARTED: - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing started"); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing started"); break; case GAPBOND_PAIRING_STATE_COMPLETE: if (status == SUCCESS) { - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing success"); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing success"); } else { - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing fail: %d", status); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Pairing fail: %d", status); } break; case GAPBOND_PAIRING_STATE_ENCRYPTED: if (status == SUCCESS) { - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Encryption success"); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Encryption success"); } else { - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Encryption failed: %d", status); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Encryption failed: %d", status); } break; case GAPBOND_PAIRING_STATE_BOND_SAVED: if (status == SUCCESS) { - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Bond save success"); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Bond save success"); } else { - Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Bond save failed: %d", status); +// Display_printf(dispHandle, SP_ROW_CONNECTION, 0, "Bond save failed: %d", status); } break; @@ -1520,8 +1520,8 @@ static void SimplePeripheral_processPasscode(spPasscodeData_t *pPasscodeData) // Display passcode to user if (pPasscodeData->uiOutputs != 0) { - Display_doPrintf(dispHandle, SP_ROW_CONNECTION, 0, "Passcode: %d", - B_APP_DEFAULT_PASSCODE); +// Display_doPrintf(dispHandle, SP_ROW_CONNECTION, 0, "Passcode: %d", +// B_APP_DEFAULT_PASSCODE); } // Send passcode response @@ -1559,7 +1559,7 @@ static void SimplePeripheral_processConnEvt(Gap_ConnEventRpt_t *pReport) if (connIndex >= MAX_NUM_BLE_CONNS) { - Display_doPrintf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); +// Display_doPrintf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); return; } @@ -1613,12 +1613,12 @@ bool SimplePeripheral_doSelectConn(uint8_t index) menuConnHandle = connList[index].connHandle; // Set the menu title and go to this connection's context - TBM_SET_TITLE(&spMenuPerConn, TBM_GET_ACTION_DESC(&spMenuSelectConn, index)); +// TBM_SET_TITLE(&spMenuPerConn, TBM_GET_ACTION_DESC(&spMenuSelectConn, index)); // Clear non-connection-related message - Display_clearLine(dispHandle, SP_ROW_CONNECTION); +// Display_clearLine(dispHandle, SP_ROW_CONNECTION); - tbm_goTo(&spMenuPerConn); +// tbm_goTo(&spMenuPerConn); return (true); } @@ -1649,7 +1649,7 @@ bool SimplePeripheral_doAutoConnect(uint8_t index) //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); autoConnect = AUTOCONNECT_GROUP_A; } - Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group A"); +// Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group A"); } else if (index == 2) { @@ -1665,7 +1665,7 @@ bool SimplePeripheral_doAutoConnect(uint8_t index) //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); autoConnect = AUTOCONNECT_GROUP_B; } - Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group B"); +// Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect enabled: Group B"); } else { @@ -1681,9 +1681,9 @@ bool SimplePeripheral_doAutoConnect(uint8_t index) //GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); autoConnect = AUTOCONNECT_DISABLE; } - Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect disabled"); +// Display_printf(dispHandle, SP_ROW_AC, 0, "AutoConnect disabled"); } - tbm_goTo(&spMenuMain); +// tbm_goTo(&spMenuMain); return (true); } @@ -1908,7 +1908,7 @@ static void SimplePeripheral_processParamUpdate(uint16_t connHandle) connIndex = SimplePeripheral_getConnIndex(connHandle); if (connIndex >= MAX_NUM_BLE_CONNS) { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); return; } @@ -1968,7 +1968,7 @@ static void SimplePeripheral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg) uint8_t index = SimplePeripheral_getConnIndex(handle); if (index >= MAX_NUM_BLE_CONNS) { - Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); +// Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connection handle is not in the connList !!!"); return; } @@ -2056,10 +2056,10 @@ static void SimplePeripheral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg) } // end of if (connList[index].phyCngRq == FALSE) } // end of if (rssi != LL_RSSI_NOT_AVAILABLE) - Display_printf(dispHandle, SP_ROW_RSSI, 0, - "RSSI:%d dBm, AVG RSSI:%d dBm", - (uint32_t)(rssi), - connList[index].rssiAvg); +// Display_printf(dispHandle, SP_ROW_RSSI, 0, +// "RSSI:%d dBm, AVG RSSI:%d dBm", +// (uint32_t)(rssi), +// connList[index].rssiAvg); } // end of if (status == SUCCESS) break; @@ -2069,8 +2069,8 @@ static void SimplePeripheral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg) { if (status == SUCCESS) { - Display_printf(dispHandle, SP_ROW_RSSI + 2, 0, "RXPh: %d, TXPh: %d", - pMsg->pReturnParam[3], pMsg->pReturnParam[4]); +// Display_printf(dispHandle, SP_ROW_RSSI + 2, 0, "RXPh: %d, TXPh: %d", +// pMsg->pReturnParam[3], pMsg->pReturnParam[4]); } break; } @@ -2307,13 +2307,13 @@ static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, if (pAddrs == NULL) { - TBM_SET_NUM_ITEM(&spMenuSelectConn, 0); +// TBM_SET_NUM_ITEM(&spMenuSelectConn, 0); } else { uint8_t i; - TBM_SET_NUM_ITEM(&spMenuSelectConn, MAX_NUM_BLE_CONNS); +// TBM_SET_NUM_ITEM(&spMenuSelectConn, MAX_NUM_BLE_CONNS); pAddrTemp = pAddrs; @@ -2329,14 +2329,14 @@ static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, // the address of this connection and enable the item. memcpy(pAddrTemp, Util_convertBdAddr2Str(linkInfo.addr), SP_ADDR_STR_SIZE); - TBM_SET_ACTION_DESC(&spMenuSelectConn, i, pAddrTemp); - tbm_setItemStatus(&spMenuSelectConn, (1 << i), SP_ITEM_NONE); +// TBM_SET_ACTION_DESC(&spMenuSelectConn, i, pAddrTemp); +// tbm_setItemStatus(&spMenuSelectConn, (1 << i), SP_ITEM_NONE); pAddrTemp += SP_ADDR_STR_SIZE; } else { // This connection is not active. Disable the corresponding menu item. - tbm_setItemStatus(&spMenuSelectConn, SP_ITEM_NONE, (1 << i)); +// tbm_setItemStatus(&spMenuSelectConn, SP_ITEM_NONE, (1 << i)); } } } @@ -2346,7 +2346,7 @@ static void SimplePeripheral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, // Now we are not in a specific connection's context // Clear connection-related message - Display_clearLine(dispHandle, SP_ROW_CONNECTION); +// Display_clearLine(dispHandle, SP_ROW_CONNECTION); } } /********************************************************************* @@ -2369,7 +2369,7 @@ static void bleStack_init(void) - bleStack_buildMenu(); +// bleStack_buildMenu(); //Register the current thread as an ICall dispatcher application ICall_registerApp(&selfEntity, &syncEvent); @@ -2482,28 +2482,28 @@ static void bleStack_init(void) // The type of display is configured based on the BOARD_DISPLAY_USE... // preprocessor definitions - dispHandle = Display_open(Display_Type_ANY, NULL); +// dispHandle = Display_open(Display_Type_ANY, NULL); // Initialize Two-Button Menu module - TBM_SET_TITLE(&spMenuMain, "Simple Peripheral"); - tbm_setItemStatus(&spMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL); +// TBM_SET_TITLE(&spMenuMain, "Simple Peripheral"); +// tbm_setItemStatus(&spMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL); - tbm_initTwoBtnMenu(dispHandle, &spMenuMain, 5, SimplePeripheral_menuSwitchCb); - Display_printf(dispHandle, SP_ROW_SEPARATOR_1, 0, "===================="); +// tbm_initTwoBtnMenu(dispHandle, &spMenuMain, 5, SimplePeripheral_menuSwitchCb); +// Display_printf(dispHandle, SP_ROW_SEPARATOR_1, 0, "===================="); -#ifdef PTM_MODE +//#ifdef PTM_MODE // Intercept NPI RX events. - NPITask_registerIncomingRXEventAppCB(simple_peripheral_handleNPIRxInterceptEvent, INTERCEPT); +// NPITask_registerIncomingRXEventAppCB(simple_peripheral_handleNPIRxInterceptEvent, INTERCEPT); // Register for Command Status information - HCI_TL_Init(NULL, (HCI_TL_CommandStatusCB_t) simple_peripheral_sendToNPI, NULL, selfEntity); +// HCI_TL_Init(NULL, (HCI_TL_CommandStatusCB_t) simple_peripheral_sendToNPI, NULL, selfEntity); // Register for Events - HCI_TL_getCmdResponderID(ICall_getLocalMsgEntityId(ICALL_SERVICE_CLASS_BLE_MSG, selfEntity)); +// HCI_TL_getCmdResponderID(ICall_getLocalMsgEntityId(ICALL_SERVICE_CLASS_BLE_MSG, selfEntity)); // Inform Stack to Initialize PTM - HCI_EXT_EnablePTMCmd(); -#endif // PTM_MODE +// HCI_EXT_EnablePTMCmd(); +//#endif // PTM_MODE } /********************************************************************* @@ -2537,7 +2537,7 @@ static void simple_peripheral_spin(void) * * @return none. */ -void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg) +/*void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg) { // Send Command via HCI TL HCI_TL_SendToStack(((NPIMSG_msg_t *)pMsg)->pBuf); @@ -2548,7 +2548,7 @@ void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg) // Free container. ICall_free(pMsg); } - +*/ /********************************************************************* * @fn simple_peripheral_sendToNPI * @@ -2560,7 +2560,7 @@ void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg) * * @return none */ -static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len) +/*static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len) { npiPkt_t *pNpiPkt = (npiPkt_t *)ICall_allocMsg(sizeof(npiPkt_t) + len); @@ -2577,7 +2577,7 @@ static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len) // Note: there is no need to free this packet. NPI will do that itself. NPITask_sendToHost((uint8_t *)pNpiPkt); } -} +}*/ #endif // PTM_MODE //self define AssertHandler diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 1c296ba..9d7775a 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -109,6 +109,16 @@ int main(void) AESECB_init(); SHA2_init(); + + GPIO_setConfig(CONFIG_GPIO_FEM_CHL, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH); + GPIO_setConfig(CONFIG_GPIO_FEM_CPS, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); + GPIO_setConfig(CONFIG_GPIO_FEM_CRX, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH); + GPIO_setConfig(CONFIG_GPIO_FEM_CSD, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH); + GPIO_setConfig(CONFIG_GPIO_FEM_CTX, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); + + GPIO_setMux(CONFIG_GPIO_FEM_CRX, IOC_PORT_RFC_GPO0); + GPIO_setMux(CONFIG_GPIO_FEM_CTX, IOC_PORT_RFC_GPO3); + GPIO_setMux(CONFIG_GPIO_FEM_CHL, IOC_PORT_RFC_GPO3); user0Cfg.appServiceInfo->timerTickPeriod = ICall_getTickPeriod(); user0Cfg.appServiceInfo->timerMaxMillisecond = ICall_getMaxMSecs(); @@ -140,14 +150,14 @@ int main(void) dmmSchedulerParams.indexTable = DMMPolicy_ApplicationPolicyTable.indexTable; DMMSch_open(&dmmSchedulerParams); bleAppTask_init(); -#if 0 +//#if 0 if (NULL == - xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 4, appStack, &appTaskBuffer)) + xTaskCreateStatic(vTaskCode, "APP", APP_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, appStack, &appTaskBuffer)) { while (1) ; } -#endif +//#endif vTaskStartScheduler(); diff --git a/script/build b/script/build index 303e9b9..fdf7cab 100755 --- a/script/build +++ b/script/build @@ -32,7 +32,7 @@ set -euxo pipefail OT_CMAKE_NINJA_TARGET=${OT_CMAKE_NINJA_TARGET:-} TI_SYSCONFIG_ROOT=${TI_SYSCONFIG_ROOT:-} -SYSCONFIG_VERSION=sysconfig_1.15.0 +SYSCONFIG_VERSION=sysconfig_1.16.2 SYSCONFIG_USER=~/ti/${SYSCONFIG_VERSION}/ SYSCONFIG_SYSTEM=/opt/ti/${SYSCONFIG_VERSION}/ @@ -63,6 +63,7 @@ readonly TI_LAUNCHPAD=( LP_CC2652RSIP LP_EM_CC1354P10_1 LP_EM_CC1354P10_6 + CC2674R10 ) readonly OT_SRCDIR="$(pwd)" @@ -158,7 +159,8 @@ main() options+=("-DCMAKE_TOOLCHAIN_FILE=src/arm-none-eabi-m4f.cmake") ;; LP_EM_CC1354P10_1 | \ - LP_EM_CC1354P10_6) + LP_EM_CC1354P10_6 | \ + CC2674R10) options+=("-DCMAKE_TOOLCHAIN_FILE=src/arm-none-eabi-m33.cmake") ;; esac diff --git a/src/CC2674.syscfg b/src/CC2674.syscfg new file mode 100755 index 0000000..dfcaba9 --- /dev/null +++ b/src/CC2674.syscfg @@ -0,0 +1,206 @@ +/** + * These arguments were used when this file was generated. They will be automatically applied on subsequent loads + * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. + * @cliArgs --device "CC2674R10RGZ" --package "RGZ" --part "Default" --rtos "freertos" --product "simplelink_cc13xx_cc26xx_sdk@7.10.01.24" + * @versions {"tool":"1.16.2+3028"} + */ + +/** + * Import the modules used in this configuration. + */ +const ble = scripting.addModule("/ti/ble5stack/ble"); +const CCFG = scripting.addModule("/ti/devices/CCFG"); +const custom = scripting.addModule("/ti/devices/radioconfig/custom"); +const rfdesign = scripting.addModule("/ti/devices/radioconfig/rfdesign"); +const dmm = scripting.addModule("/ti/dmm/dmm"); +const AESCCM = scripting.addModule("/ti/drivers/AESCCM", {}, false); +const AESCCM1 = AESCCM.addInstance(); +const AESCTRDRBG = scripting.addModule("/ti/drivers/AESCTRDRBG", {}, false); +const AESCTRDRBG1 = AESCTRDRBG.addInstance(); +const AESECB = scripting.addModule("/ti/drivers/AESECB"); +const AESECB1 = AESECB.addInstance(); +const AESECB2 = AESECB.addInstance(); +const DMA = scripting.addModule("/ti/drivers/DMA"); +const ECDH = scripting.addModule("/ti/drivers/ECDH"); +const ECDH1 = ECDH.addInstance(); +const ECDSA = scripting.addModule("/ti/drivers/ECDSA"); +const ECDSA1 = ECDSA.addInstance(); +const ECJPAKE = scripting.addModule("/ti/drivers/ECJPAKE"); +const ECJPAKE1 = ECJPAKE.addInstance(); +const GPIO = scripting.addModule("/ti/drivers/GPIO"); +const GPIO1 = GPIO.addInstance(); +const GPIO2 = GPIO.addInstance(); +const GPIO3 = GPIO.addInstance(); +const GPIO4 = GPIO.addInstance(); +const GPIO5 = GPIO.addInstance(); +const GPIO6 = GPIO.addInstance(); +const GPIO7 = GPIO.addInstance(); +const GPIO8 = GPIO.addInstance(); +const GPIO9 = GPIO.addInstance(); +const GPIO10 = GPIO.addInstance(); +const NVS = scripting.addModule("/ti/drivers/NVS"); +const NVS1 = NVS.addInstance(); +const Power = scripting.addModule("/ti/drivers/Power"); +const RF = scripting.addModule("/ti/drivers/RF"); +const SHA2 = scripting.addModule("/ti/drivers/SHA2"); +const SHA21 = SHA2.addInstance(); +const SPI = scripting.addModule("/ti/drivers/SPI"); +const SPI1 = SPI.addInstance(); +const TRNG = scripting.addModule("/ti/drivers/TRNG"); +const TRNG1 = TRNG.addInstance(); +const TRNG2 = TRNG.addInstance(); +const UART2 = scripting.addModule("/ti/drivers/UART2"); +const UART21 = UART2.addInstance(); +const Watchdog = scripting.addModule("/ti/drivers/Watchdog"); +const Watchdog1 = Watchdog.addInstance(); + +/** + * Write custom configuration values to the imported modules. + */ +ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param2"; +ble.connUpdateParamsPeripheral.$name = "ti_ble5stack_general_ble_conn_update_params0"; +ble.advSet1.$name = "ti_ble5stack_broadcaster_advertisement_set0"; +ble.advSet1.advParam1.$name = "ti_ble5stack_broadcaster_advertisement_params0"; +ble.advSet1.advData1.$name = "ti_ble5stack_broadcaster_advertisement_data0"; +ble.advSet1.advData1.GAP_ADTYPE_LOCAL_NAME_SHORT = true; +ble.advSet1.advData1.shortenedLocalName = "SP"; +ble.advSet1.advData1.GAP_ADTYPE_FLAGS = true; +ble.advSet1.advData1.advertisingFlags = ["GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED"]; +ble.advSet1.advData1.GAP_ADTYPE_16BIT_MORE = true; +ble.advSet1.advData1.numOfUUIDs16More = 1; +ble.advSet1.advData1.UUID016More = 0xFFF0; +ble.advSet1.scanRes1.$name = "ti_ble5stack_broadcaster_advertisement_data1"; +ble.advSet1.scanRes1.GAP_ADTYPE_LOCAL_NAME_COMPLETE = true; +ble.advSet1.scanRes1.GAP_ADTYPE_POWER_LEVEL = true; +ble.advSet1.scanRes1.GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE = true; +ble.advSet1.scanRes1.maxConnInterval = 130; +ble.advSet2.$name = "ti_ble5stack_broadcaster_advertisement_set1"; +ble.advSet2.advParam2.$name = "ti_ble5stack_broadcaster_advertisement_params1"; +ble.advSet2.advData2.$name = "ti_ble5stack_broadcaster_advertisement_data2"; +ble.advSet2.advData2.GAP_ADTYPE_LOCAL_NAME_SHORT = true; +ble.advSet2.advData2.shortenedLocalName = "SP"; +ble.advSet2.advData2.GAP_ADTYPE_FLAGS = true; +ble.advSet2.advData2.advertisingFlags = ["GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED"]; +ble.advSet2.advData2.GAP_ADTYPE_16BIT_MORE = true; +ble.advSet2.advData2.numOfUUIDs16More = 1; +ble.advSet2.advData2.UUID016More = 0xFFF0; +ble.advSet2.scanRes2.$name = "ti_ble5stack_broadcaster_advertisement_data3"; + +CCFG.xoscCapArrayDelta = 0xD5; +CCFG.enableBootloader = true; +CCFG.dioBootloaderBackdoor = 15; +CCFG.levelBootloaderBackdoor = "Active low"; +CCFG.srcClkLF = "Derived from HF XOSC"; +CCFG.ccfgTemplate.$name = "ti_devices_CCFG_CCFGCC26XXTemplate0"; + +custom.ieee = ["ieee154"]; +custom.radioConfigieee154.$name = "ti_devices_radioconfig_settings_ieee_15_40"; +custom.radioConfigieee154.txPower = "3"; +custom.radioConfigieee154.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param0"; +custom.radioConfigieee154.codeExportConfig.cmdList_ieee_15_4 = ["cmdFs","cmdIeeeCsma","cmdIeeeEdScan","cmdIeeeRx","cmdIeeeRxAck","cmdIeeeTx","cmdRadioSetup","cmdTxTest"]; +custom.radioConfigieee154.codeExportConfig.useConst = true; +custom.radioConfigieee154.codeExportConfig.useMulti = true; +custom.radioConfigieee154.codeExportConfig.symGenMethod = "Custom"; +custom.radioConfigieee154.codeExportConfig.cmdRadioSetup = "RF_cmdIeeeRadioSetup"; + +dmm.stackRoles = ["blePeripheral","custom1"]; +dmm.numApplicationStates = 2; +dmm.applicationState0 = "ANY"; +dmm.applicationState1 = "DMMPOLICY_BLE_IDLE"; +dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; +dmm.policyArray[0].custom1.$name = "ti_dmm_policy_stack_dmm_stack_custom0"; +dmm.policyArray[0].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble0"; +dmm.policyArray[0].blePeripheral.weight = 1; + +AESCCM1.$name = "CONFIG_AESCCM_0"; + +AESCTRDRBG1.$name = "CONFIG_AESCTRDRBG_0"; + +AESECB1.$name = "CONFIG_AESECB_MBEDTLS"; + +AESECB2.$name = "CONFIG_AESECB_0"; + +ECDH1.$name = "CONFIG_ECDH_0"; + +ECDSA1.$name = "CONFIG_ECDSA_0"; + +ECJPAKE1.$name = "CONFIG_ECJPAKE_0"; + +GPIO1.$name = "CONFIG_GPIO_BTN1"; +GPIO1.gpioPin.$assign = "DIO_13"; + +GPIO2.$name = "CONFIG_GPIO_BTN2"; +GPIO2.gpioPin.$assign = "DIO_14"; + +GPIO3.mode = "Output"; +GPIO3.$name = "CONFIG_GPIO_GLED"; +GPIO3.gpioPin.$assign = "DIO_16"; + +GPIO4.mode = "Output"; +GPIO4.$name = "CONFIG_GPIO_RLED"; +GPIO4.gpioPin.$assign = "DIO_6"; + +GPIO5.$name = "CONFIG_SPINEL_INT"; +GPIO5.mode = "Output"; +GPIO5.outputStrength = "High"; +GPIO5.initialOutputState = "High"; +GPIO5.gpioPin.$assign = "DIO_15"; + +GPIO6.mode = "Output"; +GPIO6.$name = "CONFIG_GPIO_FEM_CHL"; +GPIO6.initialOutputState = "High"; +GPIO6.gpioPin.$assign = "DIO_4"; + +GPIO7.mode = "Output"; +GPIO7.$name = "CONFIG_GPIO_FEM_CTX"; +GPIO7.initialOutputState = "High"; +GPIO7.gpioPin.$assign = "DIO_7"; + +GPIO8.$name = "CONFIG_GPIO_FEM_CPS"; +GPIO8.mode = "Output"; +GPIO8.gpioPin.$assign = "DIO_8"; + +GPIO9.$name = "CONFIG_GPIO_FEM_CRX"; +GPIO9.mode = "Output"; +GPIO9.gpioPin.$assign = "DIO_5"; + +GPIO10.$name = "CONFIG_GPIO_FEM_CSD"; +GPIO10.mode = "Output"; +GPIO10.initialOutputState = "High"; +GPIO10.gpioPin.$assign = "DIO_1"; + +NVS1.$name = "CONFIG_NVSINTERNAL"; +NVS1.internalFlash.$name = "ti_drivers_nvs_NVSCC26XX0"; +NVS1.internalFlash.regionBase = 0x52000; +NVS1.internalFlash.regionSize = 0x4000; + +RF.coexEnable = true; +RF.coexPhy = ["ieee_15_4"]; +RF.coexMode = "coexMode2Wire"; +RF.rfCoexRequestPin.$assign = "DIO_20"; +RF.rfCoexGrantPin.$assign = "DIO_19"; + +SHA21.$name = "CONFIG_SHA2_0"; + +SPI1.$name = "CONFIG_SPI_1"; +SPI1.mode = "Four Pin CS Active Low"; +SPI1.spi.$assign = "SPI3"; +SPI1.spi.sclkPin.$assign = "DIO_28"; +SPI1.spi.pociPin.$assign = "DIO_30"; +SPI1.spi.picoPin.$assign = "DIO_29"; +SPI1.spi.dmaRxChannel.$assign = "DMA_CH25"; +SPI1.spi.dmaTxChannel.$assign = "DMA_CH26"; +SPI1.spi.csnPin.$assign = "DIO_27"; + +TRNG1.$name = "CONFIG_TRNG_0"; + +TRNG2.$name = "CONFIG_TRNG_THREAD"; + +UART21.$name = "CONFIG_UART2_0"; +UART21.interruptPriority = "1"; +UART21.uart.$assign = "UART0"; +UART21.uart.txPin.$assign = "DIO_3"; +UART21.uart.rxPin.$assign = "DIO_2"; + +Watchdog1.$name = "CONFIG_WATCHDOG0"; +Watchdog1.watchdog.$assign = "WDT0"; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91e42d0..286f5ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,7 +29,7 @@ if(NOT $ENV{TI_SYSCONFIG_ROOT} STREQUAL "") set(TI_SYSCONFIG_INSTALL_DIR $ENV{TI_SYSCONFIG_ROOT} CACHE PATH "") else() - set(TI_SYSCONFIG_INSTALL_DIR $ENV{HOME}/ti/sysconfig_1.15.0 CACHE PATH "") + set(TI_SYSCONFIG_INSTALL_DIR $ENV{HOME}/ti/sysconfig_1.16.2 CACHE PATH "") endif() if(WIN32) @@ -197,11 +197,16 @@ add_custom_command( -s ${TI_SIMPLELINK_SDK_DIR}/.metadata/product.json -o ${CMAKE_CURRENT_BINARY_DIR}/syscfg --compiler gcc - --board /ti/boards/${TI_SIMPLELINK_BOARD} + #--board /ti/boards/${TI_SIMPLELINK_BOARD} --rtos ${TI_SIMPLELINK_KERNEL} - ${CMAKE_CURRENT_SOURCE_DIR}/openthread.syscfg + --device "CC2674R10RGZ" + --package "RGZ" + --part "Default" + #${CMAKE_CURRENT_SOURCE_DIR}/openthread.syscfg + ${CMAKE_CURRENT_SOURCE_DIR}/CC2674.syscfg DEPENDS - openthread.syscfg + #openthread.syscfg + CC2674.syscfg VERBATIM ) @@ -221,6 +226,7 @@ add_library(openthread-cc13xx_cc26xx system.c system.h uart.c + dmm_scheduler.c $ ) @@ -247,11 +253,15 @@ set(USR_COMPILE_DEFINITIONS "SYSCFG" "CC13X4" "CC13XX" - "POWER_SAVING" - "TBM_ACTIVE_ITEMS_ONLY" + "DeviceFamily_CC26X4" + "CC1354P10_1_LP" + "NVOCMP_NWSAMEITEM=1" + "NVOCMP_POSIX_MUTEX" +# "POWER_SAVING" +# "TBM_ACTIVE_ITEMS_ONLY" "STACK_LIBRARY" "EXTENDED_STACK_SETTINGS=EXTENDED_STACK_SETTINGS_DEFAULT" - "NPI_USE_UART" +# "NPI_USE_UART" "ICALL_EVENTS" "ICALL_JT" "ICALL_LITE" diff --git a/src/dmm_scheduler.c b/src/dmm_scheduler.c new file mode 100644 index 0000000..a0dbc7b --- /dev/null +++ b/src/dmm_scheduler.c @@ -0,0 +1,1891 @@ +/****************************************************************************** + + @file dmm_scheduler.c + + @brief Dual Mode Manager Scheduler + + Group: WCS LPC + Target Device: cc13xx_cc26xx + + ****************************************************************************** + + Copyright (c) 2019-2023, Texas Instruments Incorporated + + All rights reserved not granted herein. + Limited License. + + Texas Instruments Incorporated grants a world-wide, royalty-free, + non-exclusive license under copyrights and patents it now or hereafter + owns or controls to make, have made, use, import, offer to sell and sell + ("Utilize") this software subject to the terms herein. With respect to the + foregoing patent license, such license is granted solely to the extent that + any such patent is necessary to Utilize the software alone. The patent + license shall not apply to any combinations which include this software, + other than combinations with devices manufactured by or for TI ("TI + Devices"). No hardware patent is licensed hereunder. + + Redistributions must preserve existing copyright notices and reproduce + this license (including the above copyright notice and the disclaimer and + (if applicable) source code license limitations below) in the documentation + and/or other materials provided with the distribution. + + Redistribution and use in binary form, without modification, are permitted + provided that the following conditions are met: + + * No reverse engineering, decompilation, or disassembly of this software + is permitted with respect to any software provided in binary form. + * Any redistribution and use are licensed by TI for use only with TI Devices. + * Nothing shall obligate TI to provide you with source code for the software + licensed and provided to you in object code. + + If software source code is provided to you, modification and redistribution + of the source code are permitted provided that the following conditions are + met: + + * Any redistribution and use of the source code, including any resulting + derivative works, are licensed by TI for use only with TI Devices. + * Any redistribution and use of any object code compiled from the source + code and any resulting derivative works, are licensed by TI for use + only with TI Devices. + + Neither the name of Texas Instruments Incorporated nor the names of its + suppliers may be used to endorse or promote products derived from this + software without specific prior written permission. + + DISCLAIMER. + + THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + + + *****************************************************************************/ + +/***** Includes *****/ + +#ifndef FREERTOS +#include +#include +#include +#else +#include +#include +#endif + + +#include +#include + +#include +#include +#include +#include +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee_coex.h) +#include DeviceFamily_constructPath(driverlib/rf_data_entry.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) + +/***** Defines *****/ + +#define MAX_DMM_CLIENTS 2 + +#define RF_GET_SCHEDULE_MAP_CURR_CMD_IDX RF_SCH_MAP_CURRENT_CMD_OFFSET +#define RF_GET_SCHEDULE_MAP_PENDING_CMD_IDX (RF_SCH_MAP_PENDING_CMD_OFFSET) + +#define MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US 3000 +#define MIN_TIME_FOR_BLOCK_MODE_US 1000 + +#define DMM_DEFAULT_PHY_SWITCHING_MARGIN 314 //This should match the define in the RF driver +#define DMM_CONFICT_HOOK_DELAY 50 +#define STACK_RF_CB_LATENCY 500 // Latency of the stack callback + +#define RF_NUM_RAT_TICKS_IN_1_US 4 +/* (3/4)th of a full RAT cycle, in us */ +#define RF_DISPATCH_MAX_TIME_US (UINT32_MAX / RF_NUM_RAT_TICKS_IN_1_US * 3 / 4) +/* (1/4)th of a full RAT cycle, in us */ +#define RF_DISPATCH_MAX_TIME_WRAPAROUND_US (int32_t)(RF_DISPATCH_MAX_TIME_US - UINT32_MAX / RF_NUM_RAT_TICKS_IN_1_US) + +#define RadioTime_To_ms(radioTime) (radioTime / (4000000/1000)) +#define ms_To_RadioTime(ms) (ms * (4000000/1000)) + +/* full RAT cycle (~17.8 min) */ +#define MAX_RAT_TIME_US UINT32_MAX / RF_NUM_RAT_TICKS_IN_1_US +/* Schedule limit, (3/4)th of a full RAT cycle = ~13.4 min */ +#define SCHEDULE_LIMIT_US (MAX_RAT_TIME_US * 3/4) +/* Schedule limit, (3/4)th of a full RAT cycle = ~13.4 min */ +#define WRAPAROUND_LIMIT_US (MAX_RAT_TIME_US * 1/4) + +/* //! \brief Option to enable RX Resume in DMM scheduler + * defined: enable DMM scheduler Rx Resume + * not defined: Use the 15.4 stack Rx resume + */ +#define xDMM_RX_RESUME ///< Automatically resume RX commands that were preempted by DMM + + +/***** Type declarations *****/ +typedef struct { +#ifndef FREERTOS + Task_Handle* pTaskHndl; +#else + TaskHandle_t pTaskHndl; +#endif + DMMPolicy_StackRole stackRole; + RF_Handle clientHndl; + RF_ClientCallback rfClientCb; + bool isBlocked; +} DMMSch_Client_t; + +#ifdef DMM_RX_RESUME +typedef struct { + RF_Handle h; + RF_CmdHandle cmdHndl; + RF_Callback cb; + RF_EventMask bmEvent; + RF_ScheduleCmdParams SchParamsDmm; + RF_Op* pOp; + bool cmdResubmitted; + List_List* pPendQ; +} RxResumeCmd_t; +#endif + +/***** Variable declarations *****/ + +static DMMSch_Client_t dmmClients[MAX_DMM_CLIENTS] = {0}; +static uint32_t numDmmClients = 0; + +//Mutex for locking the RF driver resource +static SemaphoreP_Handle DmmSchedulerMutex; + + +#ifdef DMM_RX_RESUME +static RxResumeCmd_t rxResumeCmd; +static void rxResumeCmdCb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e); +#endif + +static bool dmmInitialized = false; + +static DMMSch_PreemptionCb preemptionCb; +static uint8_t preemptCnt = 0; + +/***** Private function definitions *****/ +#if !CONFLICT_FLUSH_ALL +static RF_ScheduleStatus dmmSinglePreemptCheck(RF_Cmd* pCmdBg, RF_Cmd* pCmdNew, List_List* pPendQueue); +static DMM_ConflictStatus dmmCmdConflictCheck(RF_Cmd* prevCmd, RF_Cmd* newCmd, RF_Cmd* nextCmd); +static bool conflictCheckWithNextCmd(RF_Cmd* pNewCmd, RF_Cmd* pNextCmd); +static bool conflictCheckWithPrevCmd(RF_Cmd* pPrevCmd, RF_Cmd* pNewCmd); +#endif +static DMMSch_Client_t* getClient(void); +static DMMPolicy_StackRole getClientStackRole(RF_Handle clientHndl); +static int32_t getSwitchingTimeInUs(RF_Cmd* prevCmd, RF_Cmd* nextCmd); +static uint32_t getAbsTimeGap (uint32_t time1, uint32_t time2); +static bool cmdInsertCheckAfterPrevCmd(RF_Cmd* pPrevCmd, RF_Cmd* pNewCmd); +static bool cmdInsertCheckBeforeNextCmd(RF_Cmd* pNewCmd, RF_Cmd* pNextCmd); +static bool dmmCmdInsertCheck(RF_Cmd* prevCmd, RF_Cmd* newCmd, RF_Cmd* nextCmd); +static RF_ScheduleStatus dmmScheduleCmd(RF_Cmd* pCmdBg, RF_Cmd* pCmdNew, List_List* pPendQueue); +static RF_Cmd* dmmCheckPreemption(RF_Handle h2Handle, RF_Cmd* pCmdNew, RF_Cmd* pCmdBg, List_List* pPendQueue, bool* isQEmpty); +static RF_Stat dmmPreemptCmd(RF_Cmd* pCmdPreempt); +static bool isClientMatched(RF_Handle h, RF_Cmd* pCmd); +static bool isNewCmdHigherPriority(RF_Cmd* pCmdNew, RF_Cmd* pCompareCmd); +static void dmmAdjustCmdSettings(RF_Cmd* pCmd ); +static bool isTimeInOrder (uint32_t earlyTime, uint32_t laterTime); +static void dmmAdjustCmdSettings(RF_Cmd* pCmd); +static bool isSameClient(RF_Cmd* pCmdNew, RF_Cmd* pCompareCmd); +static bool isBlockModeOn (RF_Cmd* pCmd); + +RF_ExecuteAction DMM_resolveConflictCb(RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue, bool bConflict, RF_Cmd* pConflictCmd); +RF_ScheduleStatus DMM_commandScheduleCb (RF_Cmd* pCmdNew, RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue); + +RFCC26XX_SchedulerPolicy RFCC26XX_schedulerPolicy = +{ + .submitHook = DMM_commandScheduleCb, + .executeHook = DMM_resolveConflictCb +}; + +#ifdef DMM_RX_RESUME +/* + * Only called within the wrapper function to run scheduleCmd within the callback workaround. + */ +/* + * This is the DMM level callback function wrapper that is passed to RF_scheduleCmd. + * This function wraps the regular client callback function passed from app/stack. + * The regular client callback function was saved in rxResumeCmd in schedule time. + * After the rf command is finished, this wrapper callback is called. Any DMM + * specific actions can be done here. After that, this function looks up and + * call the regular client callback function. + * + * Input: h - RF_Handle + * ch - Command handle + * e - event mask + * + * Return: void + */ +static void rxResumeCmdCb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) +{ + DMM_dbgLog4("rxResumeCmdCb: c=%x, ch=%x, e=0x%x-%x", h, ch, e >> 32, e & 0xFFFFFFFF); + + if(rxResumeCmd.cmdResubmitted == false) + { + if (rxResumeCmd.cmdHndl == ch) + { + if(e & RF_EventCmdPreempted) + { + bool IsRxInPendQ = false; + + /* check if a Rx command is in the Pend Q, if so, do not resume this Rx */ + RF_Cmd* pTemp = (RF_Cmd*)List_head(rxResumeCmd.pPendQ); + + while(pTemp != NULL) + { + if((rxResumeCmd.pOp->commandNo == pTemp->pOp->commandNo)&&(pTemp->pCb != rxResumeCmdCb )) + { + /* A Rx command has been scheduled by the stack, so DMM should not resume this Rx command. + * call the client callback so that the stack makes a decision*/ + IsRxInPendQ = true; + break; + } + pTemp = (RF_Cmd*)List_next((List_Elem*)pTemp); + } + + if(IsRxInPendQ) + { + /* call client callback */ + if (rxResumeCmd.cb) + { + /* call client command callback */ + rxResumeCmd.cb(h, ch, e); + } + /* invalidate RxResume Command */ + rxResumeCmd.cmdHndl = RF_SCHEDULE_CMD_ERROR; + rxResumeCmd.cmdResubmitted = false; + } + else + { + rfc_dataEntryGeneral_t* pDataEntry = NULL; + switch(rxResumeCmd.pOp->commandNo) + { + case (CMD_PROP_RX): + pDataEntry = (rfc_dataEntryGeneral_t*) (((rfc_CMD_PROP_RX_t*)(rxResumeCmd).pOp)->pQueue->pCurrEntry); + break; + case (CMD_PROP_RX_ADV): + pDataEntry = (rfc_dataEntryGeneral_t*) (((rfc_CMD_PROP_RX_ADV_t*)(rxResumeCmd).pOp)->pQueue->pCurrEntry); + break; + case (CMD_IEEE_RX): + pDataEntry = (rfc_dataEntryGeneral_t*) (((rfc_CMD_IEEE_RX_t*)(rxResumeCmd).pOp)->pRxQ->pCurrEntry); + break; + default: + break; + } + if( pDataEntry ) + { + pDataEntry->status = DATA_ENTRY_PENDING; + } + /* re-submit */ + RF_scheduleCmd(rxResumeCmd.h, rxResumeCmd.pOp, &rxResumeCmd.SchParamsDmm, rxResumeCmdCb, rxResumeCmd.bmEvent); + rxResumeCmd.cmdResubmitted = true; + } + } + else if( (e & RF_EventLastCmdDone) || (e & RF_EventCmdAborted) || (e & RF_EventCmdStopped) || (e & RF_EventCmdCancelled) ) + { + /* The Rx command has been finished, so no need to reschedule it */ + if (rxResumeCmd.cb) + { + /* call clients command callback */ + rxResumeCmd.cb(h, ch, e); + } + /* invalidate RxResume Command */ + rxResumeCmd.cmdHndl = RF_SCHEDULE_CMD_ERROR; + rxResumeCmd.cmdResubmitted = false; + } + } + } + else if (rxResumeCmd.cmdHndl == ch) + { + /* Note that the Rx command has been submitted */ + if (rxResumeCmd.cb) + { + /* call clients command callback */ + rxResumeCmd.cb(h, ch, e); + } + /* we may have more client callback before the command end's so only free the resumeCmd structure when it is ended */ + if( (e & RF_EventLastCmdDone) || (e & RF_EventCmdAborted) || (e & RF_EventCmdStopped) || (e & RF_EventCmdCancelled)|| (e & RF_EventCmdPreempted)) + { + /* invalidate RxResume Command */ + rxResumeCmd.cmdHndl = RF_SCHEDULE_CMD_ERROR; + rxResumeCmd.cmdResubmitted = false; + } + } +} +#endif //#ifdef DMM_RX_RESUME +/* + * Find which client is running in the current task + * + * Input: void + * + * Return: DMMSch_Client_t - DMM client pointer + * + */ + +static DMMSch_Client_t* getClient(void) +{ + uint32_t clientIdx; + /* map task handle to rfHandle returned */ + for(clientIdx = (uint32_t)0; clientIdx < MAX_DMM_CLIENTS; clientIdx++) + { + /* If the clients task equals this task and there is no + * client handle registered + */ +#ifndef FREERTOS + Task_Handle currentTask = Task_self(); + /* If the clients task equals this task and there is no + * client handle registered + */ + if (*(dmmClients[clientIdx].pTaskHndl) == currentTask) + { + return &(dmmClients[clientIdx]); + } + +#else + TaskHandle_t currentTask = xTaskGetCurrentTaskHandle(); + + if (dmmClients[clientIdx].pTaskHndl == currentTask) + { + return &(dmmClients[clientIdx]); + } +#endif + + } + + return NULL; +} + +/* + * Find the given client stack role + * + * Input: clientHndl - RF_Handle + * + * Return: DMMPolicy_StackRole - DMM stack role + * + */ +static DMMPolicy_StackRole getClientStackRole(RF_Handle clientHndl) +{ + uint32_t clientIdx; + + /* map task handle to rfHandle returned */ + for(clientIdx = (uint32_t)0; clientIdx < MAX_DMM_CLIENTS; clientIdx++) + { + /* If the clients task equals this ask and there is no + * client handle registered + */ + if (dmmClients[clientIdx].clientHndl == clientHndl) + + { + return dmmClients[clientIdx].stackRole; + } + } + + return DMMPolicy_StackRole_invalid; +} + +static void dmmAdjustCmdSettings(RF_Cmd* pCmd) +{ +#ifdef DMM_DEBUG_LOGGING + pCmd->pOp->startTrigger.pastTrig = true; +#endif + + if(DMMPolicy_getGPTStatus()) + { + /* GPT is available */ + if((pCmd->allowDelay ==RF_AllowDelayNone)||(pCmd->allowDelay ==RF_AllowDelayAny)) + { + pCmd->allowDelay =0; + } + } + else + { + /* GPT is not available. Legacy policy table */ + if(DMMPOLICY_TIME_CRITICAL == DMMPolicy_getTimeConstraintValue(pCmd->pClient->clientConfig.nID)) + { + pCmd->allowDelay =0; + } + else if(pCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + /* force to assign enough allowDelay even for the ABS commands + * this won't work for ABS command that master and device need to sync-up + * User should be aware of this*/ + pCmd->allowDelay = SCHEDULE_LIMIT_US*RF_NUM_RAT_TICKS_IN_1_US; + } + } + + if (pCmd->pOp->commandNo == CMD_BLE5_SLAVE) + { + ((rfc_CMD_BLE5_SLAVE_t*)(pCmd->pOp))->pParams->endTrigger.pastTrig = (uint8_t)1; + ((rfc_CMD_BLE5_SLAVE_t*)(pCmd->pOp))->pParams->timeoutTrigger.pastTrig = (uint8_t)1; + } +} + + +/* + * Check if the requesting command can be scheduled by preempting the running command + * or any of the commands in the queue belonging to the other client. + * + * Input: h2Handle - other client RF_Handle to be checked against + * pCmdNew - requesting command + * pCmdBg - Bg command + * pPendQueue - Pend Queue + * + * Return: RF_Cmd* - RF_Cmd pointer to the first command to be preempted. + * Return NULL pointer if there is no commands from the other client running/queued. + * isQEmpty = true when no command with h2 in the queue + * isQEmpty = false when there is a command with h2 in the queue + */ +static RF_Cmd* dmmCheckPreemption(RF_Handle h2Handle, RF_Cmd* pCmdNew, RF_Cmd* pCmdBg, List_List* pPendQueue, bool* isQEmpty) +{ + + /* use pPendQueue */ + bool canBePreempted = false; + RF_Cmd* pPreemptCmd = NULL; + RF_Cmd* pRefCmd = (RF_Cmd*)List_head(pPendQueue); + uint8_t cntH2ClientHigherthanNewCmd = 0; + + /* As default, no commands belonging to h2 is found in the queue */ + bool noH2Cmd = true; + + /* Check if we can preempt the Bg command */ + if (isClientMatched(h2Handle, pCmdBg)) + { + noH2Cmd = false; + canBePreempted = isNewCmdHigherPriority(pCmdNew, pCmdBg); + if (canBePreempted) + { + pPreemptCmd = pCmdBg; + } + } + + while (pRefCmd) + { + if (isClientMatched(h2Handle, pRefCmd)) + { + noH2Cmd = false; + canBePreempted = isNewCmdHigherPriority(pCmdNew, pRefCmd); + if((canBePreempted == true) && (pPreemptCmd == NULL)) + { + pPreemptCmd = pRefCmd; + } + /* Any individual command found in the queue which has higher priority + than the pCmdNew, the preemption criterion will clear the preemption pointer. */ + else if (canBePreempted == false) + { + cntH2ClientHigherthanNewCmd++; + } + } + pRefCmd = (RF_Cmd*)List_next((List_Elem*)pRefCmd); + } + + /* If there was no commands belonging to h2 in the queue, + return with the requesting command */ + if(noH2Cmd == true) + { + pPreemptCmd = NULL; // no preemption + + if (isQEmpty) + { + *isQEmpty = true; + } + } + else if(cntH2ClientHigherthanNewCmd > 0) + { + pPreemptCmd = NULL; // no preemption + } + else + { + if (isQEmpty) + { + *isQEmpty = false; + } + } + + return pPreemptCmd; +} + + +static RF_Stat dmmPreemptCmd(RF_Cmd* pCmdPreempt) +{ + + /* Abort the running command per default*/ + uint8_t stopOrAbort = 0; + + /* Abort multiple radio commands implicitly, mark them as preempted */ + return (RF_flushCmd(pCmdPreempt->pClient, RF_CMDHANDLE_FLUSH_ALL, + (stopOrAbort | (uint8_t)RF_ABORT_PREEMPTION))); +} + +/* check if the time1 and time2 are in order */ +static bool isTimeInOrder(uint32_t earlyTime, uint32_t laterTime) +{ + uint32_t timeGap; + bool result = false; + + if(laterTime > earlyTime) + { + timeGap = laterTime - earlyTime; + timeGap = MAX_RAT_TIME_US - timeGap; + if(timeGap < WRAPAROUND_LIMIT_US) { + result = false; + } else { + result = true; + } + } + else + { + // wrap around + timeGap = earlyTime - laterTime; + timeGap = MAX_RAT_TIME_US - timeGap; + if(timeGap < WRAPAROUND_LIMIT_US) { + result = true; + } + else { + result = false; + } + } + return(result); +} + +/* calculate the time gap between time1 and time2, assuming time2 comes after time1 */ +static uint32_t getAbsTimeGap (uint32_t earlyTime, uint32_t laterTime) +{ + uint32_t timeGap; + if(laterTime > earlyTime) + timeGap = laterTime - earlyTime; + else + { + // wrap around + timeGap = earlyTime - laterTime; + timeGap = MAX_RAT_TIME_US - timeGap; + } + return (timeGap); +} + +/* check if the time gap between time1 and time2 is bigger than the limitGap, assuming time2 comes after time1 */ +static bool isGapOK(uint32_t earlyTime, uint32_t laterTime, uint32_t limitGap) +{ + uint32_t time1InUS = (uint32_t)RF_convertRatTicksToUs(earlyTime); + uint32_t time2InUS = (uint32_t)RF_convertRatTicksToUs(laterTime); + if(isTimeInOrder(time1InUS, time2InUS)) + { + uint32_t timeGap = getAbsTimeGap(time1InUS, time2InUS); + if(timeGap > limitGap) + return true; + else + return false; + } + else + { + /* time is not in order */ + return false; + } +} + +static uint32_t getRequiredDelay(uint32_t earlyTime, uint32_t laterTime, uint32_t limitGap) +{ + uint32_t time1InUS = (uint32_t)RF_convertRatTicksToUs(earlyTime); + uint32_t time2InUS = (uint32_t)RF_convertRatTicksToUs(laterTime); + + if(isTimeInOrder(time1InUS, time2InUS)) + { + uint32_t timeGap = getAbsTimeGap(time1InUS, time2InUS); + if(timeGap > limitGap) + return (0); + else + return (uint32_t)((limitGap - timeGap)*RF_NUM_RAT_TICKS_IN_1_US); + } + else + { + /* time order is wrong, so required delay should be max, so that it cannot be scheudled */ + return ((uint32_t)(SCHEDULE_LIMIT_US*RF_NUM_RAT_TICKS_IN_1_US)); + } + +} + +/* check BLOCK from policy table */ +static bool isBlockModeOn (RF_Cmd* pCmd) +{ + uint32_t clientIdx; + bool status = false; + + if (pCmd) + { + for(clientIdx = (uint32_t)0; clientIdx < MAX_DMM_CLIENTS; clientIdx++) + { + if( pCmd->pClient == dmmClients[clientIdx].clientHndl) + { + status = dmmClients[clientIdx].isBlocked; + break; + } + } + } + + return(status); +} + +/***** Public function definitions *****/ + +/** @brief Function to initialize the DMMSch_Params + * * This function is currently a placeholder. To follow the convention, + * we provide this function for application level. + * + * @param params An pointer to RF_Params structure for + * initialization + * + * Defaults values are: + */ +void DMMSch_Params_init(DMMSch_Params *params) +{ + memset(params, 0, sizeof(DMMSch_Params)); +} + +/** @brief Function that initializes the DMMSch module + * + */ +void DMMSch_init(void) +{ + // create semaphore instance if not already created + if (!dmmInitialized) + { + //Create a semaphore for blocking commands + SemaphoreP_Params semParams; + + // init params + SemaphoreP_Params_init(&semParams); + + DmmSchedulerMutex = SemaphoreP_create(0, &semParams); + + /* Assert */ + DebugP_assert(DmmSchedulerMutex != NULL); + + +#ifdef DMM_RX_RESUME + /* init cmd callback table */ + rxResumeCmd.cmdHndl = RF_SCHEDULE_CMD_ERROR; + rxResumeCmd.cmdResubmitted = false; + rxResumeCmd.pPendQ = NULL; + rxResumeCmd.pOp = NULL; +#endif + dmmInitialized = true; + + SemaphoreP_post(DmmSchedulerMutex); + } +} + +/** @brief Function to open the DMMSch module + * This function is currently a placeholder. To follow the convention, + * we provide this function for application level. In the future, + * when it is needed, we can add more code to this function. + * + * @param params An pointer to RF_Params structure for initialization + */ +void DMMSch_open(DMMSch_Params *params) +{ + DebugP_assert(params != NULL); + +} + +/** @brief Register a DMM Scheduler client + * + * @param pTaskHndl - Task handle that the stack is running in, used to map the + * RF Client handle to a stack role + * + * @param StackRole - stack role associated with Task handle + */ +#ifndef FREERTOS +void DMMSch_registerClient(Task_Handle* pTaskHndl, DMMPolicy_StackRole StackRole) +#else +void DMMSch_registerClient(TaskHandle_t pTaskHndl, DMMPolicy_StackRole StackRole) +#endif +{ + if(numDmmClients < MAX_DMM_CLIENTS) + { + dmmClients[numDmmClients].pTaskHndl = pTaskHndl; + dmmClients[numDmmClients].stackRole = StackRole; + + numDmmClients++; + } +} + +/** @brief Turn on Block mode. It aborts the current command if it belongs to the same client. + * + * @param stackRole stack role associated with Task handle + * @return true: success, false: the stack role cannot be found + */ +bool DMMSch_setBlockModeOn(DMMPolicy_StackRole stackRole) { + + uint32_t clientIdx; + for(clientIdx = (uint32_t)0; clientIdx < MAX_DMM_CLIENTS; clientIdx++) + { + /* find the stack role and set the isBlocked flag true */ + if (dmmClients[clientIdx].stackRole == stackRole) + { + dmmClients[clientIdx].isBlocked = true; + + /* Abort the running command */ + RF_InfoVal info; + + if(RF_StatSuccess == RF_getInfo(dmmClients[clientIdx].clientHndl, RF_GET_CURR_CMD, &info)) { + + uint8_t stopOrAbort = 0; + + RF_cancelCmd(dmmClients[clientIdx].clientHndl, info.ch, (stopOrAbort | (uint8_t)RF_ABORT_PREEMPTION)); + } + return (true); + } + } + // incorrect stack role + return (false); +} + +/** @brief Turn off Block mode + * + * @param stackRole stack role associated with Task handle + * @return true: success, false: the stack role cannot be found + */ +bool DMMSch_setBlockModeOff(DMMPolicy_StackRole stackRole) { + + uint32_t clientIdx; + for(clientIdx = (uint32_t)0; clientIdx < MAX_DMM_CLIENTS; clientIdx++) + { + /* find the stack role and set the isBlocked flag false */ + if (dmmClients[clientIdx].stackRole == stackRole) + { + dmmClients[clientIdx].isBlocked = false; + return (true); + } + } + // incorrect stack role + return(false); +} + +/** @brief Get Block mode status + * + * @param StackRole stack role associated with Task handle + * + * return True: Block Mode is On, False: Block Mode is Off + */ +bool DMMSch_getBlockModeStatus(DMMPolicy_StackRole stackRole) { + + uint32_t clientIdx; + for(clientIdx = (uint32_t)0; clientIdx < MAX_DMM_CLIENTS; clientIdx++) + { + /* find the stack role and return isBlocked flag*/ + if (dmmClients[clientIdx].stackRole == stackRole) + { + return (dmmClients[clientIdx].isBlocked); + } + } + + // If stackRole isn't found, return false + return false; +} + +/** @brief allows policy manager to register a callback on command preemption + * + * @param dmmSchPreemptionCb callback to register + */ +void DMMSch_registerPreemptionCb(DMMSch_PreemptionCb dmmSchPreemptionCb) +{ + preemptionCb = dmmSchPreemptionCb; +} + +/** @brief Intercepts calls from a stack to RF_postCmd (re-mapped to DMMSch_rfOpen), + * The DMMSch module uses this to tie + * + * @param pObj Pointer to a #RF_Object that will hold the state for this + * RF client. The object must be in persistent and writeable + * memory. + * @param pRfMode Pointer to a #RF_Mode struct holding PHY information + * @param pRadioSetup Pointer to the radio setup command used for this client. + * This is re-executed by the RF Driver on each power-up. + * @param params Pointer to an RF_Params object with the desired driver configuration. + * A NULL pointer results in the default configuration being loaded. + * @return A handle for further RF driver calls on success. Otherwise NULL. + */ +RF_Handle DMMSch_rfOpen(RF_Object *pObj, RF_Mode *pRfMode, RF_RadioSetup *pOpSetup, RF_Params *params) +{ + DMMSch_Client_t *dmmClient; + RF_Handle clientHndl = NULL; + uint32_t phySwitchingTime; + /* block other callers until RF driver is opened for this client */ + SemaphoreP_pend(DmmSchedulerMutex, SemaphoreP_WAIT_FOREVER); + + /* override the RF_Mode and patches for multi-mode operation */ + pRfMode->cpePatchFxn = rf_patch_cpe_ieee_coex; +#if defined(CC13X2R1_LAUNCHXL) || defined(CC13X2P1_LAUNCHXL) + pRfMode->rfMode = (uint8_t)RF_MODE_AUTO; +#else + pRfMode->rfMode = (uint8_t)RF_MODE_MULTIPLE; +#endif + + dmmClient = getClient(); + + clientHndl = RF_open(pObj, pRfMode, pOpSetup, params); + + /* if we found the client then save the handle, note that for 15.4 SLR Phy + * mode the RF_open is called first from macTask and called again from the MAC app task. + * The same RF Handle value (clientHndl) is used from both calls. So, we can save only once. + * + */ + if(dmmClient) + { + dmmClient->clientHndl = clientHndl; + DMMPolicy_setStackID(params->nID, dmmClient->stackRole); + dmmClient->isBlocked = false; + } + //release mutex + SemaphoreP_post(DmmSchedulerMutex); + + phySwitchingTime = (STACK_RF_CB_LATENCY + DMM_CONFICT_HOOK_DELAY + DMM_DEFAULT_PHY_SWITCHING_MARGIN); + RF_control(clientHndl, RF_CTRL_SET_PHYSWITCHING_DURATION_MARGIN, &phySwitchingTime); + + return clientHndl; +} + +/** + * @brief Handles calls from a stack to RF_postCmd (re-mapped to DMMSch_postCmd), + * adjusts timing as necessary and schedules then accordingly with RF_scheduleCmd. + * + * @sa RF_pendCmd(), RF_runCmd(), RF_scheduleCmd(), RF_RF_cancelCmd(), RF_flushCmd(), RF_getCmdOp() + * + * @param h Driver handle previously returned by RF_open() + * @param pOp Pointer to the RF operation command. + * @param ePri Priority of this RF command (used for arbitration in multi-client systems) + * @param pCb Callback function called during command execution and upon completion. + * If RF_postCmd() fails, no callback is made. + * @param bmEvent Bitmask of events that will trigger the callback or that can be pended on. + * @return A handle to the RF command. Return value of RF_ALLOC_ERROR indicates error. + */ +RF_CmdHandle DMMSch_rfPostCmd(RF_Handle h, RF_Op* pOp, RF_Priority ePri, RF_Callback pCb, RF_EventMask bmEvent) +{ + RF_CmdHandle cmdHndl; + RF_ScheduleCmdParams schParams; + uint32_t hwiKey, swiKey; + + /* use default values for RF_ScheduleCmdParams for now. allowed delay will be determined based on trigger Type, priority will be based on policy table */ + schParams.allowDelay = RF_AllowDelayAny; + schParams.endTime =0; + + hwiKey = HwiP_disable(); + swiKey = SwiP_disable(); + + /* simply call RF driver. RF driver will invoke the DMM hook function later. */ + cmdHndl = RF_scheduleCmd(h, pOp, &schParams, pCb, bmEvent); + + SwiP_restore(swiKey); + HwiP_restore(hwiKey); + + return cmdHndl; +} + +/** + * @brief Handles calls from a stack to RF_scheduleCmd (re-mapped to DMMSch_scheduleCmd), + * adjusts timing as necessary and schedules then accordingly with RF_scheduleCmd. + * + * @param h Handle previously returned by RF_open() + * @param pOp Pointer to the #RF_Op. Must normally be in persistent and writeable memory + * @param pSchParams Pointer to the schedule command parameter structure + * @param pCb Callback function called upon command completion (and some other events). + * If RF_scheduleCmd() fails no callback is made + * @param bmEvent Bitmask of events that will trigger the callback. + * @return A handle to the RF command. Return value of RF_ALLOC_ERROR indicates error. + */ +uint8_t schDgbFlg = 0; +uint8_t schBleFLushFlg = 1; +uint32_t pSchErr = 0; +RF_CmdHandle DMMSch_rfScheduleCmd(RF_Handle h, RF_Op* pOp, RF_ScheduleCmdParams *pSchParams, RF_Callback pCb, RF_EventMask bmEvent) +{ + RF_CmdHandle cmdHndl; + uint32_t hwiKey, swiKey; + + hwiKey = HwiP_disable(); + swiKey = SwiP_disable(); + + /* simply call RF driver. RF driver will invoke the DMM hook function later. */ + cmdHndl = RF_scheduleCmd(h, pOp, pSchParams, pCb, bmEvent); + + SwiP_restore(swiKey); + HwiP_restore(hwiKey); + + return cmdHndl; +} + +/** @brief Handles calls from a stack to RF_runCmd (re-mapped to DMMSch_runCmd), + * adjusts timing as necessary and schedules then accordingly with RF_scheduleCmd. + * + * @param h Driver handle previously returned by RF_open() + * @param pOp Pointer to the RF operation command. + * @param ePri Priority of this RF command (used for arbitration in multi-client systems) + * @param pCb Callback function called during command execution and upon completion. + * If RF_runCmd() fails, no callback is made. + * @param bmEvent Bitmask of events that will trigger the callback or that can be pended on. + * @return The relevant termination event. + */ +RF_EventMask DMMSch_rfRunCmd(RF_Handle h, RF_Op* pOp, RF_Priority ePri, RF_Callback pCb, RF_EventMask bmEvent) +{ + return RF_runCmd(h, pOp, ePri, pCb, bmEvent); +} + +/** + * @brief Handles calls from a stack to RF_runScheduleCmd (re-mapped to DMMSch_runScheduleCmd), + * adjusts timing as necessary and schedules then accordingly with RF_scheduleCmd. + * + * + * @param h Handle previously returned by RF_open() + * @param pOp Pointer to the #RF_Op. Must normally be in persistent and writeable memory + * @param pSchParams Pointer to the schedule command parameter structure + * @param pCb Callback function called upon command completion (and some other events). + * If RF_runScheduleCmd() fails, no callback is made. + * @param bmEvent Bitmask of events that will trigger the callback. + * @return The relevant command completed event. + */ +RF_EventMask DMMSch_rfRunScheduleCmd(RF_Handle h, RF_Op* pOp, RF_ScheduleCmdParams *pSchParams, RF_Callback pCb, RF_EventMask bmEvent) +{ + return RF_runScheduleCmd(h, pOp, pSchParams, pCb, bmEvent); +} + +/** + * @brief Abort/stop/cancel single command in command queue. + * + * If command is running, aborts/stops it and posts callback for the + * aborted/stopped command.
+ * If command has not yet run, cancels it it and posts callback for the + * cancelled command.
+ * If command has already run or been aborted/stopped/cancelled, has no effect.
+ * If RF_cancelCmd is called from a Swi context with same or higher priority + * than RF Driver Swi, when the RF core is powered OFF -> the cancel callback will be delayed + * until the next power-up cycle.
+ * + * @note Calling context : Task/SWI + * + * @param h Handle previously returned by RF_open() + * @param ch Command handle previously returned by RF_postCmd(). + * @param mode 1: Stop gracefully, 0: abort abruptly + * @return RF_Stat indicates if command was successfully completed + */ +RF_Stat DMMSch_rfCancelCmd(RF_Handle h, RF_CmdHandle ch, uint8_t mode) +{ + RF_Stat status = RF_StatError; + + DMM_dbgLog5("Cancel: Stack:%x ch:%x mode:%x", h->clientConfig.nID, ch, mode, 0, 0); + +#ifdef DMM_RX_RESUME + if (rxResumeCmd.cmdHndl == ch) + { + rxResumeCmd.cmdResubmitted = true; + status = RF_cancelCmd(h, ch, mode); + DMM_dbgLog1("DMMSch_rfCancelCmd: RF_cancelCmd status %x", status); + + if(status != RF_StatSuccess) + { + /* command was not running so flush pendQ */ + RF_flushCmd(h, ch, mode); + status = RF_StatSuccess; + } + } + else + { + status = RF_cancelCmd(h, ch, mode); + } +#else + status = RF_cancelCmd(h, ch, mode); +#endif + return status; +} + +/** + * @brief Abort/stop/cancel command and any subsequent commands in command queue. + * + * If command is running, aborts/stops it and then cancels all later commands in queue.
+ * If command has not yet run, cancels it and all later commands in queue.
+ * If command has already run or been aborted/stopped/cancelled, has no effect.
+ * The callbacks for all cancelled commands are issued in chronological order.
+ * If RF_flushCmd is called from a Swi context with same or higher priority + * than RF Driver Swi, when the RF core is powered OFF -> the cancel callback will be delayed + * until the next power-up cycle.
+ * + * @note Calling context : Task/SWI + * + * @param h Handle previously returned by RF_open() + * @param ch Command handle previously returned by RF_postCmd(). + * @param mode 1: Stop gracefully, 0: abort abruptly + * @return RF_Stat indicates if command was successfully completed + */ +RF_Stat DMMSch_rfFlushCmd(RF_Handle h, RF_CmdHandle ch, uint8_t mode) +{ + DMM_dbgLog3("DMMSch_rfFlushCmd: c=%x, ch=%x, mode=%x", h, ch, mode); + +#ifdef DMM_RX_RESUME + if (rxResumeCmd.cmdHndl == ch) + { + /* force submitted flag in case it is the process of being submitted */ + rxResumeCmd.cmdResubmitted = true; + } +#endif + + return RF_flushCmd(h, ch, mode); +} + +/** + * @brief Send any Immediate command.
+ * + * Immediate Comamnd is send to RDBELL, if radio is active and the RF_Handle points + * to the current client.
+ * In other appropriate RF_Stat values are returned.
+ * + * @note Calling context : Task/SWI/HWI + * + * @param h Handle previously returned by RF_open() + * @param pCmdStruct Pointer to the immediate command structure + * @return RF_Stat indicates if command was successfully completed +*/ +RF_Stat DMMSch_rfRunImmediateCmd(RF_Handle h, uint32_t* pCmdStruct) +{ + return RF_runImmediateCmd(h, pCmdStruct); +} + +/** + * @brief Send any Direct command.
+ * + * Direct Comamnd value is send to RDBELL immediately, if radio is active and + * the RF_Handle point to the current client.
+ * In other appropriate RF_Stat values are returned.
+ * + * @note Calling context : Task/SWI/HWI + * + * @param h Handle previously returned by RF_open() + * @param cmd Direct command value. + * @return RF_Stat indicates if command was successfully completed. +*/ +RF_Stat DMMSch_rfRunDirectCmd(RF_Handle h, uint32_t cmd) +{ + return RF_runDirectCmd(h, cmd); +} + +RF_Stat DMMSch_rfRequestAccess(RF_Handle h, RF_AccessParams *pParams) +{ + /* request access RF API should not be used in DMM */ + return RF_StatError; +} + +/** + * Determines the method to resolve the schedule conflicts. + * + * Input: pCmdBg - Running background command. + * pCmdFg - Running foreground command. + * pPendQueue - Pointer to the head structure of pend queue. + * pDoneQueue - Pointer to the head structure of done queue. + * bConflict - Boolean to indicate a conflict. + * pConflictCmd - Pointer to the conflict command. + * Return: RF_Conflict - Identifies the method to resolve the conflict. + */ +RF_ExecuteAction DMM_resolveConflictCb(RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue, bool bConflict, RF_Cmd* pConflictCmd) +{ + RF_ExecuteAction conflictResolution = RF_ExecuteActionNone; + RF_Cmd* pPendCmd = NULL; + RF_Cmd* pSearchCmd = (RF_Cmd*)List_head(pPendQueue); + + if(!bConflict) + { + /* check BLOCK mode first if no conflict */ + /* note that the pendQ cannot be NULL here */ + if (isBlockModeOn(pSearchCmd)) { + conflictResolution = RF_ExecuteActionRejectIncoming; + } + } + else + { + /* Look for the first abs command, conflicts will only happen if the next + * command is an abs command. TRIG_NOW commands can always be delayed + * there must be an ABS command if bConflict = true */ + while (pSearchCmd) + { + if (pSearchCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + pPendCmd = pSearchCmd; + break; + } + else + { + pSearchCmd = (RF_Cmd*)List_next((List_Elem*)pSearchCmd); + } + } + + /* check BLOCK mode first even for the case of a conflict */ + if (isBlockModeOn(pSearchCmd)) + { + conflictResolution = RF_ExecuteActionRejectIncoming; + } + else + { + /* Normal conflict Hook function */ + if(pCmdBg && pPendCmd) + { + if(isSameClient(pPendCmd, pCmdBg)) + { + /* the commands belong to the same stack, no conflict */ + } + else if((!isNewCmdHigherPriority(pPendCmd, pCmdBg)) || (pCmdFg && (!isNewCmdHigherPriority(pPendCmd, pCmdFg)))) + { + conflictResolution = RF_ExecuteActionRejectIncoming; + if(preemptionCb) + { + /* inform policy manager that a stack command has been preempted */ + preemptionCb(getClientStackRole(pPendCmd->pClient)); + } + } + else + { + conflictResolution = RF_ExecuteActionAbortOngoing; + if(preemptionCb) + { + /* inform policy manager that a stack command has been preempted */ + preemptionCb(getClientStackRole(pCmdBg->pClient)); + } + + #ifdef DMM_RX_RESUME + /* for rx resume */ + if(pCmdBg->pCb && ( (pCmdBg->pOp->commandNo == CMD_IEEE_RX) || + (pCmdBg->pOp->commandNo == CMD_PROP_RX_ADV) || + (pCmdBg->pOp->commandNo == CMD_PROP_RX)) ) + { + uint32_t key; + RF_ScheduleCmdParams SchParamsResubmit; + + SchParamsResubmit.allowDelay = pCmdBg->allowDelay; + SchParamsResubmit.endTime = pCmdBg->endTime; + + key = HwiP_disable(); + + /* since in this new scheduler, we re-submit the command + * immediately, we just need to save "cmdHndl" and "pCb" for + * dmm version call back function to find the command's original + * callback. */ + rxResumeCmd.h = pCmdBg->pClient; + rxResumeCmd.cmdHndl = pCmdBg->ch; + + /* Check that the client callback has not been set to + * rxResumeCmdCb already. This will happen if a previously + * resumed command is being resumed again. We do not want to + * rxResumeCmd.cb to rxResumeCmdCb or as it will reenter + * rxResumeCmdCb in a tight loop */ + if(pCmdBg->pCb != rxResumeCmdCb) + { + /* save the original callback in the rxResumeCmd structure. + * So the re-submitted command callback is the original one. + * Then when the command has any events other than abort, the + * original callback will be invoked. */ + rxResumeCmd.cb = pCmdBg->pCb; + + /* change the client callback to DMM version of the callback so + * that the stack won't be notified for this current abort action + * (because it will be resumed by DMM soon). */ + pCmdBg->pCb = rxResumeCmdCb; + } + + rxResumeCmd.bmEvent = pCmdBg->bmEvent; + rxResumeCmd.SchParamsDmm.endTime = SchParamsResubmit.endTime; + rxResumeCmd.SchParamsDmm.allowDelay = SchParamsResubmit.allowDelay; + rxResumeCmd.SchParamsDmm.activityInfo = pCmdBg->activityInfo; + rxResumeCmd.SchParamsDmm.duration = pCmdBg->duration; + rxResumeCmd.SchParamsDmm.startType = RF_StartNotSpecified; /* Trig Now for resumed Rx */ + rxResumeCmd.SchParamsDmm.startTime = 0; /* Trig Now for resumed Rx */ + rxResumeCmd.pOp = pCmdBg->pOp; + rxResumeCmd.pOp->startTrigger.triggerType = TRIG_NOW; /* Trig Now for resumed Rx */ + rxResumeCmd.cmdResubmitted = false; + rxResumeCmd.pPendQ = pPendQueue; + + /* Exit critical section. */ + HwiP_restore(key); + } + #endif // #ifdef DMM_RX_RESUME + } //if(isSameClient(pPendCmd, pCmdBg)) + } + } //if (isBlockModeOn(pSearchCmd)) + } //if(!bConflict) + + DMM_dbgLog5("conflictCb: Bg:%x Pend:%x ID%x:%x s%x", + pCmdBg->pOp->commandNo, pPendCmd->pOp->commandNo, pCmdBg->pClient->clientConfig.nID, pPendCmd->pClient->clientConfig.nID, conflictResolution); + + return(conflictResolution); +} + +/** + * Sorts and adds command to the RF driver internal command queue. + * + * Input: pCmdNew - Pointer to the command to be submitted. + * pCmdBg - Running background command. + * pCmdFg - Running foreground command. + * pPendQueue - Pointer to the head structure of pend queue. + * pDoneQueue - Pointer to the head structure of done queue. + * Return: RF_ScheduleStatus - Identifies the success or failure of enquing. + */ +RF_ScheduleStatus DMM_commandScheduleCb(RF_Cmd* pCmdNew, RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue) +{ +// RF_Cmd* pHeadCmd = (RF_Cmd*)List_head(pPendQueue); + + RF_ScheduleStatus schStatus = RF_ScheduleStatusError; + RF_Handle h, h2; + RF_Stat rfPreemptStats = RF_StatError; + bool isQEmpty = false; + + /* check BLOCK mode */ + if (isBlockModeOn(pCmdNew)) + { + if(pCmdNew->pOp->startTrigger.triggerType == TRIG_ABSTIME) { + /* check if the start time of the command is within MIN_TIME_FOR_BLOCK_MODE_US */ + uint32_t currentTime = RF_getCurrentTime(); + uint32_t cmdTime = (uint32_t)MIN_TIME_FOR_BLOCK_MODE_US; + if(!isGapOK(currentTime, pCmdNew->startTime,cmdTime)) return(schStatus); + } + /* reject if the command is TRIG_NOW */ + else if(pCmdNew->pOp->startTrigger.triggerType == TRIG_NOW) return(schStatus); + } + + /* check input parameters */ + if(pCmdNew->startType == RF_StartAbs) + { + /*check input time parameters */ + if(pCmdNew->duration > SCHEDULE_LIMIT_US*RF_NUM_RAT_TICKS_IN_1_US) + { + /* min duration is not specified or too long */ + return(RF_ScheduleStatusError); + } + + if(pCmdNew->pOp->startTrigger.triggerType != TRIG_ABSTIME) + { + /* startType does not match */ + return(RF_ScheduleStatusError); + } + } + + dmmAdjustCmdSettings(pCmdNew); + + /* schedule the new command*/ + schStatus = dmmScheduleCmd(pCmdBg, pCmdNew, pPendQueue); + + if(schStatus < RF_ScheduleStatusNone) + { + /* Schedule failed, Now check whether commands in the queue can be preempted. */ + + h = pCmdNew->pClient; + + if( h == dmmClients[0].clientHndl) + { + h2 = dmmClients[1].clientHndl; + } + else + { + h2 = dmmClients[0].clientHndl; + } + +#if CONFLICT_FLUSH_ALL + RF_Cmd* pCmdPreempted = dmmCheckPreemption(h2, pCmdNew, pCmdBg, pPendQueue, &isQEmpty); + + if (pCmdPreempted) + { + preemptCnt++; + rfPreemptStats = dmmPreemptCmd(pCmdPreempted); + // if we preempted some commands + if ( rfPreemptStats == RF_StatSuccess) + { + // try to insert command one more time. + if (isClientMatched(h2, pCmdBg)) + { + // this time, BgCmd must be NULL, but RF driver can be in the middle of aborting the BgCmd + schStatus = dmmScheduleCmd(NULL, pCmdNew, pPendQueue); + } + else + { + schStatus = dmmScheduleCmd(pCmdBg, pCmdNew, pPendQueue); + } + } + } + else if (isQEmpty == (bool)true) + { + /* This may happen if there was a command in the queue when RF_scheduleCmd was called + * but the command was served/completed before the program checks the preemption + * dmmCheckPreemption(). So, the Q is empty. In this case, we should re-schedule.*/ + schStatus =dmmScheduleCmd(pCmdBg, pCmdNew, pPendQueue); + } + +#else + /* reject command individually */ + if (RF_STACK_ID_BLE == h2->clientConfig.nID) + { + /* Find a single command to preempt or reject. The new cmd must be absolute time cmd and BG exists, so no need to check the condition */ + schStatus = dmmSinglePreemptCheck(pCmdBg, pCmdNew, pPendQueue); + if(schStatus == RF_ScheduleStatusNone) + { + /* cannot find conflict, so try schedule again */ + /* This may happen if there was a command in the queue when RF_scheduleCmd was called + * but the command was served/completed before the program checks the preemption + * In this case, we should re-schedule.*/ + schStatus = dmmScheduleCmd(pCmdBg, pCmdNew, pPendQueue); + } + else if (schStatus > RF_ScheduleStatusNone) + { + preemptCnt++; + } + } + else + { + RF_Cmd* pCmdPreempted = dmmCheckPreemption(h2, pCmdNew, pCmdBg, pPendQueue, &isQEmpty); + + if (pCmdPreempted) + { + preemptCnt++; + rfPreemptStats = dmmPreemptCmd(pCmdPreempted); + // if we preempted some commands + if ( rfPreemptStats == RF_StatSuccess) + { + // try to insert command one more time. + schStatus = dmmScheduleCmd(pCmdBg, pCmdNew, pPendQueue); + } + } + else if (isQEmpty == (bool)true) + { + /* This may happen if there was a command in the queue when RF_scheduleCmd was called + * but the command was served/completed before the program checks the preemption + * dmmCheckPreemption(). So, the Q is empty. In this case, we should re-schedule.*/ + schStatus =dmmScheduleCmd(pCmdBg, pCmdNew, pPendQueue); + } + } + +#endif + } + +#ifdef DMM_RX_RESUME + /* check if we successfully inserted the command and there is a command being resumed*/ + if( (schStatus > RF_ScheduleStatusNone) && (rxResumeCmd.h == pCmdNew->pClient) && (rxResumeCmd.cmdHndl != RF_SCHEDULE_CMD_ERROR) ) + { + RF_Cmd* pPendQIterator = (RF_Cmd*)List_head(pPendQueue); + + /* check if this is an Rx-Resume command and if so replace the handle */ + /* Walk the queue.*/ + while (pPendQIterator) + { + /* Check if there is a matching Rx-Resume command */ + if ((rxResumeCmd.pOp == pPendQIterator->pOp)&&(pPendQIterator->pCb == rxResumeCmdCb)) + { + /* Replace cmdHandle with the original one */ + DMM_dbgLog1("scheduleCb: resumed c%x", rxResumeCmd.cmdHndl); + pPendQIterator->ch = rxResumeCmd.cmdHndl; + + break; + } + else + { + pPendQIterator = (RF_Cmd*)List_next((List_Elem*)pPendQIterator); + } + } + } +#endif //#ifdef DMM_RX_RESUME + + + if( (preemptionCb) && (schStatus == RF_ScheduleStatusError) ) + { + /* inform policy manager that a stack command has been preempted */ + preemptionCb(getClientStackRole(pCmdNew->pClient)); + } + + +#ifdef DMM_DEBUG_LOGGING + if(pCmdNew->pClient->clientConfig.nID == RF_STACK_ID_154) + { + DMM_dbgLog5("ScheduleCmd: Stack:%x cmd:%x Act:%x TrigType:%x Delay:%x", + pCmdNew->pClient->clientConfig.nID, pCmdNew->pOp->commandNo, pCmdNew->activityInfo,pCmdNew->pOp->startTrigger.triggerType, pCmdNew->allowDelay); + + RF_Cmd* pTemp = (RF_Cmd*)List_head(pPendQueue); + while(pTemp != NULL) + { + DMM_dbgLog5("PendQ: Stack:%x cmd:%x Act:%x TrigType:%x Delay:%x", + pTemp->pClient->clientConfig.nID, pTemp->pOp->commandNo, pTemp->activityInfo,pTemp->pOp->startTrigger.triggerType, pTemp->allowDelay); + pTemp = (RF_Cmd*)List_next((List_Elem*)pTemp); + } + } +#endif + + return schStatus; +} + +#if !CONFLICT_FLUSH_ALL +static RF_ScheduleStatus dmmSinglePreemptCheck(RF_Cmd* pCmdBg, RF_Cmd* pCmdNew, List_List* pPendQueue) +{ + RF_ScheduleStatus scheduleResult = RF_ScheduleStatusError; + DMM_ConflictStatus conflictStatus; + RF_Cmd* pRefCmd; + RF_Cmd* pAfterRefCmd; + uint8_t mode = RF_ABORT_PREEMPTION; + + /* Typecast the arguments to RF commands. */ + RF_Cmd* pHead = (RF_Cmd*)List_head(pPendQueue); + + /* special case, with BgCmd */ + conflictStatus = dmmCmdConflictCheck(pCmdBg, pCmdNew, pHead); + switch(conflictStatus) + { + case DMM_ConflictWithPrev: + /* just schedule at top, let conflict hook takes care of priority */ + List_putHead(pPendQueue, (List_Elem*)pCmdNew); + return(RF_ScheduleStatusTop); + case DMM_ConflictWithNext: + case DMM_ConfictWithBoth: + if(isNewCmdHigherPriority(pCmdNew, pHead)) + { + /* remove the next command from the Pend Q, then schedule at top */ + RF_cancelCmd(pHead->pClient, pHead->ch, mode); + List_putHead(pPendQueue, (List_Elem*)pCmdNew); + return(RF_ScheduleStatusTop); + } + else + { + return(RF_ScheduleStatusError); + } + default: + /* move down to Pend Q */ + break; + } + + /* Load list head as the start point of the iterator. */ + pRefCmd = pHead; + + /* Walk the queue.*/ + while (pRefCmd) + { + pAfterRefCmd = (RF_Cmd*)List_next((List_Elem*)pRefCmd); + conflictStatus = dmmCmdConflictCheck(pRefCmd, pCmdNew, pAfterRefCmd); + + switch(conflictStatus) + { + case DMM_ConflictWithPrev: + if(isNewCmdHigherPriority(pCmdNew, pRefCmd)) + { + /* insert to PendQ first before removing pRefCmd */ + if (pAfterRefCmd) + { + List_insert(pPendQueue, (List_Elem*)pCmdNew, List_next((List_Elem*)pAfterRefCmd)); + scheduleResult = RF_ScheduleStatusMiddle; + } + else + { + List_put(pPendQueue, (List_Elem*)pCmdNew); + scheduleResult = RF_ScheduleStatusTail; + } + RF_cancelCmd(pRefCmd->pClient, pRefCmd->ch, mode); + return(scheduleResult); + } + else + { + return(RF_ScheduleStatusError); + } + case DMM_ConflictWithNext: + if(isNewCmdHigherPriority(pCmdNew, pAfterRefCmd)) + { + if (List_next((List_Elem*)pAfterRefCmd)) + { + List_insert(pPendQueue, (List_Elem*)pCmdNew, List_next((List_Elem*)pAfterRefCmd)); + scheduleResult = RF_ScheduleStatusMiddle; + } + else + { + List_put(pPendQueue, (List_Elem*)pCmdNew); + scheduleResult = RF_ScheduleStatusTail; + } + RF_cancelCmd(pAfterRefCmd->pClient, pAfterRefCmd->ch, mode); + return(scheduleResult); + } + else + { + return(RF_ScheduleStatusError); + } + case DMM_ConfictWithBoth: + if(isNewCmdHigherPriority(pCmdNew, pRefCmd)) + { + /*pAfterRefCmd must not NULL */ + List_insert(pPendQueue, (List_Elem*)pCmdNew, (List_Elem*)pAfterRefCmd); + RF_cancelCmd(pRefCmd->pClient, pRefCmd->ch, mode); + } + if(isNewCmdHigherPriority(pCmdNew, pAfterRefCmd)) + { + /* no need to insert the new cmd here */ + RF_cancelCmd(pAfterRefCmd->pClient, pAfterRefCmd->ch, mode); + } + return(RF_ScheduleStatusMiddle); + case DMM_NoConflict: + default: + /* move down to Pend Q */ + pRefCmd = (RF_Cmd*)List_next((List_Elem*)pRefCmd); + break; + + } + } + + /* cannot find conflict*/ + return(RF_ScheduleStatusNone); +} +#endif + +static RF_ScheduleStatus dmmScheduleCmd(RF_Cmd* pCmdBg, RF_Cmd* pCmdNew, List_List* pPendQueue) +{ + RF_ScheduleStatus scheduleResult = RF_ScheduleStatusError; + + /* Typecast the arguments to RF commands. */ + RF_Cmd* pHead = (RF_Cmd*)List_head(pPendQueue); + + if(true == dmmCmdInsertCheck(pCmdBg, pCmdNew, pHead)) + { + /* Insert command at the beginning of the queue */ + List_putHead(pPendQueue, (List_Elem*)pCmdNew); + scheduleResult = RF_ScheduleStatusTop; + } + else + { + /* Load list head as the start point of the iterator. */ + RF_Cmd* pRefCmd = pHead; + + /* Walk the queue.*/ + while (pRefCmd) + { + /* Check if we can insert the new command in between. */ + if (dmmCmdInsertCheck(pRefCmd, pCmdNew, (RF_Cmd*)List_next((List_Elem*)pRefCmd))) + { + /* Set the return value that the new command should be + inserted in between RefCmd and RefCmd->pNext. */ + if (List_next((List_Elem*)pRefCmd)) + { + /* Insert command before pInsertLocation->next. */ + List_insert(pPendQueue, (List_Elem*)pCmdNew, List_next((List_Elem*)pRefCmd)); + scheduleResult = RF_ScheduleStatusMiddle; + } + else + { + /* Append command to the end of the queue (if nextCmd does not exist). */ + List_put(pPendQueue, (List_Elem*)pCmdNew); + scheduleResult = RF_ScheduleStatusTail; + } + break; + } + else + { + pRefCmd = (RF_Cmd*)List_next((List_Elem*)pRefCmd); + } + } + } + + if ((scheduleResult == RF_ScheduleStatusError) && (pCmdNew->pOp->startTrigger.triggerType == TRIG_NOW)) + { + /* put Trig_Now at the end */ + List_put(pPendQueue, (List_Elem*)pCmdNew); + scheduleResult = RF_ScheduleStatusTail; + } + /* Return with the scheduling method. */ + return(scheduleResult); +} + + +/* rf driver has this function. We can access clientConfig.nPhySwitchingDuration but we want to make sure whether physwitch is there or not */ +static int32_t getSwitchingTimeInUs(RF_Cmd* prevCmd, RF_Cmd* nextCmd) +{ + int32_t switchingTime = 0; + + /* If otherCmd and newCmd are from different client then there is a switching time + related to moving between the two commands. */ + if (prevCmd->pClient != nextCmd->pClient) + { + switchingTime = (int32_t)nextCmd->pClient->clientConfig.nPhySwitchingDuration; + } + + /* Return the switching time related to moving between the two clients. */ + return(switchingTime); +} + + +/* check cmd insert after prev cmd (general case) */ +static bool cmdInsertCheckAfterPrevCmd(RF_Cmd* pPrevCmd, RF_Cmd* pNewCmd) +{ + uint32_t requiredDelay; + uint32_t cmdTime; + bool scheduleResult = true; + + if(pPrevCmd->pClient->clientConfig.nID == pNewCmd->pClient->clientConfig.nID) + { + // same client, new command should come after the previous one + scheduleResult = true; + } + else if (pNewCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + if(pPrevCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + /* duration will be added later when 15.4 stack puts all related commands into a chain command */ + //cmdTime = (uint32_t)RF_convertRatTicksToUs(pPrevCmd->duration) + (uint32_t)getSwitchingTimeInUs(pPrevCmd, pNewCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + cmdTime = (uint32_t)getSwitchingTimeInUs(pPrevCmd, pNewCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + scheduleResult = isGapOK(pPrevCmd->startTime, pNewCmd->startTime,cmdTime); + + if(false == scheduleResult) + { + if(pNewCmd->allowDelay ==0) + { + // no delay + scheduleResult = false; + } + else + { + requiredDelay = getRequiredDelay(pPrevCmd->startTime, pNewCmd->startTime,cmdTime); + if(pNewCmd->allowDelay > requiredDelay) + { + // delay is enough + scheduleResult = true; + pNewCmd->allowDelay -= requiredDelay; + pNewCmd->startTime += requiredDelay; + } + else + { + // delay is not enough + scheduleResult = false; + } + } + } + } + else if(pPrevCmd->pOp->startTrigger.triggerType == TRIG_NOW) + { + scheduleResult = true; + } + } + else if(pNewCmd->pOp->startTrigger.triggerType == TRIG_NOW) + { + if(pPrevCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + /* Trig_Now will be added later at the end of the Q or available slot */ + scheduleResult = false; + } + else if(pPrevCmd->pOp->startTrigger.triggerType == TRIG_NOW) + { + /* Trig_Now after Trig_Now */ + scheduleResult = true; + } + } + return(scheduleResult); +} + +/* check cmd insert after prev cmd (general case) */ +static bool cmdInsertCheckBeforeNextCmd(RF_Cmd* pNewCmd, RF_Cmd* pNextCmd) +{ + uint32_t cmdTime; + bool scheduleResult = true; + + if(pNewCmd->pClient->clientConfig.nID == pNextCmd->pClient->clientConfig.nID) + { + /* from the same client, the new command should not be placed before the previous one */ + scheduleResult = false; + } + else if (pNewCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + if(pNextCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + /* duration will be added later when 15.4 stack puts all related commands into a chain command */ + //cmdTime = (uint32_t)RF_convertRatTicksToUs(pNewCmd->duration) + (uint32_t)getSwitchingTimeInUs(pNewCmd, pNextCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + cmdTime = (uint32_t)getSwitchingTimeInUs(pNewCmd, pNextCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + scheduleResult = isGapOK(pNewCmd->startTime, pNextCmd->startTime,cmdTime); + + /* cannot apply delay for the conflict with the next command */ + } + else if(pNextCmd->pOp->startTrigger.triggerType == TRIG_NOW) + { + scheduleResult = false; + } + } + else if(pNewCmd->pOp->startTrigger.triggerType == TRIG_NOW) + { + if(pNextCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + uint32_t currentTime = RF_getCurrentTime(); + /* duration will be added later when 15.4 stack puts all related commands into a chain command */ + //cmdTime = (uint32_t)RF_convertRatTicksToUs(pNewCmd->duration) + (uint32_t)getSwitchingTimeInUs(pNewCmd, pNextCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + cmdTime = (uint32_t)getSwitchingTimeInUs(pNewCmd, pNextCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + scheduleResult = isGapOK(currentTime, pNextCmd->startTime,cmdTime); + /* cannot apply delay for the conflict with the next command */ + } + else if(pNextCmd->pOp->startTrigger.triggerType == TRIG_NOW) + { + /* Trig_Now cannot be placed in front of existing Trig_Now */ + scheduleResult = false; + } + } + return(scheduleResult); +} + + + + +static bool isClientMatched(RF_Handle h, RF_Cmd* pCmd) +{ + if (pCmd && (pCmd->pClient == h)) + { + return (bool)true; + } + else + { + return (bool)false; + } +} + +#if !CONFLICT_FLUSH_ALL +/* return = true => no conflict, false => conflict */ +static bool conflictCheckWithNextCmd(RF_Cmd* pNewCmd, RF_Cmd* pNextCmd) +{ + bool scheduleResult = true; + uint32_t cmdTime; + + if(pNextCmd->pClient != pNewCmd->pClient) + { + if (pNewCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + if(pNextCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + /* duration will be added later when 15.4 stack puts all related commands into a chain command */ + //cmdTime = (uint32_t)RF_convertRatTicksToUs(pNewCmd->duration) + (uint32_t)getSwitchingTimeInUs(pNewCmd, pNextCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + cmdTime = (uint32_t)getSwitchingTimeInUs(pNewCmd, pNextCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + scheduleResult = isGapOK(pNewCmd->startTime, pNextCmd->startTime,cmdTime); + } + } + } + + return(scheduleResult); +} + +/* return = true => no conflict, false => conflict */ +static bool conflictCheckWithPrevCmd(RF_Cmd* pPrevCmd, RF_Cmd* pNewCmd) +{ + bool scheduleResult = true; + uint32_t cmdTime; + + if(pPrevCmd->pClient != pNewCmd->pClient) + { + if (pNewCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + if(pPrevCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME) + { + /* duration will be added later when 15.4 stack puts all related commands into a chain command */ + //cmdTime = (uint32_t)RF_convertRatTicksToUs(pPrevCmd->duration) + (uint32_t)getSwitchingTimeInUs(pPrevCmd, pNewCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + cmdTime = (uint32_t)getSwitchingTimeInUs(pPrevCmd, pNewCmd) + MIN_NEW_CMD_START_TIME_TO_CURRENT_CMD_US; + scheduleResult = isGapOK(pPrevCmd->startTime, pNewCmd->startTime,cmdTime); + } + /* conflict with Trig Now cmd is not considered */ + } + /* Trig Now command won't come here, so no need to check */ + } + return(scheduleResult); +} + +#endif + +static bool isSameClient(RF_Cmd* pCmdNew, RF_Cmd* pCompareCmd) +{ + if(pCmdNew->pClient->clientConfig.nID == pCompareCmd->pClient->clientConfig.nID) + return (true); + else + return(false); +} + +static bool isNewCmdHigherPriority(RF_Cmd* pCmdNew, RF_Cmd* pCompareCmd) +{ + uint8_t compCmdPri = DMMPolicy_getGlobalPriority(pCompareCmd->activityInfo, pCompareCmd->pClient->clientConfig.nID); + uint8_t newCmdPri = DMMPolicy_getGlobalPriority(pCmdNew->activityInfo, pCmdNew->pClient->clientConfig.nID); + + if (newCmdPri == compCmdPri) + { + compCmdPri = DMMPolicy_getDefaultPriority(pCompareCmd->pClient->clientConfig.nID); + newCmdPri = DMMPolicy_getDefaultPriority(pCmdNew->pClient->clientConfig.nID); + } + + return((newCmdPri > compCmdPri ? true : false)); +} + +static bool dmmCmdInsertCheck(RF_Cmd* prevCmd, RF_Cmd* newCmd, RF_Cmd* nextCmd) +{ + bool insertOK = false; + + if(prevCmd) + { + if(true == cmdInsertCheckAfterPrevCmd(prevCmd,newCmd)) + { + if(nextCmd) + { + insertOK = cmdInsertCheckBeforeNextCmd(newCmd,nextCmd); + } + else + { + // no nextCmd + insertOK = true; + } + } + } + else + { + if(nextCmd) + { + insertOK = cmdInsertCheckBeforeNextCmd(newCmd,nextCmd); + } + else + { + // no prev nor next cmd + insertOK = true; + } + + } + return(insertOK); +} + +#if !CONFLICT_FLUSH_ALL +static DMM_ConflictStatus dmmCmdConflictCheck(RF_Cmd* prevCmd, RF_Cmd* newCmd, RF_Cmd* nextCmd) +{ + DMM_ConflictStatus conflictStatus=DMM_NoConflict; + bool insertOKPrev = true; + bool insertOKNext = true; + + if(prevCmd) + { + insertOKPrev = conflictCheckWithPrevCmd(prevCmd,newCmd); + } + if(nextCmd) + { + insertOKNext = conflictCheckWithNextCmd(newCmd,nextCmd); + } + + if((false == insertOKPrev)&&(false == insertOKNext)) + { + conflictStatus = DMM_ConfictWithBoth; + } + else if ((false == insertOKPrev)&&(true == insertOKNext)) + { + conflictStatus = DMM_ConflictWithPrev; + } + else if ((true == insertOKPrev)&&(false == insertOKNext)) + { + conflictStatus = DMM_ConflictWithNext; + } + else + { + conflictStatus = DMM_NoConflict; + } + + return(conflictStatus); +} +#endif + diff --git a/src/openthread.syscfg b/src/openthread_orig.syscfg similarity index 81% rename from src/openthread.syscfg rename to src/openthread_orig.syscfg index 4b26b9e..261b77e 100755 --- a/src/openthread.syscfg +++ b/src/openthread_orig.syscfg @@ -1,9 +1,4 @@ -/** - * These arguments were used when this file was generated. They will be automatically applied on subsequent loads - * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. - * @cliArgs --board "/ti/boards/LP_EM_CC1354P10_1" --product "simplelink_cc13xx_cc26xx_sdk@7.10.00.98" - * @versions {"tool":"1.16.2+3028"} - */ +// @cliArgs --product ../../ot-ti/third_party/ti_simplelink_sdk/repo_cc13xx_cc26xx/.metadata/product.json --board /ti/boards/LP_EM_CC1354P10_1 --rtos freertos /** * Import the modules used in this configuration. @@ -12,8 +7,6 @@ const ble = scripting.addModule("/ti/ble5stack/ble"); const CCFG = scripting.addModule("/ti/devices/CCFG"); const custom = scripting.addModule("/ti/devices/radioconfig/custom"); const rfdesign = scripting.addModule("/ti/devices/radioconfig/rfdesign"); -const Display = scripting.addModule("/ti/display/Display", {}, false); -const Display1 = Display.addInstance(); const dmm = scripting.addModule("/ti/dmm/dmm"); const AESCCM = scripting.addModule("/ti/drivers/AESCCM", {}, false); const AESCCM1 = AESCCM.addInstance(); @@ -21,6 +14,7 @@ const AESCTRDRBG = scripting.addModule("/ti/drivers/AESCTRDRBG", {}, false); const AESCTRDRBG1 = AESCTRDRBG.addInstance(); const AESECB = scripting.addModule("/ti/drivers/AESECB"); const AESECB1 = AESECB.addInstance(); +const AESECB2 = AESECB.addInstance(); const DMA = scripting.addModule("/ti/drivers/DMA"); const ECDH = scripting.addModule("/ti/drivers/ECDH"); const ECDH1 = ECDH.addInstance(); @@ -34,6 +28,8 @@ const GPIO2 = GPIO.addInstance(); const GPIO3 = GPIO.addInstance(); const GPIO4 = GPIO.addInstance(); const GPIO5 = GPIO.addInstance(); +const GPIO17 = GPIO.addInstance(); +const GPIO18 = GPIO.addInstance(); const NVS = scripting.addModule("/ti/drivers/NVS"); const NVS1 = NVS.addInstance(); const Power = scripting.addModule("/ti/drivers/Power"); @@ -46,13 +42,14 @@ const TRNG = scripting.addModule("/ti/drivers/TRNG"); const TRNG1 = TRNG.addInstance(); const TRNG2 = TRNG.addInstance(); const UART2 = scripting.addModule("/ti/drivers/UART2"); +const UART21 = UART2.addInstance(); const Watchdog = scripting.addModule("/ti/drivers/Watchdog"); const Watchdog1 = Watchdog.addInstance(); /** * Write custom configuration values to the imported modules. */ -ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param1"; +ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param2"; ble.connUpdateParamsPeripheral.$name = "ti_ble5stack_general_ble_conn_update_params0"; ble.advSet1.$name = "ti_ble5stack_broadcaster_advertisement_set0"; ble.advSet1.advParam1.$name = "ti_ble5stack_broadcaster_advertisement_params0"; @@ -100,18 +97,14 @@ custom.radioConfigieee154.codeExportConfig.cmdList_ieee_15_4 = ["cmdIeeeCsma","c rfdesign.rfDesign = "LP_EM_CC1354P10_1"; -Display1.$name = "CONFIG_Display_0"; -Display1.uart.$name = "CONFIG_DISPLAY_UART"; -Display1.uart.$hardware = system.deviceData.board.components.XDS110UART; - dmm.stackRoles = ["blePeripheral","custom1"]; +dmm.numApplicationStates = 2; +dmm.applicationState0 = "ANY"; +dmm.applicationState1 = "DMMPOLICY_BLE_IDLE"; dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; dmm.policyArray[0].custom1.$name = "ti_dmm_policy_stack_dmm_stack_custom0"; dmm.policyArray[0].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble0"; dmm.policyArray[0].blePeripheral.weight = 1; -dmm.numApplicationStates = 2; -dmm.applicationState0 = "ANY"; -dmm.applicationState1 = "DMMPOLICY_BLE_IDLE"; AESCCM1.$name = "CONFIG_AESCCM_0"; @@ -119,6 +112,8 @@ AESCTRDRBG1.$name = "CONFIG_AESCTRDRBG_0"; AESECB1.$name = "CONFIG_AESECB_MBEDTLS"; +AESECB2.$name = "CONFIG_AESECB_0"; + ECDH1.$name = "CONFIG_ECDH_0"; ECDSA1.$name = "CONFIG_ECDSA_0"; @@ -143,12 +138,23 @@ GPIO5.outputStrength = "High"; GPIO5.initialOutputState = "High"; GPIO5.gpioPin.$assign = "boosterpack.32"; +GPIO17.$name = "CONFIG_GPIO_RF_RX"; +GPIO17.mode = "Output"; +GPIO17.gpioPin.$assign = "boosterpack.39"; + +GPIO18.$name = "CONFIG_GPIO_RF_TX"; +GPIO18.mode = "Output"; +GPIO18.gpioPin.$assign = "boosterpack.40"; + NVS1.$name = "CONFIG_NVSINTERNAL"; NVS1.internalFlash.$name = "ti_drivers_nvs_NVSCC26XX0"; NVS1.internalFlash.regionBase = 0x52000; NVS1.internalFlash.regionSize = 0x4000; -RF.$hardware = system.deviceData.board.components["SKY13317-373LF"]; +RF.$hardware = system.deviceData.board.components["SKY13317-373LF"]; +RF.coexEnable = true; +RF.coexPhy = ["ieee_15_4"]; +RF.coexMode = "coexMode2Wire"; SHA21.$name = "CONFIG_SHA2_0"; @@ -159,8 +165,14 @@ SPI1.spi.pociPin.$assign = "boosterpack.6"; SPI1.spi.picoPin.$assign = "boosterpack.23"; SPI1.spi.csnPin.$assign = "boosterpack.25"; +TRNG1.$name = "CONFIG_TRNG_0"; + TRNG2.$name = "CONFIG_TRNG_THREAD"; +UART21.$name = "CONFIG_UART2_0"; +UART21.$hardware = system.deviceData.board.components.XDS110UART; +UART21.interruptPriority = "1"; + Watchdog1.$name = "CONFIG_WATCHDOG0"; Watchdog1.watchdog.$assign = "WDT0"; @@ -169,16 +181,18 @@ Watchdog1.watchdog.$assign = "WDT0"; * version of the tool will not impact the pinmux you originally saw. These lines can be completely deleted in order to * re-solve from scratch. */ -Display1.uart.uart.$suggestSolution = "UART0"; -Display1.uart.uart.txPin.$suggestSolution = "boosterpack.4"; -Display1.uart.uart.rxPin.$suggestSolution = "boosterpack.3"; -GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; -GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; -GPIO3.gpioPin.$suggestSolution = "DIO_7"; -GPIO4.gpioPin.$suggestSolution = "DIO_6"; -RF.rfAntennaPin0.$suggestSolution = "DIO_34"; -RF.rfAntennaPin1.$suggestSolution = "DIO_3"; -RF.rfAntennaPin2.$suggestSolution = "DIO_35"; -SPI1.spi.$suggestSolution = "SPI0"; -SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; -SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; +GPIO1.gpioPin.$suggestSolution = "boosterpack.11"; +GPIO2.gpioPin.$suggestSolution = "boosterpack.17"; +GPIO3.gpioPin.$suggestSolution = "DIO_7"; +GPIO4.gpioPin.$suggestSolution = "DIO_6"; +RF.rfAntennaPin0.$suggestSolution = "DIO_34"; +RF.rfAntennaPin1.$suggestSolution = "DIO_3"; +RF.rfAntennaPin2.$suggestSolution = "DIO_35"; +RF.rfCoexRequestPin.$suggestSolution = "boosterpack.9"; +RF.rfCoexGrantPin.$suggestSolution = "boosterpack.10"; +SPI1.spi.$suggestSolution = "SPI0"; +SPI1.spi.dmaRxChannel.$suggestSolution = "DMA_CH3"; +SPI1.spi.dmaTxChannel.$suggestSolution = "DMA_CH4"; +UART21.uart.$suggestSolution = "UART0"; +UART21.uart.txPin.$suggestSolution = "boosterpack.4"; +UART21.uart.rxPin.$suggestSolution = "boosterpack.3"; diff --git a/src/spi_periph.c b/src/spi_periph.c index 6e078ea..b492ae3 100644 --- a/src/spi_periph.c +++ b/src/spi_periph.c @@ -63,6 +63,8 @@ #define SPINEL_INT_ASSERT 0 #define SPINEL_INT_DEASSERT 1 +#if 0 + otPlatSpiSlaveTransactionCompleteCallback sCompleteCallback = NULL; otPlatSpiSlaveTransactionProcessCallback sProcessCallback = NULL; void * sContext = NULL; @@ -384,3 +386,4 @@ otError otPlatSpiSlavePrepareTransaction(uint8_t *aOutputBuf, return retval; } +#endif diff --git a/src/system.c b/src/system.c index bee5a6b..08f0b17 100644 --- a/src/system.c +++ b/src/system.c @@ -182,7 +182,7 @@ void platformUartSignal(uintptr_t arg) (void) ret; } -void platformSpiSignal() +/*void platformSpiSignal() { struct OtStack_procQueueMsg msg; int ret; @@ -191,7 +191,7 @@ void platformSpiSignal() assert(0 == ret); (void) ret; -} +}*/ void platformRadioSignal(uintptr_t arg) { @@ -263,7 +263,7 @@ void otSysProcessDrivers(otInstance *aInstance) case OtStack_procQueueCmd_spi: { - platformSpiProcess(); +// platformSpiProcess(); break; } diff --git a/src/uart.c b/src/uart.c index ccbcdb4..30faf1c 100644 --- a/src/uart.c +++ b/src/uart.c @@ -112,7 +112,7 @@ otError otPlatUartEnable(void) params.writeCallback = uartWriteCallback; #endif - PlatformUart_uartHandle = UART2_open(CONFIG_DISPLAY_UART, ¶ms); + PlatformUart_uartHandle = UART2_open(CONFIG_UART2_0, ¶ms); UART2_read(PlatformUart_uartHandle, PlatformUart_receiveBuffer, sizeof(PlatformUart_receiveBuffer), NULL); diff --git a/third_party/mbedtls/mbedtls-config-cc13x4_cc26x4.h b/third_party/mbedtls/mbedtls-config-cc13x4_cc26x4.h index 0b62d19..6ba7610 100644 --- a/third_party/mbedtls/mbedtls-config-cc13x4_cc26x4.h +++ b/third_party/mbedtls/mbedtls-config-cc13x4_cc26x4.h @@ -43,14 +43,14 @@ #include /* Enable Hardware Acceleration */ -#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT +/*#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT #define MBEDTLS_ECDH_GEN_PUBLIC_ALT #define MBEDTLS_ECDSA_SIGN_ALT #define MBEDTLS_ECDSA_VERIFY_ALT #define MBEDTLS_ECJPAKE_ALT #define MBEDTLS_ENTROPY_HARDWARE_ALT #define MBEDTLS_AES_ALT -#define MBEDTLS_SHA256_ALT +#define MBEDTLS_SHA256_ALT*/ #define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf diff --git a/third_party/ti_simplelink_sdk/repo_cc13xx_cc26xx b/third_party/ti_simplelink_sdk/repo_cc13xx_cc26xx index 857bbba..bce0be3 160000 --- a/third_party/ti_simplelink_sdk/repo_cc13xx_cc26xx +++ b/third_party/ti_simplelink_sdk/repo_cc13xx_cc26xx @@ -1 +1 @@ -Subproject commit 857bbba035ddf5383836536ae304cb1d0d53e2ee +Subproject commit bce0be31dd568f9ebb334652e6737436d8a4b6a0 From 1729718db7077f5892b635d45f9df7b7280e8cde Mon Sep 17 00:00:00 2001 From: Ryan-Brownf11 Date: Wed, 22 May 2024 14:15:40 -0500 Subject: [PATCH 19/19] Minor FreeRTOS changes to enable sleep mode --- examples/apps/cli/freertos_main.c | 2 +- src/FreeRTOSConfig.h | 2 +- third_party/freertos/repo | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/apps/cli/freertos_main.c b/examples/apps/cli/freertos_main.c index 9d7775a..7be6970 100644 --- a/examples/apps/cli/freertos_main.c +++ b/examples/apps/cli/freertos_main.c @@ -79,7 +79,7 @@ static TaskHandle_t BLEAPPTaskHandle; __attribute__((section(".heap"))) uint8_t ucHeap[TOTAL_ICALL_HEAP_SIZE]; uint32_t heapSize = TOTAL_ICALL_HEAP_SIZE; -void vApplicationStackOverflowHook(void) +void vApplicationStackOverflowHook( TaskHandle_t xTask, char * pcTaskName ) { while (1) { diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index b48f4a3..07db16b 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -112,7 +112,7 @@ } /* Constants related to the behaviour or the scheduler. */ -#define configTICK_RATE_HZ ((TickType_t)100000) +#define configTICK_RATE_HZ ((TickType_t)10000) #define configUSE_PREEMPTION 1 #define configUSE_TIME_SLICING 0 #define configMAX_PRIORITIES (10UL) diff --git a/third_party/freertos/repo b/third_party/freertos/repo index 88e3232..abb5452 160000 --- a/third_party/freertos/repo +++ b/third_party/freertos/repo @@ -1 +1 @@ -Subproject commit 88e32327e975ddde97c390bc5b6c1f8e7d9d239e +Subproject commit abb5452a12ebff8e8af640e3ceb5fe16f30e6f54