diff --git a/config/telink/chip-module/Kconfig.defaults b/config/telink/chip-module/Kconfig.defaults index 9c27fe1059451f..45c8894722eeea 100644 --- a/config/telink/chip-module/Kconfig.defaults +++ b/config/telink/chip-module/Kconfig.defaults @@ -304,9 +304,6 @@ config CHIP_WIFI select NET_IPV6_ND # enable Neighbor Discovery to handle Router Advertisements select NET_IPV6_NBR_CACHE select NET_STATISTICS_USER_API -# select NET_IPV4 # TODO: remove IPv4 when IPv6 will be ready (see CHIP_IPV4) -# select NET_CONFIG_NEED_IPV4 -# select NET_DHCPV4 if CHIP_WIFI diff --git a/docs/guides/fabric_synchronization_guide.md b/docs/guides/fabric_synchronization_guide.md index b2cfd26d9f439e..5944105512776d 100644 --- a/docs/guides/fabric_synchronization_guide.md +++ b/docs/guides/fabric_synchronization_guide.md @@ -127,7 +127,7 @@ KVS Pair the Light Example with node ID 3 using its payload number: ``` -pairing already-discovered 3 20202021 5540 +pairing already-discovered 3 20202021 5543 ``` After the device is successfully added, you will observe the following on diff --git a/examples/platform/telink/common/src/AppTaskCommon.cpp b/examples/platform/telink/common/src/AppTaskCommon.cpp index 59ad41b3c45bde..d2ad2a6fd83a00 100644 --- a/examples/platform/telink/common/src/AppTaskCommon.cpp +++ b/examples/platform/telink/common/src/AppTaskCommon.cpp @@ -414,8 +414,9 @@ void AppTaskCommon::InitPwms() void AppTaskCommon::LinkPwms(PwmManager & pwmManager) { -#if CONFIG_WS2812_STRIP || \ - CONFIG_BOARD_TLSR9118BDK40D // TLSR9118BDK40D EVK buttons located on 4th PWM channel (see tlsr9118bdk40d.overlay) +#if CONFIG_BOARD_TLSR9118BDK40D // TLSR9118BDK40D EVK supports only 1 PWM channel connected to LED + pwmManager.linkPwm(PwmManager::EAppPwm_Red, 0); +#elif CONFIG_WS2812_STRIP pwmManager.linkPwm(PwmManager::EAppPwm_Red, 0); pwmManager.linkPwm(PwmManager::EAppPwm_Green, 1); pwmManager.linkPwm(PwmManager::EAppPwm_Blue, 2); diff --git a/examples/rvc-app/rvc-common/include/rvc-device.h b/examples/rvc-app/rvc-common/include/rvc-device.h index b66ce3251feba6..e2011f6c83e196 100644 --- a/examples/rvc-app/rvc-common/include/rvc-device.h +++ b/examples/rvc-app/rvc-common/include/rvc-device.h @@ -61,7 +61,7 @@ class RvcDevice mOperationalStateDelegate.SetGoHomeCallback(&RvcDevice::HandleOpStateGoHomeCallback, this); mServiceAreaDelegate.SetIsSetSelectedAreasAllowedCallback(&RvcDevice::SaIsSetSelectedAreasAllowed, this); - mServiceAreaDelegate.SetHandleSkipCurrentAreaCallback(&RvcDevice::SaHandleSkipCurrentArea, this); + mServiceAreaDelegate.SetHandleSkipAreaCallback(&RvcDevice::SaHandleSkipArea, this); mServiceAreaDelegate.SetIsSupportedAreasChangeAllowedCallback(&RvcDevice::SaIsSupportedAreasChangeAllowed, this); mServiceAreaDelegate.SetIsSupportedMapChangeAllowedCallback(&RvcDevice::SaIsSupportedMapChangeAllowed, this); } @@ -104,7 +104,7 @@ class RvcDevice bool SaIsSetSelectedAreasAllowed(MutableCharSpan & statusText); - bool SaHandleSkipCurrentArea(uint32_t skippedArea, MutableCharSpan & skipStatusText); + bool SaHandleSkipArea(uint32_t skippedArea, MutableCharSpan & skipStatusText); bool SaIsSupportedAreasChangeAllowed(); diff --git a/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h b/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h index fdad4f83f0666a..c6be8aa5bb55f0 100644 --- a/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h +++ b/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h @@ -30,7 +30,7 @@ namespace Clusters { class RvcDevice; typedef bool (RvcDevice::*IsSetSelectedAreasAllowedCallback)(MutableCharSpan & statusText); -typedef bool (RvcDevice::*HandleSkipCurrentAreaCallback)(uint32_t skippedArea, MutableCharSpan & skipStatusText); +typedef bool (RvcDevice::*HandleSkipAreaCallback)(uint32_t skippedArea, MutableCharSpan & skipStatusText); typedef bool (RvcDevice::*IsChangeAllowedSimpleCallback)(); namespace ServiceArea { @@ -46,8 +46,8 @@ class RvcServiceAreaDelegate : public Delegate RvcDevice * mIsSetSelectedAreasAllowedDeviceInstance; IsSetSelectedAreasAllowedCallback mIsSetSelectedAreasAllowedCallback; - RvcDevice * mHandleSkipCurrentAreaDeviceInstance; - HandleSkipCurrentAreaCallback mHandleSkipCurrentAreaCallback; + RvcDevice * mHandleSkipAreaDeviceInstance; + HandleSkipAreaCallback mHandleSkipAreaCallback; RvcDevice * mIsSupportedAreasChangeAllowedDeviceInstance; IsChangeAllowedSimpleCallback mIsSupportedAreasChangeAllowedCallback; RvcDevice * mIsSupportedMapChangeAllowedDeviceInstance; @@ -82,7 +82,7 @@ class RvcServiceAreaDelegate : public Delegate bool IsValidSelectAreasSet(const ServiceArea::Commands::SelectAreas::DecodableType & req, ServiceArea::SelectAreasStatus & areaStatus, MutableCharSpan & statusText) override; - bool HandleSkipCurrentArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) override; + bool HandleSkipArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) override; //************************************************************************* // Supported Areas accessors @@ -169,10 +169,10 @@ class RvcServiceAreaDelegate : public Delegate mIsSetSelectedAreasAllowedDeviceInstance = instance; } - void SetHandleSkipCurrentAreaCallback(HandleSkipCurrentAreaCallback callback, RvcDevice * instance) + void SetHandleSkipAreaCallback(HandleSkipAreaCallback callback, RvcDevice * instance) { - mHandleSkipCurrentAreaCallback = callback; - mHandleSkipCurrentAreaDeviceInstance = instance; + mHandleSkipAreaCallback = callback; + mHandleSkipAreaDeviceInstance = instance; } void SetIsSupportedAreasChangeAllowedCallback(IsChangeAllowedSimpleCallback callback, RvcDevice * instance) diff --git a/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml index ce0ddaa38b5307..fa0b258557745c 100644 --- a/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml +++ b/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml @@ -1,13 +1,20 @@ - + RVC Clean Mode Cluster Test Plan @@ -16,7 +23,7 @@ Draft RVCCLEANM.S Does the device implement the RVCCLEANM cluster as a server? - 89.1. Role - allclusters.html[pdf] + 99.1. Role - allclusters.html[pdf] O true @@ -26,16 +33,14 @@ Draft PIXIT.RVCCLEANM.MODE_CHANGE_FAIL Id of mode the device will fail to transition to, given its current state - 90. PIXIT Definition - allclusters.html[pdf] - O - 0x01 + 100. PIXIT Definition - allclusters.html[pdf] + On/a PIXIT.RVCCLEANM.MODE_CHANGE_OK Id of mode the device will successfully transition to, given its current state - 90. PIXIT Definition - allclusters.html[pdf] - O - 0x01 + 100. PIXIT Definition - allclusters.html[pdf] + On/a @@ -45,31 +50,17 @@ Draft RVCCLEANM.S.A0000 Does the device implement the SupportedModes attribute? - 89.2.2. Attributes - allclusters.html[pdf] + 99.2.1. Attributes - allclusters.html[pdf] M true RVCCLEANM.S.A0001 Does the device implement the CurrentMode attribute? - 89.2.2. Attributes - allclusters.html[pdf] + 99.2.1. Attributes - allclusters.html[pdf] M true - - RVCCLEANM.S.A0002 - Does the device implement the StartUpMode attribute? - 89.2.2. Attributes - allclusters.html[pdf] - O - false - - - RVCCLEANM.S.A0003 - Does the device implement the OnMode attribute? - 89.2.2. Attributes - allclusters.html[pdf] - M - false - @@ -78,7 +69,7 @@ Draft RVCCLEANM.S.C01.Tx Does the device implement sending the ChangeToModeResponse command? - 89.2.4. Commands generated - allclusters.html[pdf] + 99.2.3. Commands generated - allclusters.html[pdf] M true @@ -88,7 +79,7 @@ Draft RVCCLEANM.S.C00.Rsp Does the device implement receiving the ChangeToMode command? - 89.2.3. Commands received - allclusters.html[pdf] + 99.2.2. Commands received - allclusters.html[pdf] M true @@ -96,9 +87,9 @@ Draft - RVCCLEANM.S.F00 - Does the device support depending on an On/Off cluster implemented on the same endpoint? - 89.2.1. Features - allclusters.html[pdf] + RVCCLEANM.S.F16 + Does the device support changing clean modes from non-Idle states? + 101.1. Features - allclusters.html[pdf] O false @@ -108,10 +99,17 @@ Draft RVCCLEANM.S.M.CAN_TEST_MODE_FAILURE Does the DUT support testing the failed ChangeToMode command? - 89.2.5. Manual controllable - allclusters.html[pdf] + 99.2.4. Manual controllable - allclusters.html[pdf] O true + + RVCCLEANM.S.M.CAN_MANUALLY_CONTROLLED + Can the mode change be manually controlled? + 99.2.4. Manual controllable - allclusters.html[pdf] + O + false + diff --git a/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml index c600445a35964a..59028fa95e2822 100644 --- a/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml +++ b/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml @@ -1,11 +1,11 @@ RVC Operational State Cluster Test Plan @@ -15,8 +15,8 @@ Draft RVCOPSTATE.S - Does the device implement the RVC Operational State cluster as a server? - 223.1. Role - allclusters.html[pdf] + Does the device implement the RVC Operational State Cluster as a server? + 238.1. Role - allclusters.html[pdf] O true @@ -30,42 +30,42 @@ Draft RVCOPSTATE.S.A0000 Does the device implement the PhaseList attribute? - 223.2.1. Attributes - allclusters.html[pdf] + 238.2.1. Attributes - allclusters.html[pdf] M true RVCOPSTATE.S.A0001 Does the device implement the CurrentPhase attribute? - 223.2.1. Attributes - allclusters.html[pdf] + 238.2.1. Attributes - allclusters.html[pdf] M true RVCOPSTATE.S.A0002 Does the device implement the CountdownTime attribute? - 223.2.1. Attributes - allclusters.html[pdf] + 238.2.1. Attributes - allclusters.html[pdf] O false RVCOPSTATE.S.A0003 Does the device implement the OperationalStateList attribute? - 223.2.1. Attributes - allclusters.html[pdf] + 238.2.1. Attributes - allclusters.html[pdf] M true RVCOPSTATE.S.A0004 Does the device implement the OperationalState attribute? - 223.2.1. Attributes - allclusters.html[pdf] + 238.2.1. Attributes - allclusters.html[pdf] M true RVCOPSTATE.S.A0005 Does the device implement the OperationalError attribute? - 223.2.1. Attributes - allclusters.html[pdf] + 238.2.1. Attributes - allclusters.html[pdf] M true @@ -75,14 +75,14 @@ Draft RVCOPSTATE.S.E00 Does the device implement the OperationalError Event ? - 223.2.4. Events - allclusters.html[pdf] + 238.2.4. Events - allclusters.html[pdf] M true RVCOPSTATE.S.E01 Does the device implement the OperationCompletion Event ? - 223.2.4. Events - allclusters.html[pdf] + 238.2.4. Events - allclusters.html[pdf] O true @@ -92,8 +92,8 @@ Draft RVCOPSTATE.S.C04.Tx Does the device implement generating the OperationalCommandResponse command? - 223.2.3. Commands generated - allclusters.html[pdf] - M + 238.2.3. Commands generated - allclusters.html[pdf] + M true @@ -102,28 +102,35 @@ Draft RVCOPSTATE.S.C00.Rsp Does the device implement receiving the Pause command? - 223.2.2. Commands received - allclusters.html[pdf] + 238.2.2. Commands received - allclusters.html[pdf] O true RVCOPSTATE.S.C01.Rsp Does the device implement receiving the Stop command? - 223.2.2. Commands received - allclusters.html[pdf] + 238.2.2. Commands received - allclusters.html[pdf] O false RVCOPSTATE.S.C02.Rsp Does the device implement receiving the Start command? - 223.2.2. Commands received - allclusters.html[pdf] + 238.2.2. Commands received - allclusters.html[pdf] O false RVCOPSTATE.S.C03.Rsp Does the device implement receiving the Resume command? - 223.2.2. Commands received - allclusters.html[pdf] + 238.2.2. Commands received - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.C80.Rsp + Does the device implement receiving the GoHome command? + 238.2.2. Commands received - allclusters.html[pdf] O true @@ -135,136 +142,143 @@ Draft RVCOPSTATE.S.M.ST_STOPPED Does the DUT support testing the Stopped(0x00) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ST_RUNNING Does the DUT support testing the Running(0x01) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ST_PAUSED Does the DUT support testing the Paused(0x02) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ST_ERROR Does the DUT support testing the Error(0x03) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ST_SEEKING_CHARGER Does the DUT support testing the SeekingCharger(0x40) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ST_CHARGING Does the DUT support testing the Charging(0x41) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ST_DOCKED Does the DUT support testing the Docked(0x42) operational state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_NO_ERROR Does the DUT support testing the NoError(0x00) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_UNABLE_TO_START_OR_RESUME Does the DUT support testing the UnableToStartOrResume(0x01) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_UNABLE_TO_COMPLETE_OPERATION Does the DUT support testing the UnableToCompleteOperation(0x02) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_COMMAND_INVALID_IN_STATE Does the DUT support testing the CommandInvalidInState(0x03) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_FAILED_TO_FIND_CHARGING_DOCK Does the DUT support testing the FailedToFindChargingDock(0x40) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_STUCK Does the DUT support testing the Stuck(0x41) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_DUST_BIN_MISSING Does the DUT support testing the DustBinMissing(0x42) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_DUST_BIN_FULL Does the DUT support testing the DustBinFull(0x43) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_WATER_TANK_EMPTY Does the DUT support testing the WaterTankEmpty(0x44) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_WATER_TANK_MISSING Does the DUT support testing the WaterTankMissing(0x45) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_WATER_TANK_LID_OPEN Does the DUT support testing the WaterTankLidOpen(0x46) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true RVCOPSTATE.S.M.ERR_MOP_CLEANING_PAD_MISSING Does the DUT support testing the MopCleaningPadMissing(0x47) error state? - 223.2.5. Manual controllable - allclusters.html[pdf] + 238.2.5. Manual controllable - allclusters.html[pdf] O true + + RVCOPSTATE.S.M.RESUME_AFTER_ERR + Does the DUT support testing the Resume command after cleared error? + 238.2.5. Manual controllable - allclusters.html[pdf] + O + false + diff --git a/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml index 0bdd95322e213b..a3305b8b92de51 100644 --- a/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml +++ b/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml @@ -1,13 +1,19 @@ - + RVC Run Mode Cluster Test Plan @@ -16,7 +22,7 @@ Draft RVCRUNM.S Does the device implement the RVCRUNM cluster as a server? - 84.1. Role - allclusters.html[pdf] + 93.1. Role - allclusters.html[pdf] O true @@ -26,16 +32,26 @@ Draft PIXIT.RVCRUNM.MODE_CHANGE_FAIL Id of mode the device will fail to transition to, given its current state - 85. PIXIT Definition - allclusters.html[pdf] - O - 0x02 + 95. PIXIT Definition - allclusters.html[pdf] + O PIXIT.RVCRUNM.MODE_CHANGE_OK Id of mode the device will successfully transition to, given its current state - 85. PIXIT Definition - allclusters.html[pdf] - O - 0x00 + 95. PIXIT Definition - allclusters.html[pdf] + O + + + PIXIT.RVCRUNM.MODE_A + Id of non-Idle mode the device can successfully switch to, given its current state + 95. PIXIT Definition - allclusters.html[pdf] + O0x01 + + + PIXIT.RVCRUNM.MODE_B + Id of non-Idle mode the device can successfully switch to, given its current state + 95. PIXIT Definition - allclusters.html[pdf] + O0x02 @@ -45,31 +61,17 @@ Draft RVCRUNM.S.A0000 Does the device implement the SupportedModes attribute? - 84.2.2. Attributes - allclusters.html[pdf] + 93.2.1. Attributes - allclusters.html[pdf] M true RVCRUNM.S.A0001 Does the device implement the CurrentMode attribute? - 84.2.2. Attributes - allclusters.html[pdf] + 93.2.1. Attributes - allclusters.html[pdf] M true - - RVCRUNM.S.A0002 - Does the device implement the StartUpMode attribute? - 84.2.2. Attributes - allclusters.html[pdf] - O - false - - - RVCRUNM.S.A0003 - Does the device implement the OnMode attribute? - 84.2.2. Attributes - allclusters.html[pdf] - M - false - @@ -78,7 +80,7 @@ Draft RVCRUNM.S.C01.Tx Does the device implement sending the ChangeToModeResponse command? - 84.2.4. Commands generated - allclusters.html[pdf] + 93.2.3. Commands generated - allclusters.html[pdf] M true @@ -88,7 +90,7 @@ Draft RVCRUNM.S.C00.Rsp Does the device implement receiving the ChangeToMode command? - 84.2.3. Commands received - allclusters.html[pdf] + 93.2.2. Commands received - allclusters.html[pdf] M true @@ -96,9 +98,9 @@ Draft - RVCRUNM.S.F00 - Does the device support depending on an On/Off cluster implemented on the same endpoint? - 84.2.1. Features - allclusters.html[pdf] + RVCRUNM.S.F16 + Does the device support support changing run modes from non-Idle states? + 94.1. Features - allclusters.html[pdf] O false @@ -108,10 +110,23 @@ Draft RVCRUNM.S.M.CAN_TEST_MODE_FAILURE Does the DUT support testing the failed ChangeToMode command? - 84.2.5. Manual controllable - allclusters.html[pdf] + 93.2.4. Manual controllable - allclusters.html[pdf] O true + + RVCRUNM.S.M.CAN_MANUALLY_CONTROLLED + Can the mode change be manually controlled? + 93.2.4. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.M.ST_STOPPED | RVCOPSTATE.M.ST_PAUSED | RVCOPSTATE.M.ST_CHARGING | RVCOPSTATE.M.ST_DOCKED + 97.2.2. [TC-RVCRUNM-2.2] Change to Mode restrictions with DUT as Server - allclusters.html[pdf] + O + true + diff --git a/examples/rvc-app/rvc-common/pics/Service Area Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/Service Area Cluster Test Plan.xml new file mode 100644 index 00000000000000..665504f1a2a6bb --- /dev/null +++ b/examples/rvc-app/rvc-common/pics/Service Area Cluster Test Plan.xml @@ -0,0 +1,243 @@ + + + Service Area Cluster Test Plan + + + + + + SEAR.S + Does the device implement the Service Area cluster as a server? + 306.1. Role - allclusters.html[pdf] + O + true + + + + + + + + + + SEAR.S.A0000 + Does the device implement the SupportedAreas attribute? + 306.2.2. Attributes - allclusters.html[pdf] + M + true + + + SEAR.S.A0001 + Does the device implement the SupportedMaps attribute? + 306.2.2. Attributes - allclusters.html[pdf] + M + true + + + SEAR.S.A0002 + Does the device implement the SelectedAreas attribute? + 306.2.2. Attributes - allclusters.html[pdf] + M + true + + + SEAR.S.A0003 + Does the device implement the CurrentArea attribute? + 306.2.2. Attributes - allclusters.html[pdf] + O + true + + + SEAR.S.A0004 + Does the device implement the EstimatedEndTime attribute? + 306.2.2. Attributes - allclusters.html[pdf] + O + true + + + SEAR.S.A0005 + Does the device implement the Progress attribute? + 306.2.2. Attributes - allclusters.html[pdf] + M + true + + + + + + + + SEAR.S.C01.Tx + Does the device implement generating the SelectAreasResponse command? + 306.2.4. Commands generated - allclusters.html[pdf] + M + true + + + SEAR.S.C03.Tx + Does the device implement generating the SkipAreaResponse command? + 306.2.4. Commands generated - allclusters.html[pdf] + M + true + + + + + + SEAR.S.C00.Rsp + Does the device implement receiving the SelectAreas command? + 306.2.3. Commands received - allclusters.html[pdf] + M + true + + + SEAR.S.C02.Rsp + Does the device implement receiving the SkipArea command? + 306.2.3. Commands received - allclusters.html[pdf] + O + true + + + + + + SEAR.S.F00 + Does the device support changing the selected areas while running? + 306.2.1. Features - allclusters.html[pdf] + O + false + + + SEAR.S.F01 + Does the device support reporting the progress? + 306.2.1. Features - allclusters.html[pdf] + O + true + + + SEAR.S.F02 + Does the device support the maps feature? + 306.2.1. Features - allclusters.html[pdf] + O + true + + + + + + SEAR.S.M.REMOVE_AREA + Does the DUT support testing the effects of removing a SupportedAreas entry? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.ADD_AREA + Does the DUT support testing the effects of adding a SupportedAreas entry? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.REMOVE_MAP + Does the DUT support testing the effects of removing a SupportedMaps entry? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.ADD_MAP + Does the DUT support testing the effects of adding a SupportedMaps entry? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.INVALID_STATE_FOR_SELECT_AREAS + Does the DUT support testing the selecting areas while the device doesn’t allow that? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.VALID_STATE_FOR_SELECT_AREAS + Does the DUT support testing the selecting areas while the device allows that? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + false + + + SEAR.S.M.SELECT_AREAS_WHILE_NON_IDLE + Does the DUT support testing the selecting areas while the device is a non-idle state? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.HAS_MANUAL_SELAREA_STATE_CONTROL + Can the device state affecting SelectAreas be manually controlled? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.HAS_MANUAL_SKIP_STATE_CONTROL + Can the device state affecting SkipArea be manually controlled? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.INVALID_STATE_FOR_SKIP + Does the DUT support testing the SkipArea command while the device doesn’t allow that? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.NO_SELAREA_FOR_SKIP + Does the DUT support testing the SkipArea command while SelectedAreas is null? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.VALID_STATE_FOR_SKIP + Does the DUT support testing the SkipArea command while the device allows that? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + SEAR.S.M.HAS_MANUAL_OPERATING_STATE_CONTROL + Can the device operating state (idle, operating, terminate operating) be manually controlled? + 306.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/rvc-app/rvc-common/src/rvc-device.cpp b/examples/rvc-app/rvc-common/src/rvc-device.cpp index 623c95963f8834..dac7db9e43708e 100644 --- a/examples/rvc-app/rvc-common/src/rvc-device.cpp +++ b/examples/rvc-app/rvc-common/src/rvc-device.cpp @@ -174,7 +174,7 @@ bool RvcDevice::SaIsSetSelectedAreasAllowed(MutableCharSpan & statusText) return true; } -bool RvcDevice::SaHandleSkipCurrentArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) +bool RvcDevice::SaHandleSkipArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) { if (mServiceAreaInstance.GetCurrentArea() != skippedArea) { diff --git a/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp b/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp index 984472977a0356..9041efd3d9105b 100644 --- a/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp +++ b/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp @@ -180,9 +180,9 @@ bool RvcServiceAreaDelegate::IsValidSelectAreasSet(const Commands::SelectAreas:: return true; }; -bool RvcServiceAreaDelegate::HandleSkipCurrentArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) +bool RvcServiceAreaDelegate::HandleSkipArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) { - return (mHandleSkipCurrentAreaDeviceInstance->*mHandleSkipCurrentAreaCallback)(skippedArea, skipStatusText); + return (mHandleSkipAreaDeviceInstance->*mHandleSkipAreaCallback)(skippedArea, skipStatusText); }; //************************************************************************* diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index bf21adf48e22d1..8ab6e2ca4e0d58 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -110,10 +110,9 @@ def BuildHostTarget(): TargetPart('all-clusters-minimal', app=HostApp.ALL_CLUSTERS_MINIMAL), TargetPart('chip-tool', app=HostApp.CHIP_TOOL), TargetPart('thermostat', app=HostApp.THERMOSTAT), - TargetPart('java-matter-controller', - app=HostApp.JAVA_MATTER_CONTROLLER), - TargetPart('kotlin-matter-controller', - app=HostApp.KOTLIN_MATTER_CONTROLLER), + # TODO: controllers depending on a datamodel is odd. For now fix compile dependencies on ember. + TargetPart('java-matter-controller', app=HostApp.JAVA_MATTER_CONTROLLER, data_model_interface="disabled"), + TargetPart('kotlin-matter-controller', app=HostApp.KOTLIN_MATTER_CONTROLLER, data_model_interface="disabled"), TargetPart('minmdns', app=HostApp.MIN_MDNS), TargetPart('light', app=HostApp.LIGHT), TargetPart('lock', app=HostApp.LOCK), @@ -189,6 +188,9 @@ def BuildHostTarget(): target.AppendModifier('enable-dnssd-tests', enable_dnssd_tests=True).OnlyIfRe('-tests') target.AppendModifier('disable-dnssd-tests', enable_dnssd_tests=False).OnlyIfRe('-tests') target.AppendModifier('chip-casting-simplified', chip_casting_simplified=True).OnlyIfRe('-tv-casting-app') + target.AppendModifier('data-model-check', data_model_interface="check").ExceptIfRe('-data-model-(enabled|disabled)') + target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-(check|enabled)') + target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-(check|disabled)') return target diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index 4ea5a9aae0f836..8c03ac7b133501 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -317,7 +317,8 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, minmdns_high_verbosity=False, imgui_ui=False, crypto_library: HostCryptoLibrary = None, enable_test_event_triggers=None, enable_dnssd_tests: Optional[bool] = None, - chip_casting_simplified: Optional[bool] = None + chip_casting_simplified: Optional[bool] = None, + data_model_interface: Optional[bool] = None, ): super(HostBuilder, self).__init__( root=os.path.join(root, 'examples', app.ExamplePath()), @@ -352,6 +353,9 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, if use_ubsan: self.extra_gn_options.append('is_ubsan=true') + if data_model_interface is not None: + self.extra_gn_options.append(f'chip_use_data_model_interface="{data_model_interface}"') + if use_dmalloc: self.extra_gn_options.append('chip_config_memory_debug_checks=true') self.extra_gn_options.append('chip_config_memory_debug_dmalloc=true') @@ -457,10 +461,6 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, if self.app == HostApp.SIMULATED_APP2: self.extra_gn_options.append('chip_tests_zap_config="app2"') - if self.app in {HostApp.JAVA_MATTER_CONTROLLER, HostApp.KOTLIN_MATTER_CONTROLLER}: - # TODO: controllers depending on a datamodel is odd. For now fix compile dependencies on ember. - self.extra_gn_options.append('chip_use_data_model_interface="disabled"') - if self.app == HostApp.TESTS and fuzzing_type != HostFuzzingType.NONE: self.build_command = 'fuzz_tests' diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index a8e5b8770caa63..d202b8aea3c8fb 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -9,7 +9,7 @@ efr32-{brd2704b,brd4316a,brd4317a,brd4318a,brd4319a,brd4186a,brd4187a,brd2601b,b esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing] genio-lighting-app linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-coverage][-dmalloc][-clang] -linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified] +linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-data-model-check][-data-model-disabled][-data-model-enabled] linux-x64-efr32-test-runner[-clang] imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release] infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage][-trustm] diff --git a/scripts/py_matter_yamltests/matter_yamltests/runner.py b/scripts/py_matter_yamltests/matter_yamltests/runner.py index 541a261a43b4b2..05fe8fc54e851c 100644 --- a/scripts/py_matter_yamltests/matter_yamltests/runner.py +++ b/scripts/py_matter_yamltests/matter_yamltests/runner.py @@ -162,7 +162,8 @@ async def _run_with_timeout(self, parser: TestParser, config: TestRunnerConfig): try: if config.auto_start_stop: await self.start() - status = await asyncio.wait_for(self._run(parser, config), parser.timeout) + task = self._run(parser, config) + status = await asyncio.wait_for(asyncio.shield(task), parser.timeout) except (Exception, CancelledError) as exception: status = exception finally: diff --git a/src/app/WriteHandler.cpp b/src/app/WriteHandler.cpp index 8d4a82d11630c4..15776eb545fc21 100644 --- a/src/app/WriteHandler.cpp +++ b/src/app/WriteHandler.cpp @@ -16,7 +16,6 @@ * limitations under the License. */ -#include "messaging/ExchangeContext.h" #include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include @@ -62,7 +62,7 @@ void WriteHandler::Close() // successful. DeliverFinalListWriteEnd(false /* wasSuccessful */); mExchangeCtx.Release(); - mSuppressResponse = false; + mStateFlags.Clear(StateBits::kSuppressResponse); MoveToState(State::Uninitialized); } @@ -106,7 +106,7 @@ Status WriteHandler::OnWriteRequest(Messaging::ExchangeContext * apExchangeConte Status status = HandleWriteRequestMessage(apExchangeContext, std::move(aPayload), aIsTimedWrite); // The write transaction will be alive only when the message was handled successfully and there are more chunks. - if (!(status == Status::Success && mHasMoreChunks)) + if (!(status == Status::Success && mStateFlags.Has(StateBits::kHasMoreChunks))) { Close(); } @@ -142,7 +142,7 @@ CHIP_ERROR WriteHandler::OnMessageReceived(Messaging::ExchangeContext * apExchan if (status == Status::Success) { // We have no more chunks, the write response has been sent in HandleWriteRequestMessage, so close directly. - if (!mHasMoreChunks) + if (!mStateFlags.Has(StateBits::kHasMoreChunks)) { Close(); } @@ -184,8 +184,8 @@ CHIP_ERROR WriteHandler::SendWriteResponse(System::PacketBufferTLVWriter && aMes VerifyOrExit(mExchangeCtx, err = CHIP_ERROR_INCORRECT_STATE); mExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime); err = mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::WriteResponse, std::move(packet), - mHasMoreChunks ? Messaging::SendMessageFlags::kExpectResponse - : Messaging::SendMessageFlags::kNone); + mStateFlags.Has(StateBits::kHasMoreChunks) ? Messaging::SendMessageFlags::kExpectResponse + : Messaging::SendMessageFlags::kNone); SuccessOrExit(err); MoveToState(State::Sending); @@ -212,7 +212,7 @@ void WriteHandler::DeliverListWriteEnd(const ConcreteAttributePath & aPath, bool void WriteHandler::DeliverFinalListWriteEnd(bool writeWasSuccessful) { - if (mProcessingAttributePath.HasValue() && mProcessingAttributeIsList) + if (mProcessingAttributePath.HasValue() && mStateFlags.Has(StateBits::kProcessingAttributeIsList)) { DeliverListWriteEnd(mProcessingAttributePath.Value(), writeWasSuccessful); } @@ -221,7 +221,8 @@ void WriteHandler::DeliverFinalListWriteEnd(bool writeWasSuccessful) CHIP_ERROR WriteHandler::DeliverFinalListWriteEndForGroupWrite(bool writeWasSuccessful) { - VerifyOrReturnError(mProcessingAttributePath.HasValue() && mProcessingAttributeIsList, CHIP_NO_ERROR); + VerifyOrReturnError(mProcessingAttributePath.HasValue() && mStateFlags.Has(StateBits::kProcessingAttributeIsList), + CHIP_NO_ERROR); Credentials::GroupDataProvider::GroupEndpoint mapping; Credentials::GroupDataProvider * groupDataProvider = Credentials::GetGroupDataProvider(); @@ -321,18 +322,20 @@ CHIP_ERROR WriteHandler::ProcessAttributeDataIBs(TLV::TLVReader & aAttributeData continue; } - if (ShouldReportListWriteEnd(mProcessingAttributePath, mProcessingAttributeIsList, dataAttributePath)) + if (ShouldReportListWriteEnd(mProcessingAttributePath, mStateFlags.Has(StateBits::kProcessingAttributeIsList), + dataAttributePath)) { - DeliverListWriteEnd(mProcessingAttributePath.Value(), mAttributeWriteSuccessful); + DeliverListWriteEnd(mProcessingAttributePath.Value(), mStateFlags.Has(StateBits::kAttributeWriteSuccessful)); } - if (ShouldReportListWriteBegin(mProcessingAttributePath, mProcessingAttributeIsList, dataAttributePath)) + if (ShouldReportListWriteBegin(mProcessingAttributePath, mStateFlags.Has(StateBits::kProcessingAttributeIsList), + dataAttributePath)) { DeliverListWriteBegin(dataAttributePath); - mAttributeWriteSuccessful = true; + mStateFlags.Set(StateBits::kAttributeWriteSuccessful); } - mProcessingAttributeIsList = dataAttributePath.IsListOperation(); + mStateFlags.Set(StateBits::kProcessingAttributeIsList, dataAttributePath.IsListOperation()); mProcessingAttributePath.SetValue(dataAttributePath); DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Write, @@ -370,9 +373,9 @@ CHIP_ERROR WriteHandler::ProcessAttributeDataIBs(TLV::TLVReader & aAttributeData SuccessOrExit(err); - if (!mHasMoreChunks) + if (!mStateFlags.Has(StateBits::kHasMoreChunks)) { - DeliverFinalListWriteEnd(mAttributeWriteSuccessful); + DeliverFinalListWriteEnd(mStateFlags.Has(StateBits::kAttributeWriteSuccessful)); } exit: @@ -426,8 +429,8 @@ CHIP_ERROR WriteHandler::ProcessGroupAttributeDataIBs(TLV::TLVReader & aAttribut iterator = groupDataProvider->IterateEndpoints(fabric); VerifyOrExit(iterator != nullptr, err = CHIP_ERROR_NO_MEMORY); - bool shouldReportListWriteEnd = - ShouldReportListWriteEnd(mProcessingAttributePath, mProcessingAttributeIsList, dataAttributePath); + bool shouldReportListWriteEnd = ShouldReportListWriteEnd( + mProcessingAttributePath, mStateFlags.Has(StateBits::kProcessingAttributeIsList), dataAttributePath); bool shouldReportListWriteBegin = false; // This will be set below. const EmberAfAttributeMetadata * attributeMetadata = nullptr; @@ -457,7 +460,8 @@ CHIP_ERROR WriteHandler::ProcessGroupAttributeDataIBs(TLV::TLVReader & aAttribut dataAttributePath.mEndpointId, dataAttributePath.mListOp, dataAttributePath.mListIndex); shouldReportListWriteBegin = - ShouldReportListWriteBegin(mProcessingAttributePath, mProcessingAttributeIsList, pathForCheckingListWriteBegin); + ShouldReportListWriteBegin(mProcessingAttributePath, mStateFlags.Has(StateBits::kProcessingAttributeIsList), + pathForCheckingListWriteBegin); } if (shouldReportListWriteEnd) @@ -498,11 +502,10 @@ CHIP_ERROR WriteHandler::ProcessGroupAttributeDataIBs(TLV::TLVReader & aAttribut DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Write, DataModelCallbacks::OperationOrder::Pre, dataAttributePath); err = WriteSingleClusterData(subjectDescriptor, dataAttributePath, tmpDataReader, this); - if (err != CHIP_NO_ERROR) { ChipLogError(DataManagement, - "WriteSingleClusterData Endpoint=%u Cluster=" ChipLogFormatMEI " Attribute =" ChipLogFormatMEI + "WriteClusterData Endpoint=%u Cluster=" ChipLogFormatMEI " Attribute =" ChipLogFormatMEI " failed: %" CHIP_ERROR_FORMAT, mapping.endpoint_id, ChipLogValueMEI(dataAttributePath.mClusterId), ChipLogValueMEI(dataAttributePath.mAttributeId), err.Format()); @@ -512,7 +515,7 @@ CHIP_ERROR WriteHandler::ProcessGroupAttributeDataIBs(TLV::TLVReader & aAttribut } dataAttributePath.mEndpointId = kInvalidEndpointId; - mProcessingAttributeIsList = dataAttributePath.IsListOperation(); + mStateFlags.Set(StateBits::kProcessingAttributeIsList, dataAttributePath.IsListOperation()); mProcessingAttributePath.SetValue(dataAttributePath); iterator->Release(); } @@ -557,24 +560,33 @@ Status WriteHandler::ProcessWriteRequest(System::PacketBufferHandle && aPayload, #if CHIP_CONFIG_IM_PRETTY_PRINT writeRequestParser.PrettyPrint(); #endif - err = writeRequestParser.GetSuppressResponse(&mSuppressResponse); + bool boolValue; + + boolValue = mStateFlags.Has(StateBits::kSuppressResponse); + err = writeRequestParser.GetSuppressResponse(&boolValue); if (err == CHIP_END_OF_TLV) { err = CHIP_NO_ERROR; } SuccessOrExit(err); + mStateFlags.Set(StateBits::kSuppressResponse, boolValue); - err = writeRequestParser.GetTimedRequest(&mIsTimedRequest); + boolValue = mStateFlags.Has(StateBits::kIsTimedRequest); + err = writeRequestParser.GetTimedRequest(&boolValue); SuccessOrExit(err); + mStateFlags.Set(StateBits::kIsTimedRequest, boolValue); - err = writeRequestParser.GetMoreChunkedMessages(&mHasMoreChunks); + boolValue = mStateFlags.Has(StateBits::kHasMoreChunks); + err = writeRequestParser.GetMoreChunkedMessages(&boolValue); if (err == CHIP_ERROR_END_OF_TLV) { err = CHIP_NO_ERROR; } SuccessOrExit(err); + mStateFlags.Set(StateBits::kHasMoreChunks, boolValue); - if (mHasMoreChunks && (mExchangeCtx->IsGroupExchangeContext() || mIsTimedRequest)) + if (mStateFlags.Has(StateBits::kHasMoreChunks) && + (mExchangeCtx->IsGroupExchangeContext() || mStateFlags.Has(StateBits::kIsTimedRequest))) { // Sanity check: group exchange context should only have one chunk. // Also, timed requests should not have more than one chunk. @@ -584,7 +596,7 @@ Status WriteHandler::ProcessWriteRequest(System::PacketBufferHandle && aPayload, err = writeRequestParser.GetWriteRequests(&AttributeDataIBsParser); SuccessOrExit(err); - if (mIsTimedRequest != aIsTimedWrite) + if (mStateFlags.Has(StateBits::kIsTimedRequest) != aIsTimedWrite) { // The message thinks it should be part of a timed interaction but it's // not, or vice versa. @@ -641,7 +653,7 @@ CHIP_ERROR WriteHandler::AddStatusInternal(const ConcreteDataAttributePath & aPa if (!aStatus.IsSuccess()) { - mAttributeWriteSuccessful = false; + mStateFlags.Clear(StateBits::kAttributeWriteSuccessful); } ReturnErrorOnFailure(writeResponses.GetError()); diff --git a/src/app/WriteHandler.h b/src/app/WriteHandler.h index 1884654f070710..0723a316738498 100644 --- a/src/app/WriteHandler.h +++ b/src/app/WriteHandler.h @@ -17,12 +17,15 @@ */ #pragma once + +#include #include #include #include #include #include #include +#include #include #include #include @@ -68,9 +71,11 @@ class WriteHandler : public Messaging::ExchangeDelegate * * @param[in] apWriteHandlerDelegate A Valid pointer to the WriteHandlerDelegate. * + * @retval #CHIP_ERROR_INVALID_ARGUMENT on invalid pointers * @retval #CHIP_ERROR_INCORRECT_STATE If the state is not equal to * kState_NotInitialized. * @retval #CHIP_NO_ERROR On success. + * */ CHIP_ERROR Init(WriteHandlerDelegate * apWriteHandlerDelegate); @@ -115,7 +120,7 @@ class WriteHandler : public Messaging::ExchangeDelegate /** * Check whether the WriteRequest we are handling is a timed write. */ - bool IsTimedWrite() const { return mIsTimedRequest; } + bool IsTimedWrite() const { return mStateFlags.Has(StateBits::kIsTimedRequest); } bool MatchesExchangeContext(Messaging::ExchangeContext * apExchangeContext) const { @@ -136,7 +141,7 @@ class WriteHandler : public Messaging::ExchangeDelegate private: friend class TestWriteInteraction; - enum class State + enum class State : uint8_t { Uninitialized = 0, // The handler has not been initialized Initialized, // The handler has been initialized and is ready @@ -172,7 +177,6 @@ class WriteHandler : public Messaging::ExchangeDelegate CHIP_ERROR AddStatusInternal(const ConcreteDataAttributePath & aPath, const StatusIB & aStatus); -private: // ExchangeDelegate CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) override; @@ -180,22 +184,7 @@ class WriteHandler : public Messaging::ExchangeDelegate Messaging::ExchangeHolder mExchangeCtx; WriteResponseMessage::Builder mWriteResponseBuilder; - State mState = State::Uninitialized; - bool mIsTimedRequest = false; - bool mSuppressResponse = false; - bool mHasMoreChunks = false; Optional mProcessingAttributePath; - bool mProcessingAttributeIsList = false; - // We record the Status when AddStatus is called to determine whether all data of a list write is accepted. - // This value will be used by DeliverListWriteEnd and DeliverFinalListWriteEnd but it won't be used by group writes based on the - // fact that the errors that won't be delivered to AttributeAccessInterface are: - // (1) Attribute not found - // (2) Access control failed - // (3) Write request to a read-only attribute - // (4) Data version mismatch - // (5) Not using timed write. - // Where (1)-(3) will be consistent among the whole list write request, while (4) and (5) are not appliable to group writes. - bool mAttributeWriteSuccessful = false; Optional mACLCheckCache = NullOptional; // This may be a "fake" pointer or a real delegate pointer, depending @@ -205,6 +194,31 @@ class WriteHandler : public Messaging::ExchangeDelegate // set to the global InteractionModelEngine and the size of this // member is 1 byte. InteractionModelDelegatePointer mDelegate; + + // bit level enums to save storage for this object. InteractionModelEngine maintains + // several of these objects, so every bit of storage multiplies storage usage. + enum class StateBits : uint8_t + { + kIsTimedRequest = 0x01, + kSuppressResponse = 0x02, + kHasMoreChunks = 0x04, + kProcessingAttributeIsList = 0x08, + // We record the Status when AddStatus is called to determine whether all data of a list write is accepted. + // This value will be used by DeliverListWriteEnd and DeliverFinalListWriteEnd but it won't be used by group writes based on + // the fact that the errors that won't be delivered to AttributeAccessInterface are: + // (1) Attribute not found + // (2) Access control failed + // (3) Write request to a read-only attribute + // (4) Data version mismatch + // (5) Not using timed write. + // Where (1)-(3) will be consistent among the whole list write request, while (4) and (5) are not appliable to group + // writes. + kAttributeWriteSuccessful = 0x10, + }; + + BitFlags mStateFlags; + State mState = State::Uninitialized; }; + } // namespace app } // namespace chip diff --git a/src/app/clusters/service-area-server/service-area-delegate.h b/src/app/clusters/service-area-server/service-area-delegate.h index 01df2faeb06488..2e9422840aa847 100644 --- a/src/app/clusters/service-area-server/service-area-delegate.h +++ b/src/app/clusters/service-area-server/service-area-delegate.h @@ -120,7 +120,7 @@ class Delegate * InvalidInMode, the StatusText field SHOULD indicate why the request is not allowed, given the current mode of the * device, which may involve other clusters. */ - virtual bool HandleSkipCurrentArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) + virtual bool HandleSkipArea(uint32_t skippedArea, MutableCharSpan & skipStatusText) { // device support of this command is optional CopyCharSpanToMutableCharSpan("Skip Current Area command not supported by device"_span, skipStatusText); diff --git a/src/app/clusters/service-area-server/service-area-server.cpp b/src/app/clusters/service-area-server/service-area-server.cpp index 0e562c78754d5b..a7e81278838ae6 100644 --- a/src/app/clusters/service-area-server/service-area-server.cpp +++ b/src/app/clusters/service-area-server/service-area-server.cpp @@ -123,7 +123,7 @@ void Instance::InvokeCommand(HandlerContext & handlerContext) case Commands::SkipArea::Id: return CommandHandlerInterface::HandleCommand( - handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleSkipCurrentAreaCmd(ctx, req); }); + handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleSkipAreaCmd(ctx, req); }); } } @@ -356,11 +356,11 @@ void Instance::HandleSelectAreasCmd(HandlerContext & ctx, const Commands::Select exitResponse(SelectAreasStatus::kSuccess, ""_span); } -void Instance::HandleSkipCurrentAreaCmd(HandlerContext & ctx, const Commands::SkipArea::DecodableType & req) +void Instance::HandleSkipAreaCmd(HandlerContext & ctx, const Commands::SkipArea::DecodableType & req) { - ChipLogDetail(Zcl, "Service Area: HandleSkipCurrentArea"); + ChipLogDetail(Zcl, "Service Area: HandleSkipArea"); - // On receipt of this command the device SHALL respond with a SkipCurrentAreaResponse command. + // On receipt of this command the device SHALL respond with a SkipAreaResponse command. auto exitResponse = [ctx](SkipAreaStatus status, CharSpan statusText) { Commands::SkipAreaResponse::Type response{ .status = status, @@ -369,11 +369,11 @@ void Instance::HandleSkipCurrentAreaCmd(HandlerContext & ctx, const Commands::Sk ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); }; - // If the SelectedAreas attribute is null, the response status should be set to InvalidAreaList. + // The SkippedArea field SHALL match an entry in the SupportedAreas list. // If the Status field is set to InvalidAreaList, the StatusText field SHALL be an empty string. - if (mDelegate->GetNumberOfSelectedAreas() == 0) + if (!IsSupportedArea(req.skippedArea)) { - ChipLogError(Zcl, "Selected Areas attribute is null"); + ChipLogError(Zcl, "SkippedArea (%u) is not in the SupportedAreas attribute.", req.skippedArea); exitResponse(SkipAreaStatus::kInvalidAreaList, ""_span); return; } @@ -394,7 +394,7 @@ void Instance::HandleSkipCurrentAreaCmd(HandlerContext & ctx, const Commands::Sk char skipStatusBuffer[kMaxSizeStatusText]; MutableCharSpan skipStatusText(skipStatusBuffer); - if (!mDelegate->HandleSkipCurrentArea(req.skippedArea, skipStatusText)) + if (!mDelegate->HandleSkipArea(req.skippedArea, skipStatusText)) { exitResponse(SkipAreaStatus::kInvalidInMode, skipStatusText); return; diff --git a/src/app/clusters/service-area-server/service-area-server.h b/src/app/clusters/service-area-server/service-area-server.h index 811499f3ff7fb2..e023f24d129261 100644 --- a/src/app/clusters/service-area-server/service-area-server.h +++ b/src/app/clusters/service-area-server/service-area-server.h @@ -124,7 +124,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface * If the input value is invalid, returns the Interaction Model status code of INVALID_COMMAND. * @param[in] req the command parameters. */ - void HandleSkipCurrentAreaCmd(HandlerContext & ctx, const Commands::SkipArea::DecodableType & req); + void HandleSkipAreaCmd(HandlerContext & ctx, const Commands::SkipArea::DecodableType & req); //************************************************************************* // attribute notifications diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h index a28aea640ba46e..f9f7aed04e4253 100644 --- a/src/include/platform/ThreadStackManager.h +++ b/src/include/platform/ThreadStackManager.h @@ -105,6 +105,7 @@ class ThreadStackManager CHIP_ERROR GetAndLogThreadTopologyFull(); CHIP_ERROR GetPrimary802154MACAddress(uint8_t * buf); CHIP_ERROR GetExternalIPv6Address(chip::Inet::IPAddress & addr); + CHIP_ERROR GetThreadVersion(uint16_t & version); CHIP_ERROR GetPollPeriod(uint32_t & buf); CHIP_ERROR SetThreadProvision(ByteSpan aDataset); @@ -444,6 +445,11 @@ inline CHIP_ERROR ThreadStackManager::GetExternalIPv6Address(chip::Inet::IPAddre return static_cast(this)->_GetExternalIPv6Address(addr); } +inline CHIP_ERROR ThreadStackManager::GetThreadVersion(uint16_t & version) +{ + return static_cast(this)->_GetThreadVersion(version); +} + inline CHIP_ERROR ThreadStackManager::GetPollPeriod(uint32_t & buf) { return static_cast(this)->_GetPollPeriod(buf); diff --git a/src/platform/Linux/NetworkCommissioningThreadDriver.cpp b/src/platform/Linux/NetworkCommissioningThreadDriver.cpp index 9bb6015809fc9a..6792e9c04439e8 100644 --- a/src/platform/Linux/NetworkCommissioningThreadDriver.cpp +++ b/src/platform/Linux/NetworkCommissioningThreadDriver.cpp @@ -211,9 +211,9 @@ ThreadCapabilities LinuxThreadDriver::GetSupportedThreadFeatures() uint16_t LinuxThreadDriver::GetThreadVersion() { - // TODO https://github.com/project-chip/connectedhomeip/issues/30602 - // Needs to be implemented with DBUS io.openthread.BorderRouter Thread API - return 0; + uint16_t version = 0; + ThreadStackMgrImpl().GetThreadVersion(version); + return version; } #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD diff --git a/src/platform/Linux/ThreadStackManagerImpl.cpp b/src/platform/Linux/ThreadStackManagerImpl.cpp index 126d30164492fe..76fd478a050f89 100644 --- a/src/platform/Linux/ThreadStackManagerImpl.cpp +++ b/src/platform/Linux/ThreadStackManagerImpl.cpp @@ -563,6 +563,13 @@ CHIP_ERROR ThreadStackManagerImpl::_GetExternalIPv6Address(chip::Inet::IPAddress return CHIP_ERROR_NOT_IMPLEMENTED; } +CHIP_ERROR ThreadStackManagerImpl::_GetThreadVersion(uint16_t & version) +{ + // TODO https://github.com/project-chip/connectedhomeip/issues/30602 + // Needs to be implemented with DBUS io.openthread.BorderRouter Thread API + return CHIP_ERROR_NOT_IMPLEMENTED; +} + CHIP_ERROR ThreadStackManagerImpl::_GetPollPeriod(uint32_t & buf) { // TODO: Remove Weave legacy APIs diff --git a/src/platform/Linux/ThreadStackManagerImpl.h b/src/platform/Linux/ThreadStackManagerImpl.h index e9c1a825d35a91..685348a4ae4a72 100755 --- a/src/platform/Linux/ThreadStackManagerImpl.h +++ b/src/platform/Linux/ThreadStackManagerImpl.h @@ -113,7 +113,7 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf); CHIP_ERROR _GetExternalIPv6Address(chip::Inet::IPAddress & addr); - + CHIP_ERROR _GetThreadVersion(uint16_t & version); CHIP_ERROR _GetPollPeriod(uint32_t & buf); void _ResetThreadNetworkDiagnosticsCounts(); diff --git a/src/platform/NuttX/NetworkCommissioningThreadDriver.cpp b/src/platform/NuttX/NetworkCommissioningThreadDriver.cpp index 79da48d49c0419..27c410400421a8 100644 --- a/src/platform/NuttX/NetworkCommissioningThreadDriver.cpp +++ b/src/platform/NuttX/NetworkCommissioningThreadDriver.cpp @@ -211,9 +211,9 @@ ThreadCapabilities LinuxThreadDriver::GetSupportedThreadFeatures() uint16_t LinuxThreadDriver::GetThreadVersion() { - // TODO https://github.com/project-chip/connectedhomeip/issues/30602 - // Needs to be implemented with DBUS io.openthread.BorderRouter Thread API - return 0; + uint16_t version = 0; + ThreadStackMgrImpl().GetThreadVersion(version); + return version; } #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD diff --git a/src/platform/NuttX/ThreadStackManagerImpl.cpp b/src/platform/NuttX/ThreadStackManagerImpl.cpp index cb717324fc989d..8eb1538128108b 100644 --- a/src/platform/NuttX/ThreadStackManagerImpl.cpp +++ b/src/platform/NuttX/ThreadStackManagerImpl.cpp @@ -568,6 +568,13 @@ CHIP_ERROR ThreadStackManagerImpl::_GetExternalIPv6Address(chip::Inet::IPAddress return CHIP_ERROR_NOT_IMPLEMENTED; } +CHIP_ERROR ThreadStackManagerImpl::_GetThreadVersion(uint16_t & version) +{ + // TODO https://github.com/project-chip/connectedhomeip/issues/30602 + // Needs to be implemented with DBUS io.openthread.BorderRouter Thread API + return CHIP_ERROR_NOT_IMPLEMENTED; +} + CHIP_ERROR ThreadStackManagerImpl::_GetPollPeriod(uint32_t & buf) { // TODO: Remove Weave legacy APIs diff --git a/src/platform/NuttX/ThreadStackManagerImpl.h b/src/platform/NuttX/ThreadStackManagerImpl.h index 5ef3d8ed36555f..ce66d51c2201a2 100644 --- a/src/platform/NuttX/ThreadStackManagerImpl.h +++ b/src/platform/NuttX/ThreadStackManagerImpl.h @@ -114,7 +114,7 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf); CHIP_ERROR _GetExternalIPv6Address(chip::Inet::IPAddress & addr); - + CHIP_ERROR _GetThreadVersion(uint16_t & version); CHIP_ERROR _GetPollPeriod(uint32_t & buf); CHIP_ERROR _JoinerStart(); diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp index 711ad4930f96d4..0e7701ec481add 100644 --- a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp +++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp @@ -325,7 +325,9 @@ ThreadCapabilities GenericThreadDriver::GetSupportedThreadFeatures() uint16_t GenericThreadDriver::GetThreadVersion() { - return otThreadGetVersion(); + uint16_t version = 0; + ThreadStackMgrImpl().GetThreadVersion(version); + return version; } } // namespace NetworkCommissioning diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h index c45ff84bb0f26e..169820c103e828 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h @@ -70,7 +70,7 @@ class GenericThreadStackManagerImpl_OpenThread otInstance * OTInstance() const; static void OnOpenThreadStateChange(uint32_t flags, void * context); - inline void OverrunErrorTally(void); + inline void OverrunErrorTally(); void SetNetworkStatusChangeCallback(NetworkCommissioning::Internal::BaseDriver::NetworkStatusChangeCallback * statusChangeCallback) { @@ -80,21 +80,21 @@ class GenericThreadStackManagerImpl_OpenThread protected: // ===== Methods that implement the ThreadStackManager abstract interface. - void _ProcessThreadActivity(void); + void _ProcessThreadActivity(); bool _HaveRouteToAddress(const Inet::IPAddress & destAddr); void _OnPlatformEvent(const ChipDeviceEvent * event); - bool _IsThreadEnabled(void); + bool _IsThreadEnabled(); CHIP_ERROR _SetThreadEnabled(bool val); - bool _IsThreadProvisioned(void); - bool _IsThreadAttached(void); + bool _IsThreadProvisioned(); + bool _IsThreadAttached(); CHIP_ERROR _GetThreadProvision(Thread::OperationalDataset & dataset); CHIP_ERROR _SetThreadProvision(ByteSpan netInfo); CHIP_ERROR _AttachToThreadNetwork(const Thread::OperationalDataset & dataset, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback); - void _OnThreadAttachFinished(void); - void _ErasePersistentInfo(void); - ConnectivityManager::ThreadDeviceType _GetThreadDeviceType(void); + void _OnThreadAttachFinished(); + void _ErasePersistentInfo(); + ConnectivityManager::ThreadDeviceType _GetThreadDeviceType(); CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType); CHIP_ERROR _StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback); static void _OnNetworkScanFinished(otActiveScanResult * aResult, void * aContext); @@ -105,16 +105,17 @@ class GenericThreadStackManagerImpl_OpenThread CHIP_ERROR _SetPollingInterval(System::Clock::Milliseconds32 pollingInterval); #endif // CHIP_CONFIG_ENABLE_ICD_SERVER - bool _HaveMeshConnectivity(void); - CHIP_ERROR _GetAndLogThreadStatsCounters(void); - CHIP_ERROR _GetAndLogThreadTopologyMinimal(void); - CHIP_ERROR _GetAndLogThreadTopologyFull(void); + bool _HaveMeshConnectivity(); + CHIP_ERROR _GetAndLogThreadStatsCounters(); + CHIP_ERROR _GetAndLogThreadTopologyMinimal(); + CHIP_ERROR _GetAndLogThreadTopologyFull(); CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf); CHIP_ERROR _GetExternalIPv6Address(chip::Inet::IPAddress & addr); - void _ResetThreadNetworkDiagnosticsCounts(void); + CHIP_ERROR _GetThreadVersion(uint16_t & version); + void _ResetThreadNetworkDiagnosticsCounts(); CHIP_ERROR _GetPollPeriod(uint32_t & buf); - void _OnWoBLEAdvertisingStart(void); - void _OnWoBLEAdvertisingStop(void); + void _OnWoBLEAdvertisingStart(); + void _OnWoBLEAdvertisingStop(); #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT CHIP_ERROR _AddSrpService(const char * aInstanceName, const char * aName, uint16_t aPort, @@ -144,8 +145,8 @@ class GenericThreadStackManagerImpl_OpenThread CHIP_ERROR ConfigureThreadStack(otInstance * otInst); CHIP_ERROR DoInit(otInstance * otInst); - bool IsThreadAttachedNoLock(void); - bool IsThreadInterfaceUpNoLock(void); + bool IsThreadAttachedNoLock(); + bool IsThreadInterfaceUpNoLock(); private: // ===== Private members for use by this class only. @@ -282,19 +283,19 @@ inline otInstance * GenericThreadStackManagerImpl_OpenThread::OTInsta } template -inline void GenericThreadStackManagerImpl_OpenThread::OverrunErrorTally(void) +inline void GenericThreadStackManagerImpl_OpenThread::OverrunErrorTally() { mOverrunCount++; } template -inline void GenericThreadStackManagerImpl_OpenThread::_OnWoBLEAdvertisingStart(void) +inline void GenericThreadStackManagerImpl_OpenThread::_OnWoBLEAdvertisingStart() { // Do nothing by default. } template -inline void GenericThreadStackManagerImpl_OpenThread::_OnWoBLEAdvertisingStop(void) +inline void GenericThreadStackManagerImpl_OpenThread::_OnWoBLEAdvertisingStop() { // Do nothing by default. } diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index 61452f5ff0ec90..6916c096c9ce50 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -27,6 +27,7 @@ #define GENERIC_THREAD_STACK_MANAGER_IMPL_OPENTHREAD_IPP #include +#include #include #include @@ -59,7 +60,6 @@ #include #include -#include extern "C" void otSysProcessDrivers(otInstance * aInstance); #if CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI @@ -80,7 +80,7 @@ app::Clusters::NetworkCommissioning::Instance sThreadNetworkCommissioningInstance(CHIP_DEVICE_CONFIG_THREAD_NETWORK_ENDPOINT_ID /* Endpoint Id */, &sGenericThreadDriver); #endif -void initNetworkCommissioningThreadDriver(void) +void initNetworkCommissioningThreadDriver() { #ifndef _NO_GENERIC_THREAD_NETWORK_COMMISSIONING_DRIVER_ sThreadNetworkCommissioningInstance.Init(); @@ -143,7 +143,7 @@ void GenericThreadStackManagerImpl_OpenThread::OnOpenThreadStateChang } template -void GenericThreadStackManagerImpl_OpenThread::_ProcessThreadActivity(void) +void GenericThreadStackManagerImpl_OpenThread::_ProcessThreadActivity() { otTaskletsProcess(mOTInst); otSysProcessDrivers(mOTInst); @@ -256,7 +256,7 @@ void GenericThreadStackManagerImpl_OpenThread::_OnPlatformEvent(const } template -bool GenericThreadStackManagerImpl_OpenThread::_IsThreadEnabled(void) +bool GenericThreadStackManagerImpl_OpenThread::_IsThreadEnabled() { VerifyOrReturnValue(mOTInst, false); otDeviceRole curRole; @@ -330,7 +330,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetThreadProvis } template -bool GenericThreadStackManagerImpl_OpenThread::_IsThreadProvisioned(void) +bool GenericThreadStackManagerImpl_OpenThread::_IsThreadProvisioned() { VerifyOrReturnValue(mOTInst, false); bool provisioned; @@ -363,7 +363,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetThreadProvis } template -bool GenericThreadStackManagerImpl_OpenThread::_IsThreadAttached(void) +bool GenericThreadStackManagerImpl_OpenThread::_IsThreadAttached() { VerifyOrReturnValue(mOTInst, false); otDeviceRole curRole; @@ -525,7 +525,7 @@ void GenericThreadStackManagerImpl_OpenThread::_OnNetworkScanFinished } template -ConnectivityManager::ThreadDeviceType GenericThreadStackManagerImpl_OpenThread::_GetThreadDeviceType(void) +ConnectivityManager::ThreadDeviceType GenericThreadStackManagerImpl_OpenThread::_GetThreadDeviceType() { VerifyOrReturnValue(mOTInst, ConnectivityManager::kThreadDeviceType_NotSupported); ConnectivityManager::ThreadDeviceType deviceType; @@ -651,7 +651,7 @@ GenericThreadStackManagerImpl_OpenThread::_SetThreadDeviceType(Connec } template -bool GenericThreadStackManagerImpl_OpenThread::_HaveMeshConnectivity(void) +bool GenericThreadStackManagerImpl_OpenThread::_HaveMeshConnectivity() { VerifyOrReturnValue(mOTInst, false); bool res; @@ -700,7 +700,7 @@ bool GenericThreadStackManagerImpl_OpenThread::_HaveMeshConnectivity( } template -CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadStatsCounters(void) +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadStatsCounters() { VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; @@ -795,7 +795,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThread } template -CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadTopologyMinimal(void) +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadTopologyMinimal() { VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; @@ -1072,7 +1072,14 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetExternalIPv6 } template -void GenericThreadStackManagerImpl_OpenThread::_ResetThreadNetworkDiagnosticsCounts(void) +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetThreadVersion(uint16_t & version) +{ + version = otThreadGetVersion(); + return CHIP_NO_ERROR; +} + +template +void GenericThreadStackManagerImpl_OpenThread::_ResetThreadNetworkDiagnosticsCounts() { // Based on the spec, only OverrunCount should be resetted. mOverrunCount = 0; @@ -1175,14 +1182,14 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::DoInit(otInstanc } template -bool GenericThreadStackManagerImpl_OpenThread::IsThreadAttachedNoLock(void) +bool GenericThreadStackManagerImpl_OpenThread::IsThreadAttachedNoLock() { otDeviceRole curRole = otThreadGetDeviceRole(mOTInst); return (curRole != OT_DEVICE_ROLE_DISABLED && curRole != OT_DEVICE_ROLE_DETACHED); } template -bool GenericThreadStackManagerImpl_OpenThread::IsThreadInterfaceUpNoLock(void) +bool GenericThreadStackManagerImpl_OpenThread::IsThreadInterfaceUpNoLock() { return otIp6IsEnabled(mOTInst); } @@ -1242,7 +1249,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetPollingInter #endif // CHIP_CONFIG_ENABLE_ICD_SERVER template -void GenericThreadStackManagerImpl_OpenThread::_ErasePersistentInfo(void) +void GenericThreadStackManagerImpl_OpenThread::_ErasePersistentInfo() { VerifyOrReturn(mOTInst); ChipLogProgress(DeviceLayer, "Erasing Thread persistent info..."); diff --git a/src/platform/OpenThread/OpenThreadUtils.cpp b/src/platform/OpenThread/OpenThreadUtils.cpp index 093997c66fb789..f2470b38ce4821 100644 --- a/src/platform/OpenThread/OpenThreadUtils.cpp +++ b/src/platform/OpenThread/OpenThreadUtils.cpp @@ -80,7 +80,7 @@ bool FormatOpenThreadError(char * buf, uint16_t bufSize, CHIP_ERROR err) /** * Register a text error formatter for OpenThread errors. */ -void RegisterOpenThreadErrorFormatter(void) +void RegisterOpenThreadErrorFormatter() { static ErrorFormatter sOpenThreadErrorFormatter = { FormatOpenThreadError, NULL }; diff --git a/src/platform/OpenThread/OpenThreadUtils.h b/src/platform/OpenThread/OpenThreadUtils.h index f9609e8d8728af..ab0cdd06a8aa6f 100644 --- a/src/platform/OpenThread/OpenThreadUtils.h +++ b/src/platform/OpenThread/OpenThreadUtils.h @@ -59,7 +59,7 @@ namespace Internal { #endif // CHIP_CONFIG_OPENTHREAD_ERROR_MAX extern CHIP_ERROR MapOpenThreadError(otError otErr); -extern void RegisterOpenThreadErrorFormatter(void); +extern void RegisterOpenThreadErrorFormatter(); /** * Log information related to a state change in the OpenThread stack. diff --git a/src/platform/Tizen/NetworkCommissioningThreadDriver.cpp b/src/platform/Tizen/NetworkCommissioningThreadDriver.cpp index 003564b4c90f0f..f954e6c2fc67e0 100644 --- a/src/platform/Tizen/NetworkCommissioningThreadDriver.cpp +++ b/src/platform/Tizen/NetworkCommissioningThreadDriver.cpp @@ -28,7 +28,6 @@ #include #include "NetworkCommissioningDriver.h" -#include "ThreadStackManagerImpl.h" namespace chip { namespace DeviceLayer { @@ -38,8 +37,8 @@ namespace NetworkCommissioning { CHIP_ERROR TizenThreadDriver::Init(BaseDriver::NetworkStatusChangeCallback * networkStatusChangeCallback) { - VerifyOrReturnError(ConnectivityMgrImpl().IsThreadAttached(), CHIP_NO_ERROR); - VerifyOrReturnError(ThreadStackMgrImpl().GetThreadProvision(mStagingNetwork) == CHIP_NO_ERROR, CHIP_NO_ERROR); + VerifyOrReturnError(ConnectivityMgr().IsThreadAttached(), CHIP_NO_ERROR); + VerifyOrReturnError(ThreadStackMgr().GetThreadProvision(mStagingNetwork) == CHIP_NO_ERROR, CHIP_NO_ERROR); mSavedNetwork.Init(mStagingNetwork.AsByteSpan()); @@ -133,7 +132,7 @@ void TizenThreadDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * cal (networkId.size() == Thread::kSizeExtendedPanId && memcmp(networkId.data(), extpanid, Thread::kSizeExtendedPanId) == 0), status = Status::kNetworkNotFound); - VerifyOrExit(DeviceLayer::ThreadStackMgrImpl().AttachToThreadNetwork(mStagingNetwork, callback) == CHIP_NO_ERROR, + VerifyOrExit(DeviceLayer::ThreadStackMgr().AttachToThreadNetwork(mStagingNetwork, callback) == CHIP_NO_ERROR, status = Status::kUnknownError); exit: @@ -145,7 +144,7 @@ void TizenThreadDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * cal void TizenThreadDriver::ScanNetworks(ThreadDriver::ScanCallback * callback) { - CHIP_ERROR err = DeviceLayer::ThreadStackMgrImpl().StartThreadScan(callback); + CHIP_ERROR err = DeviceLayer::ThreadStackMgr().StartThreadScan(callback); if (err != CHIP_NO_ERROR) { callback->OnFinished(Status::kUnknownError, CharSpan(), nullptr); @@ -179,8 +178,9 @@ ThreadCapabilities TizenThreadDriver::GetSupportedThreadFeatures() uint16_t TizenThreadDriver::GetThreadVersion() { - // TODO Needs to be implemented with Tizen Thread stack api - return 0; + uint16_t version = 0; + DeviceLayer::ThreadStackMgr().GetThreadVersion(version); + return version; } #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD diff --git a/src/platform/Tizen/ThreadStackManagerImpl.cpp b/src/platform/Tizen/ThreadStackManagerImpl.cpp index 950b6ec300292c..0ae0f8f84ad7c8 100644 --- a/src/platform/Tizen/ThreadStackManagerImpl.cpp +++ b/src/platform/Tizen/ThreadStackManagerImpl.cpp @@ -54,9 +54,12 @@ #include #include +#include #include #include +using chip::DeviceLayer::Internal::TizenToChipError; + namespace chip { namespace DeviceLayer { @@ -514,6 +517,18 @@ CHIP_ERROR ThreadStackManagerImpl::_GetExternalIPv6Address(chip::Inet::IPAddress return CHIP_ERROR_NOT_IMPLEMENTED; } +CHIP_ERROR ThreadStackManagerImpl::_GetThreadVersion(uint16_t & version) +{ + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_UNINITIALIZED); + + int threadErr = thread_get_version(mThreadInstance, &version); + VerifyOrReturnError(threadErr == THREAD_ERROR_NONE, TizenToChipError(threadErr), + ChipLogError(DeviceLayer, "FAIL: Get thread version: %s", get_error_message(threadErr))); + + ChipLogProgress(DeviceLayer, "Thread version [%u]", version); + return CHIP_NO_ERROR; +} + CHIP_ERROR ThreadStackManagerImpl::_GetPollPeriod(uint32_t & buf) { ChipLogError(DeviceLayer, "Not implemented"); diff --git a/src/platform/Tizen/ThreadStackManagerImpl.h b/src/platform/Tizen/ThreadStackManagerImpl.h index 3c0206cfd525fe..2bb0954bc8d25c 100644 --- a/src/platform/Tizen/ThreadStackManagerImpl.h +++ b/src/platform/Tizen/ThreadStackManagerImpl.h @@ -91,15 +91,11 @@ class ThreadStackManagerImpl : public ThreadStackManager bool _HaveMeshConnectivity(); CHIP_ERROR _GetAndLogThreadStatsCounters(); - CHIP_ERROR _GetAndLogThreadTopologyMinimal(); - CHIP_ERROR _GetAndLogThreadTopologyFull(); - CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf); - CHIP_ERROR _GetExternalIPv6Address(chip::Inet::IPAddress & addr); - + CHIP_ERROR _GetThreadVersion(uint16_t & version); CHIP_ERROR _GetPollPeriod(uint32_t & buf); void _ResetThreadNetworkDiagnosticsCounts(); diff --git a/src/platform/cc13xx_26xx/BLEManagerImpl.cpp b/src/platform/cc13xx_26xx/BLEManagerImpl.cpp index fc0a6af0beea94..f1d179c4b39310 100644 --- a/src/platform/cc13xx_26xx/BLEManagerImpl.cpp +++ b/src/platform/cc13xx_26xx/BLEManagerImpl.cpp @@ -521,7 +521,7 @@ void BLEManagerImpl::EventHandler_init(void) /* set the stacks in default states */ DMMPolicy_updateStackState(DMMPolicy_StackRole_BlePeripheral, DMMPOLICY_BLE_IDLE); - vTaskPrioritySet(xTaskGetCurrentTaskHandle(), 3); + vTaskPrioritySet(xTaskGetCurrentTaskHandle(), BLE_MANAGER_TASK_PRIORITY); // ****************************************************************** // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp @@ -634,7 +634,7 @@ CHIP_ERROR BLEManagerImpl::CreateEventHandler(void) "ble_hndlr", /* Text name for the task. */ BLEMANAGER_EVENT_HANDLER_STACK_SIZE, /* Stack size in words, not bytes. */ this, /* Parameter passed into the task. */ - ICALL_TASK_PRIORITIES, /* Keep priority the same as ICALL until init is complete */ + BLE_STACK_TASK_PRIORITY, /* Keep priority the same as ICALL until init is complete */ NULL); /* Used to pass out the created task's handle. */ if (xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) diff --git a/src/platform/cc13xx_26xx/icall_FreeRTOS.c b/src/platform/cc13xx_26xx/icall_FreeRTOS.c new file mode 100644 index 00000000000000..469ef9b3e0074c --- /dev/null +++ b/src/platform/cc13xx_26xx/icall_FreeRTOS.c @@ -0,0 +1,3926 @@ +/****************************************************************************** + @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-2024, 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 "bget.h" +#include +#include +#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 "icall.h" +#include "icall_platform.h" +#include "osal.h" +#include +#include + +#ifndef ICALL_FEATURE_SEPARATE_IMGINFO +#include +#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ + +#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 */ +#ifndef BLE_STACK_TASK_PRIORITY +static const int ICall_threadPriorities[] = { ICALL_TASK_PRIORITIES }; +#else +static const int ICall_threadPriorities[] = { BLE_STACK_TASK_PRIORITY }; +#endif + +/** @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_NO_RESOURCE; + +#ifdef FREERTOS + uint8_t statusQ; + if (HwiP_inISR()) + { + statusQ = xQueueSendFromISR(msgSyncHdl, (char *) &msg_ptr, NULL); + } + else + { + statusQ = xQueueSend(msgSyncHdl, (char *) &msg_ptr, 0); + } + + if (statusQ == pdTRUE) + { + status = ICALL_ERRNO_SUCCESS; + } +#endif + return (status); +} + +/** + * 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) + { + return status; + } +#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 + // 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) + { + return status; + } +#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) + { + return status; + } +#endif + return (ICALL_ERRNO_SUCCESS); +} +#endif /* ICALL_LITE*/ diff --git a/src/platform/telink/BUILD.gn b/src/platform/telink/BUILD.gn index 4857c048afc178..93f6aaef5ed94e 100644 --- a/src/platform/telink/BUILD.gn +++ b/src/platform/telink/BUILD.gn @@ -93,6 +93,7 @@ static_library("telink") { if (chip_enable_wifi) { sources += [ + "OTAImageProcessorImplWiFi.h", "wifi/ConnectivityManagerImplWiFi.cpp", "wifi/ConnectivityManagerImplWiFi.h", "wifi/TelinkWiFiDriver.cpp", diff --git a/src/platform/telink/OTAImageProcessorImplWiFi.h b/src/platform/telink/OTAImageProcessorImplWiFi.h new file mode 100644 index 00000000000000..29f1db87f67a54 --- /dev/null +++ b/src/platform/telink/OTAImageProcessorImplWiFi.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "OTAImageProcessorImpl.h" +#include "wifi/WiFiManager.h" + +namespace chip { + +namespace DeviceLayer { + +class OTAImageProcessorImplWiFi : public OTAImageProcessorImpl +{ +public: + explicit OTAImageProcessorImplWiFi(ExternalFlashManager * flashHandler = nullptr) : OTAImageProcessorImpl(flashHandler) {} + + CHIP_ERROR PrepareDownload() override + { + CHIP_ERROR err = WiFiManager::Instance().SetLowPowerMode(false); + if (err == CHIP_NO_ERROR) + { + return OTAImageProcessorImpl::PrepareDownload(); + } + return err; + }; + + CHIP_ERROR Abort() override + { + CHIP_ERROR err = OTAImageProcessorImpl::Abort(); + if (err == CHIP_NO_ERROR) + { + return WiFiManager::Instance().SetLowPowerMode(true); + } + return err; + }; + + CHIP_ERROR Apply() override + { + CHIP_ERROR err = OTAImageProcessorImpl::Apply(); + if (err == CHIP_NO_ERROR) + { + return WiFiManager::Instance().SetLowPowerMode(true); + } + return err; + }; +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/telink/tlsr9118bdk40d.overlay b/src/platform/telink/tlsr9118bdk40d.overlay index 6dddbe61c95a38..3c44668724d796 100644 --- a/src/platform/telink/tlsr9118bdk40d.overlay +++ b/src/platform/telink/tlsr9118bdk40d.overlay @@ -33,16 +33,7 @@ pwm_pool { compatible = "pwm-leds"; out { - pwms = <&pwm0 4 PWM_MSEC(1) PWM_POLARITY_NORMAL>, - <&pwm0 2 PWM_MSEC(1) PWM_POLARITY_NORMAL>, - <&pwm0 3 PWM_MSEC(1) PWM_POLARITY_NORMAL>; + pwms = <&pwm0 4 PWM_MSEC(1) PWM_POLARITY_NORMAL>; }; }; -}; - -&pwm0 { - /* On board RGB LEDs */ - pinctrl-ch4 = <&pwm_ch4_p20_default>; - pinctrl-ch2 = <&pwm_ch2_p17_default>; - pinctrl-ch3 = <&pwm_ch3_p18_default>; }; \ No newline at end of file diff --git a/src/platform/webos/NetworkCommissioningThreadDriver.cpp b/src/platform/webos/NetworkCommissioningThreadDriver.cpp index 557d3f6f7f7cf7..7a9f5873d57e9c 100644 --- a/src/platform/webos/NetworkCommissioningThreadDriver.cpp +++ b/src/platform/webos/NetworkCommissioningThreadDriver.cpp @@ -211,9 +211,9 @@ ThreadCapabilities LinuxThreadDriver::GetSupportedThreadFeatures() uint16_t LinuxThreadDriver::GetThreadVersion() { - // TODO https://github.com/project-chip/connectedhomeip/issues/30602 - // Needs to be implemented with DBUS io.openthread.BorderRouter Thread API - return 0; + uint16_t version = 0; + ThreadStackMgrImpl().GetThreadVersion(version); + return version; } #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD diff --git a/src/platform/webos/ThreadStackManagerImpl.cpp b/src/platform/webos/ThreadStackManagerImpl.cpp index cb538fa34ec618..cda82e673ac275 100644 --- a/src/platform/webos/ThreadStackManagerImpl.cpp +++ b/src/platform/webos/ThreadStackManagerImpl.cpp @@ -525,6 +525,13 @@ CHIP_ERROR ThreadStackManagerImpl::_GetExternalIPv6Address(chip::Inet::IPAddress return CHIP_ERROR_NOT_IMPLEMENTED; } +CHIP_ERROR ThreadStackManagerImpl::_GetThreadVersion(uint16_t & version) +{ + // TODO https://github.com/project-chip/connectedhomeip/issues/30602 + // Needs to be implemented with DBUS io.openthread.BorderRouter Thread API + return CHIP_ERROR_NOT_IMPLEMENTED; +} + CHIP_ERROR ThreadStackManagerImpl::_GetPollPeriod(uint32_t & buf) { // TODO: Remove Weave legacy APIs diff --git a/src/platform/webos/ThreadStackManagerImpl.h b/src/platform/webos/ThreadStackManagerImpl.h index b102e16ab568f7..64c3b8f6200bb8 100644 --- a/src/platform/webos/ThreadStackManagerImpl.h +++ b/src/platform/webos/ThreadStackManagerImpl.h @@ -101,7 +101,7 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf); CHIP_ERROR _GetExternalIPv6Address(chip::Inet::IPAddress & addr); - + CHIP_ERROR _GetThreadVersion(uint16_t & version); CHIP_ERROR _GetPollPeriod(uint32_t & buf); void _ResetThreadNetworkDiagnosticsCounts(); diff --git a/src/python_testing/TC_BRBINFO_4_1.py b/src/python_testing/TC_BRBINFO_4_1.py index 922a6cb555448c..8e920d8bc6013e 100644 --- a/src/python_testing/TC_BRBINFO_4_1.py +++ b/src/python_testing/TC_BRBINFO_4_1.py @@ -81,11 +81,12 @@ async def _send_keep_active_command(self, duration, endpoint_id) -> int: keep_active = await self.default_controller.SendCommand(nodeid=self.dut_node_id, endpoint=endpoint_id, payload=Clusters.Objects.BridgedDeviceBasicInformation.Commands.KeepActive(stayActiveDuration=duration)) return keep_active - async def _wait_for_active_changed_event(self, timeout) -> int: + async def _wait_for_active_changed_event(self, timeout_s) -> int: try: - promised_active_duration = self.q.get(block=True, timeout=timeout) - logging.info(f"PromisedActiveDuration: {promised_active_duration}") - return promised_active_duration + promised_active_duration_event = self.q.get(block=True, timeout=timeout_s) + logging.info(f"PromisedActiveDurationEvent: {promised_active_duration_event}") + promised_active_duration_ms = promised_active_duration_event.Data.promisedActiveDuration + return promised_active_duration_ms except queue.Empty: asserts.fail("Timeout on event ActiveChanged") @@ -192,21 +193,21 @@ async def test_TC_BRBINFO_4_1(self): self.step("1a") - idle_mode_duration = await self._read_attribute_expect_success( + idle_mode_duration_s = await self._read_attribute_expect_success( _ROOT_ENDPOINT_ID, icdm_cluster, icdm_attributes.IdleModeDuration, self.icd_nodeid ) - logging.info(f"IdleModeDuration: {idle_mode_duration}") + logging.info(f"IdleModeDurationS: {idle_mode_duration_s}") - active_mode_duration = await self._read_attribute_expect_success( + active_mode_duration_ms = await self._read_attribute_expect_success( _ROOT_ENDPOINT_ID, icdm_cluster, icdm_attributes.ActiveModeDuration, self.icd_nodeid ) - logging.info(f"ActiveModeDuration: {active_mode_duration}") + logging.info(f"ActiveModeDurationMs: {active_mode_duration_ms}") self.step("1b") @@ -218,49 +219,53 @@ async def test_TC_BRBINFO_4_1(self): subscription = await self.default_controller.ReadEvent(nodeid=self.dut_node_id, events=[(dynamic_endpoint_id, event, urgent)], reportInterval=[1, 3]) subscription.SetEventUpdateCallback(callback=cb) - stay_active_duration = 1000 - logging.info(f"Sending KeepActiveCommand({stay_active_duration}ms)") - self._send_keep_active_command(stay_active_duration, dynamic_endpoint_id) + stay_active_duration_ms = 1000 + logging.info(f"Sending KeepActiveCommand({stay_active_duration_ms}ms)") + await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) logging.info("Waiting for ActiveChanged from DUT...") - promised_active_duration = await self._wait_for_active_changed_event((idle_mode_duration + max(active_mode_duration, stay_active_duration))/1000) + timeout_s = idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms)/1000 + promised_active_duration_ms = await self._wait_for_active_changed_event(timeout_s) - asserts.assert_greater_equal(promised_active_duration, stay_active_duration, "PromisedActiveDuration < StayActiveDuration") + asserts.assert_greater_equal(promised_active_duration_ms, stay_active_duration_ms, + "PromisedActiveDuration < StayActiveDuration") self.step("2") - stay_active_duration = 1500 - logging.info(f"Sending KeepActiveCommand({stay_active_duration}ms)") - self._send_keep_active_command(stay_active_duration) + stay_active_duration_ms = 1500 + logging.info(f"Sending KeepActiveCommand({stay_active_duration_ms}ms)") + await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) logging.info("Waiting for ActiveChanged from DUT...") - promised_active_duration = await self._wait_for_active_changed_event((idle_mode_duration + max(active_mode_duration, stay_active_duration))/1000) + timeout_s = idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms)/1000 + promised_active_duration_ms = await self._wait_for_active_changed_event(timeout_s) # wait for active time duration - time.sleep(max(stay_active_duration/1000, promised_active_duration)) + sleep_time_s = max(stay_active_duration_ms, promised_active_duration_ms)/1000 + time.sleep(sleep_time_s) # ICD now should be in idle mode # sends 3x keep active commands - logging.info(f"Sending KeepActiveCommand({stay_active_duration})") - self._send_keep_active_command(stay_active_duration, dynamic_endpoint_id) - time.sleep(100) - logging.info(f"Sending KeepActiveCommand({stay_active_duration})") - self._send_keep_active_command(stay_active_duration, dynamic_endpoint_id) - time.sleep(100) - logging.info(f"Sending KeepActiveCommand({stay_active_duration})") - self._send_keep_active_command(stay_active_duration, dynamic_endpoint_id) - time.sleep(100) + logging.info(f"Step3 Sending first KeepActiveCommand({stay_active_duration_ms})") + await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) + time.sleep(0.1) + logging.info(f"Step3 Sending second KeepActiveCommand({stay_active_duration_ms})") + await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) + time.sleep(0.1) + logging.info(f"Step3 Sending third KeepActiveCommand({stay_active_duration_ms})") + await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) + time.sleep(0.1) logging.info("Waiting for ActiveChanged from DUT...") - promised_active_duration = await self._wait_for_active_changed_event((idle_mode_duration + max(active_mode_duration, stay_active_duration))/1000) + promised_active_duration_ms = await self._wait_for_active_changed_event((idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms))/1000) asserts.assert_equal(self.q.qSize(), 0, "More than one event received from DUT") self.step("3") - stay_active_duration = 10000 - logging.info(f"Sending KeepActiveCommand({stay_active_duration})") - self._send_keep_active_command(stay_active_duration, dynamic_endpoint_id) + stay_active_duration_ms = 10000 + logging.info(f"Sending KeepActiveCommand({stay_active_duration_ms})") + await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) # stops (halts) the ICD server process by sending a SIGTOP signal self.app_process.send_signal(signal.SIGSTOP.value) @@ -274,9 +279,9 @@ async def test_TC_BRBINFO_4_1(self): self.app_process.send_signal(signal.SIGCONT.value) # wait for active changed event, expect no event will be sent - event_timeout = (idle_mode_duration + max(active_mode_duration, stay_active_duration))/1000 + event_timeout = (idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms))/1000 try: - promised_active_duration = self.q.get(block=True, timeout=event_timeout) + promised_active_duration_ms = self.q.get(block=True, timeout=event_timeout) finally: asserts.assert_true(queue.Empty(), "ActiveChanged event received when not expected") diff --git a/src/python_testing/TC_CNET_1_4.py b/src/python_testing/TC_CNET_1_4.py index d7560c4fd03942..58f885c9d512aa 100644 --- a/src/python_testing/TC_CNET_1_4.py +++ b/src/python_testing/TC_CNET_1_4.py @@ -98,7 +98,8 @@ async def test_TC_CNET_1_4(self): self.step(6) concurrent_connection = await self.read_single_attribute_check_success(cluster=Clusters.GeneralCommissioning, - attribute=Clusters.GeneralCommissioning.Attributes.SupportsConcurrentConnection) + attribute=Clusters.GeneralCommissioning.Attributes.SupportsConcurrentConnection, + endpoint=kRootEndpointId) asserts.assert_true(concurrent_connection, "The device does not support concurrent connection commissioning") diff --git a/src/python_testing/TC_DeviceConformance.py b/src/python_testing/TC_DeviceConformance.py index 2a0fe309f20a4c..d847ef6aeb95ec 100644 --- a/src/python_testing/TC_DeviceConformance.py +++ b/src/python_testing/TC_DeviceConformance.py @@ -354,7 +354,8 @@ def test_TC_IDM_10_3(self): def test_TC_IDM_10_5(self): fail_on_extra_clusters = self.user_params.get("fail_on_extra_clusters", True) - success, problems = self.check_device_type(fail_on_extra_clusters) + allow_provisional = self.user_params.get("allow_provisional", False) + success, problems = self.check_device_type(fail_on_extra_clusters, allow_provisional) self.problems.extend(problems) if not success: self.fail_current_test("Problems with Device type conformance on one or more endpoints") diff --git a/src/python_testing/TC_SWTCH.py b/src/python_testing/TC_SWTCH.py index e2ef307973003b..d6c4694560b16d 100644 --- a/src/python_testing/TC_SWTCH.py +++ b/src/python_testing/TC_SWTCH.py @@ -114,7 +114,7 @@ def _ask_for_switch_position(self, endpoint_id: int, new_position: int): def _ask_for_multi_press_short_long(self, endpoint_id: int, pressed_position: int, feature_map: uint, multi_press_max: uint): if not self._use_button_simulator(): msg = f""" - Actuate the switch in the following sequence: + Actuate the switch in the following sequence (read full sequence first): 1. Operate switch (press briefly) associated with position {pressed_position} on the DUT then release switch from DUT 2. Operate switch (keep pressed for long time, e.g. 5 seconds) on the DUT immediately after the previous step 3. Release switch from the DUT @@ -128,7 +128,7 @@ def _ask_for_multi_press_short_long(self, endpoint_id: int, pressed_position: in def _ask_for_multi_press_long_short(self, endpoint_id, pressed_position, feature_map: int): if not self._use_button_simulator(): msg = f""" - Actuate the switch in the following sequence: + Actuate the switch in the following sequence (read full sequence first): 1. Operate switch (keep pressed for long time, e.g. 5 seconds) on the DUT 2. Releases switch from the DUT 3. Immediately after the previous step completes, operate switch (press briefly) associated with position {pressed_position} on the DUT then release switch from DUT @@ -142,7 +142,7 @@ def _ask_for_multi_press_long_short(self, endpoint_id, pressed_position, feature def _ask_for_multi_press(self, endpoint_id: int, number_of_presses: int, pressed_position: int, feature_map: uint, multi_press_max: uint): if not self._use_button_simulator(): self.wait_for_user_input( - f'Operate the switch (press briefly) associated with position {pressed_position} then release {number_of_presses} times') + f'Execute {number_of_presses} separate brief press/release cycles on position {pressed_position}.') else: self._send_multi_press_named_pipe_command(endpoint_id, number_of_presses, pressed_position, feature_map, multi_press_max) @@ -157,7 +157,7 @@ def _ask_for_long_press(self, endpoint_id: int, pressed_position: int, feature_m def _ask_for_keep_pressed(self, endpoint_id: int, pressed_position: int, feature_map: int): if not self._use_button_simulator(): self.wait_for_user_input( - prompt_msg=f"Press switch position {pressed_position} for a long time (around 5 seconds) on the DUT, then release it.") + prompt_msg=f"Press switch position {pressed_position} for a long time (around 5 seconds) on the DUT, keep it pressed, do NOT release it.") else: self._send_long_press_named_pipe_command(endpoint_id, pressed_position, feature_map) @@ -676,7 +676,7 @@ def test_multi_press_sequence(starting_step: str, count: int, short_long: bool = asserts.assert_equal(event.newPosition, pressed_position, "Unexpected NewPosition on LongPress") event = event_listener.wait_for_event_report(cluster.Events.LongRelease) asserts.assert_equal(event.previousPosition, pressed_position, "Unexpected PreviousPosition on LongRelease") - if self._use_button_simulator: + if self._use_button_simulator(): # simulator can't sequence so we need to help it along here self._send_multi_press_named_pipe_command(endpoint_id, number_of_presses=1, pressed_position=1, feature_map=feature_map, multi_press_max=multi_press_max) @@ -839,7 +839,7 @@ def test_multi_press_sequence(starting_step: str, count: int, short_long: bool = asserts.assert_equal(event.newPosition, pressed_position, "Unexpected NewPosition on LongPress") event = event_listener.wait_for_event_report(cluster.Events.LongRelease) asserts.assert_equal(event.previousPosition, pressed_position, "Unexpected PreviousPosition on LongRelease") - if self._use_button_simulator: + if self._use_button_simulator(): # simulator can't sequence so we need to help it along here self._send_multi_press_named_pipe_command(endpoint_id, number_of_presses=1, pressed_position=1, feature_map=feature_map, multi_press_max=multi_press_max) diff --git a/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni b/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni index b3aae392cfb39d..2bae18ab2a5db7 100644 --- a/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni +++ b/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni @@ -360,6 +360,8 @@ template("ti_simplelink_sdk") { libs = [] defines = [ + "BLE_MANAGER_TASK_PRIORITY=5", + "BLE_STACK_TASK_PRIORITY=6", "INCLUDE_BGET_STATS", "USE_DMM", "NVOCMP_FREERTOS_MUTEX=1", @@ -523,10 +525,10 @@ template("ti_simplelink_sdk") { sources = [ "${chip_root}/src/platform/cc13xx_26xx/TI_heap_wrapper.c", "${chip_root}/src/platform/cc13xx_26xx/chipOBleProfile.c", + "${chip_root}/src/platform/cc13xx_26xx/icall_FreeRTOS.c", "${ti_simplelink_sdk_root}/source/ti/ble5stack/common/cc26xx/freertos/bget.c", "${ti_simplelink_sdk_root}/source/ti/ble5stack/common/cc26xx/rcosc/rcosc_calibration.c", "${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c", - "${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c", "${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/freertos/util.c", "${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/thread/source/activity/dmm_thread_activity.c", "${ti_simplelink_sdk_root}/source/ti/dmm/dmm_priority_ble_thread.c",