diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index d9df0bca21637f..b0b4fef50e15df 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -41,7 +41,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-efr32:84 + image: ghcr.io/project-chip/chip-build-efr32:85 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml index af90dc316d0f4a..54997b6efa9b39 100644 --- a/.github/workflows/release_artifacts.yaml +++ b/.github/workflows/release_artifacts.yaml @@ -64,7 +64,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/project-chip/chip-build-efr32:84 + image: ghcr.io/project-chip/chip-build-efr32:85 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.gitmodules b/.gitmodules index 3f50d3079d4e03..c2b9a95a5e0345 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,7 +213,7 @@ [submodule "third_party/silabs/simplicity_sdk"] path = third_party/silabs/simplicity_sdk url = https://github.com/SiliconLabs/simplicity_sdk.git - branch = v2024.6.1-0 + branch = v2024.6.2 platforms = silabs [submodule "third_party/silabs/wiseconnect-wifi-bt-sdk"] path = third_party/silabs/wiseconnect-wifi-bt-sdk diff --git a/docs/development_controllers/chip-tool/chip_tool_guide.md b/docs/development_controllers/chip-tool/chip_tool_guide.md index 8aac8daa121812..81000368a47f0c 100644 --- a/docs/development_controllers/chip-tool/chip_tool_guide.md +++ b/docs/development_controllers/chip-tool/chip_tool_guide.md @@ -9,33 +9,29 @@ the setup payload or performing discovery actions.
-## Source files +## Installation -You can find source files of the CHIP Tool in the `examples/chip-tool` -directory. - -> **Note:** The CHIP Tool caches the configuration state in the -> `/tmp/chip_tool_config.ini` file. Deleting this and other `.ini` files in the -> `/tmp` directory can sometimes resolve issues related to stale configuration. +On Linux distributions +[running snapd](https://snapcraft.io/docs/installing-snapd), such as Ubuntu, the +CHIP Tool can be installed using the +[chip-tool snap](https://snapcraft.io/chip-tool). To do this, run: -> **Note:** To make the configuration persistent (since `/tmp` directory might -> be flushed at each reboot) you can change the directory where CHIP Tool caches -> its configuration by using the option `--storage-directory` +``` +sudo snap install chip-tool +``` -
+## Building from source -## Building and running the CHIP Tool +The source files of the CHIP Tool are available in the `examples/chip-tool` +directory. -Before you can use the CHIP Tool, you must compile it from source on Linux -(amd64/aarch64) or macOS. If you want to run it on Raspberry Pi, it must use a -64-bit OS. +The source can be compiled on Linux (amd64/aarch64) or macOS. If you want to run +it on Raspberry Pi, you must use a 64-bit OS. > **Note:** To ensure compatibility, always build the CHIP Tool and the Matter > device from the same revision of the `connectedhomeip` repository. -### Building the CHIP Tool - -To build and run the CHIP Tool: +To build the CHIP Tool: 1. Install all required packages for Matter and prepare the source code and the build system. Read the [Building Matter](../../guides/BUILDING.md) guide for @@ -50,10 +46,16 @@ To build and run the CHIP Tool: In this command, `BUILD_PATH` specifies where the target binaries are to be placed. -### Running the CHIP Tool +## Running the CHIP Tool + +If you installed the CHIP Tool as a snap, the command to run it would be: + +``` +$ chip-tool +``` -To check if the CHIP Tool runs correctly, execute the following command from the -`BUILD_PATH` directory: +If you compiled the CHIP Tool from source, it can be executed with the following +command from the `BUILD_PATH` directory: ``` $ ./chip-tool @@ -68,6 +70,13 @@ more complex command by appending it with sub-commands. Examples of specific commands and their use cases are described in the [Supported commands and options](#supported-commands-and-options) section. +> **Note:** The CHIP Tool caches the configuration state in the +> `/tmp/chip_tool_config.ini` file. Deleting this and other `.ini` files in the +> `/tmp` directory can sometimes resolve issues related to stale configuration. +> To make the configuration persistent you can change the directory where CHIP +> Tool caches its configuration by using the command line option +> `--storage-directory` +
## CHIP Tool modes diff --git a/examples/light-switch-app/nrfconnect/README.md b/examples/light-switch-app/nrfconnect/README.md index 11e53793463570..02f7b500aa6270 100644 --- a/examples/light-switch-app/nrfconnect/README.md +++ b/examples/light-switch-app/nrfconnect/README.md @@ -638,7 +638,7 @@ same Matter network. To perform the unicast binding process, complete the following steps: 1. Build the CHIP Tool according to the steps from the - [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-and-running-the-chip-tool). + [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-from-source). 2. Go to the CHIP Tool build directory. 3. Add an ACL to the development kit that is programmed with the [Lighting Application Example](../../lighting-app/nrfconnect/README.md) by @@ -690,7 +690,7 @@ same Matter network. To perform the unicast binding process, complete the following steps: 1. Build the CHIP Tool according to the steps from the - [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-and-running-the-chip-tool). + [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-from-source). 2. Go to the CHIP Tool build directory. 3. Add the light switch device to the multicast group by running the following diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml index 24a3029d2fe2f8..824b79d6ce1a22 100644 --- a/integrations/cloudbuild/smoke-test.yaml +++ b/integrations/cloudbuild/smoke-test.yaml @@ -1,5 +1,5 @@ steps: - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" entrypoint: "bash" args: - "-c" @@ -7,7 +7,7 @@ steps: git config --global --add safe.directory "*" python scripts/checkout_submodules.py --shallow --recursive --platform esp32 nrfconnect silabs linux android id: Submodules - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" # NOTE: silabs boostrap is NOT done with the rest as it requests a conflicting # jinja2 version (asks for 3.1.3 when constraints.txt asks for 3.0.3) env: @@ -24,7 +24,7 @@ steps: path: /pwenv timeout: 900s - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: ESP32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -45,7 +45,7 @@ steps: volumes: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: NRFConnect env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -66,7 +66,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: EFR32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -88,7 +88,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: Linux env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -141,7 +141,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: Android env: - PW_ENVIRONMENT_ROOT=/pwenv diff --git a/src/app/clusters/thermostat-server/thermostat-server-presets.cpp b/src/app/clusters/thermostat-server/thermostat-server-presets.cpp index 9413513fd0cedd..1dede071619962 100644 --- a/src/app/clusters/thermostat-server/thermostat-server-presets.cpp +++ b/src/app/clusters/thermostat-server/thermostat-server-presets.cpp @@ -152,69 +152,36 @@ bool GetMatchingPresetInPresets(Delegate * delegate, const DataModel::NullableGetPendingPresetAtIndex(i, pendingPreset); - + PresetTypeStruct::Type presetType; + auto err = delegate->GetPresetTypeAtIndex(i, presetType); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) { - break; + // We exhausted the list trying to find the preset scenario + return CHIP_NO_ERROR; } if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "CountNumberOfPendingPresets: GetPendingPresetAtIndex failed with error %" CHIP_ERROR_FORMAT, - err.Format()); - return 0; + return err; } - numberOfPendingPresets++; - } - - return numberOfPendingPresets; -} - -/** - * @brief Checks if the presetScenario is present in the PresetTypes attribute. - * - * @param[in] delegate The delegate to use. - * @param[in] presetScenario The presetScenario to match with. - * - * @return true if the presetScenario is found, false otherwise. - */ -bool PresetScenarioExistsInPresetTypes(Delegate * delegate, PresetScenarioEnum presetScenario) -{ - VerifyOrReturnValue(delegate != nullptr, false); - - for (uint8_t i = 0; true; i++) - { - PresetTypeStruct::Type presetType; - auto err = delegate->GetPresetTypeAtIndex(i, presetType); - if (err != CHIP_NO_ERROR) - { - return false; - } - if (presetType.presetScenario == presetScenario) { - return true; + count = presetType.numberOfPresets; + return CHIP_NO_ERROR; } } - return false; + return CHIP_NO_ERROR; } /** @@ -410,8 +377,16 @@ CHIP_ERROR ThermostatAttrAccess::AppendPendingPreset(Thermostat::Delegate * dele } } - if (!PresetScenarioExistsInPresetTypes(delegate, preset.GetPresetScenario())) + size_t maximumPresetCount = delegate->GetNumberOfPresets(); + size_t maximumPresetScenarioCount = 0; + if (MaximumPresetScenarioCount(delegate, preset.GetPresetScenario(), maximumPresetScenarioCount) != CHIP_NO_ERROR) { + return CHIP_IM_GLOBAL_STATUS(InvalidInState); + } + + if (maximumPresetScenarioCount == 0) + { + // This is not a supported preset scenario return CHIP_IM_GLOBAL_STATUS(ConstraintError); } @@ -423,16 +398,42 @@ CHIP_ERROR ThermostatAttrAccess::AppendPendingPreset(Thermostat::Delegate * dele // Before adding this preset to the pending presets, if the expected length of the pending presets' list // exceeds the total number of presets supported, return RESOURCE_EXHAUSTED. Note that the preset has not been appended yet. - uint8_t numberOfPendingPresets = CountNumberOfPendingPresets(delegate); + // We're going to append this preset, so let's assume a count as though it had already been inserted + size_t presetCount = 1; + size_t presetScenarioCount = 1; + for (uint8_t i = 0; true; i++) + { + PresetStructWithOwnedMembers otherPreset; + CHIP_ERROR err = delegate->GetPendingPresetAtIndex(i, otherPreset); + + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + break; + } + if (err != CHIP_NO_ERROR) + { + return CHIP_IM_GLOBAL_STATUS(InvalidInState); + } + presetCount++; + if (preset.GetPresetScenario() == otherPreset.GetPresetScenario()) + { + presetScenarioCount++; + } + } - // We will be adding one more preset, so reject if the length is already at max. - if (numberOfPendingPresets >= delegate->GetNumberOfPresets()) + if (presetCount > maximumPresetCount) { + ChipLogError(Zcl, "Preset count exceeded %u: %u ", static_cast(maximumPresetCount), + static_cast(presetCount)); return CHIP_IM_GLOBAL_STATUS(ResourceExhausted); } - // TODO #34556 : Check if the number of presets for each presetScenario exceeds the max number of presets supported for that - // scenario. We plan to support only one preset for each presetScenario for our use cases so defer this for re-evaluation. + if (presetScenarioCount > maximumPresetScenarioCount) + { + ChipLogError(Zcl, "Preset scenario count exceeded %u: %u ", static_cast(maximumPresetScenarioCount), + static_cast(presetScenarioCount)); + return CHIP_IM_GLOBAL_STATUS(ResourceExhausted); + } return delegate->AppendToPendingPresetList(preset); } diff --git a/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml b/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml index 8e9ee05b33e9ff..aa0fbcfddc83bf 100644 --- a/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml @@ -188,6 +188,16 @@ tests: minValue: MinLevelFeatureMapNotSupportedValue maxValue: MaxLevelFeatureMapNotSupportedValue + - label: "Step 9c: TH reads the OnLevel attribute from the DUT" + PICS: LVL.S.A0011 && !LVL.S.F01 && !LVL.S.A0002 && !LVL.S.A0003 + command: "readAttribute" + attribute: "OnLevel" + response: + constraints: + type: int8u + minValue: 0 + maxValue: 254 + - label: "Step 10: TH reads the OnTransitionTime attribute from the DUT" PICS: LVL.S.A0012 command: "readAttribute" diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index f7f5699ef8fccf..ff485bbf6bba81 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -2698,4 +2698,47 @@ limitations under the License. + + MA-waterheater + CHIP + Water Heater + 0x0103 + 0x050F + Simple + Endpoint + + + CLIENT_LIST + DEVICE_TYPE_LIST + PARTS_LIST + SERVER_LIST + + + IDENTIFY_TIME + IDENTIFY_TYPE + Identify + + + CONTROL_SEQUENCE_OF_OPERATION + LOCAL_TEMPERATURE + SYSTEM_MODE + SetpointRaiseLower + + + BOOST_STATE + HEATER_TYPES + HEAT_DEMAND + BoostEnded + BoostStarted + Boost + CancelBoost + + + CURRENT_MODE + SUPPORTED_MODES + ChangeToMode + ChangeToModeResponse + + + diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index b1d26e9ce0fb12..da2ce72f59373d 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -7625,6 +7625,7 @@ typedef NS_ENUM(uint32_t, MTRDeviceTypeIDType) { MTRDeviceTypeIDTypeHumiditySensorID MTR_NEWLY_AVAILABLE = 0x00000307, MTRDeviceTypeIDTypeEVSEID MTR_NEWLY_AVAILABLE = 0x0000050C, MTRDeviceTypeIDTypeDeviceEnergyManagementID MTR_NEWLY_AVAILABLE = 0x0000050D, + MTRDeviceTypeIDTypeWaterHeaterID MTR_PROVISIONALLY_AVAILABLE = 0x0000050F, MTRDeviceTypeIDTypeElectricalSensorID MTR_NEWLY_AVAILABLE = 0x00000510, MTRDeviceTypeIDTypeControlBridgeID MTR_NEWLY_AVAILABLE = 0x00000840, MTRDeviceTypeIDTypeOnOffSensorID MTR_NEWLY_AVAILABLE = 0x00000850, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm index f0530c41a54f00..b4ea67c2ed66fe 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm @@ -85,6 +85,7 @@ { 0x00000307, MTRDeviceTypeClass::Simple, "Humidity Sensor" }, { 0x0000050C, MTRDeviceTypeClass::Simple, "EVSE" }, { 0x0000050D, MTRDeviceTypeClass::Simple, "Device Energy Management" }, + { 0x0000050F, MTRDeviceTypeClass::Simple, "Water Heater" }, { 0x00000510, MTRDeviceTypeClass::Utility, "Electrical Sensor" }, { 0x00000840, MTRDeviceTypeClass::Simple, "Control Bridge" }, { 0x00000850, MTRDeviceTypeClass::Simple, "On/Off Sensor" }, diff --git a/src/lib/support/BufferReader.cpp b/src/lib/support/BufferReader.cpp index 02bce8f3fe0615..cbd13f1ed172dc 100644 --- a/src/lib/support/BufferReader.cpp +++ b/src/lib/support/BufferReader.cpp @@ -18,12 +18,29 @@ #include "BufferReader.h" #include +#include +#include #include #include namespace chip { namespace Encoding { + +BufferReader & BufferReader::ReadBytes(uint8_t * dest, size_t size) +{ + static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing"); + + if (EnsureAvailable(size)) + { + memcpy(dest, mReadPtr, size); + mReadPtr += size; + mAvailable -= size; + } + + return *this; +} + namespace LittleEndian { namespace { @@ -58,37 +75,12 @@ void Reader::RawReadLowLevelBeCareful(T * retval) constexpr size_t data_size = sizeof(T); - if (mAvailable < data_size) - { - mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; - // Ensure that future reads all fail. - mAvailable = 0; - return; - } - - ReadHelper(mReadPtr, retval); - mReadPtr += data_size; - - mAvailable = static_cast(mAvailable - data_size); -} - -Reader & Reader::ReadBytes(uint8_t * dest, size_t size) -{ - static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing"); - - if ((size > UINT16_MAX) || (mAvailable < size)) + if (EnsureAvailable(data_size)) { - mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; - // Ensure that future reads all fail. - mAvailable = 0; - return *this; + ReadHelper(mReadPtr, retval); + mReadPtr += data_size; + mAvailable -= data_size; } - - memcpy(dest, mReadPtr, size); - - mReadPtr += size; - mAvailable = static_cast(mAvailable - size); - return *this; } // Explicit Read instantiations for the data types we want to support. @@ -104,5 +96,46 @@ template void Reader::RawReadLowLevelBeCareful(uint32_t *); template void Reader::RawReadLowLevelBeCareful(uint64_t *); } // namespace LittleEndian + +namespace BigEndian { + +Reader & Reader::Read16(uint16_t * dest) +{ + if (!EnsureAvailable(sizeof(uint16_t))) + { + return *this; + } + + static_assert(sizeof(*dest) == 2); + + *dest = static_cast((mReadPtr[0] << 8) + mReadPtr[1]); + mReadPtr += 2; + mAvailable -= 2; + return *this; +} + +Reader & Reader::Read32(uint32_t * dest) +{ + if (!EnsureAvailable(sizeof(uint32_t))) + { + return *this; + } + + static_assert(sizeof(*dest) == 4); + + *dest = 0; + for (unsigned i = 0; i < sizeof(uint32_t); i++) + { + *dest <<= 8; + *dest += mReadPtr[i]; + } + + mReadPtr += sizeof(uint32_t); + mAvailable -= sizeof(uint32_t); + return *this; +} + +} // namespace BigEndian + } // namespace Encoding } // namespace chip diff --git a/src/lib/support/BufferReader.h b/src/lib/support/BufferReader.h index ac9c7145359335..725ca8e23ea915 100644 --- a/src/lib/support/BufferReader.h +++ b/src/lib/support/BufferReader.h @@ -31,26 +31,11 @@ namespace chip { namespace Encoding { -namespace LittleEndian { -/** - * @class Reader - * - * Simple reader for reading little-endian things out of buffers. - */ -class Reader +class BufferReader { public: - /** - * Create a buffer reader from a given buffer and length. - * - * @param buffer The octet buffer from which to read. The caller must ensure - * (most simply by allocating the reader on the stack) that - * the buffer outlives the reader. If `buffer` is nullptr, - * length is automatically overridden to zero, to avoid accesses. - * @param buf_len The number of octets in the buffer. - */ - Reader(const uint8_t * buffer, size_t buf_len) : mBufStart(buffer), mReadPtr(buffer), mAvailable(buf_len) + BufferReader(const uint8_t * buffer, size_t buf_len) : mBufStart(buffer), mReadPtr(buffer), mAvailable(buf_len) { if (mBufStart == nullptr) { @@ -58,15 +43,6 @@ class Reader } } - /** - * Create a buffer reader from a given byte span. - * - * @param buffer The octet buffer byte span from which to read. The caller must ensure - * that the buffer outlives the reader. The buffer's ByteSpan .data() pointer - * is is nullptr, length is automatically overridden to zero, to avoid accesses. - */ - Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} - /** * Number of octets we have read so far. */ @@ -95,6 +71,121 @@ class Reader */ bool IsSuccess() const { return StatusCode() == CHIP_NO_ERROR; } + /** + * Read a byte string from the BufferReader + * + * @param [out] dest Where the bytes read + * @param [in] size How many bytes to read + * + * @note The read can put the reader in a failed-status state if there are + * not enough octets available. Callers must either continue to do + * more reads on the return value or check its status to see whether + * the sequence of reads that has been performed succeeded. + */ + CHECK_RETURN_VALUE + BufferReader & ReadBytes(uint8_t * dest, size_t size); + + /** + * Access bytes of size length, useful for in-place processing of strings + * + * data_ptr MUST NOT be null and will contain the data pointer with `len` bytes available + * if this call is successful + * + * If len is greater than the number of available bytes, the object enters in a failed status. + */ + CHECK_RETURN_VALUE + BufferReader & ZeroCopyProcessBytes(size_t len, const uint8_t ** data_ptr) + { + if (len > mAvailable) + { + *data_ptr = nullptr; + mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; + // Ensure that future reads all fail. + mAvailable = 0; + } + else + { + *data_ptr = mReadPtr; + mReadPtr += len; + mAvailable -= len; + } + return *this; + } + + /** + * Advance the Reader forward by the specified number of octets. + * + * @param len The number of octets to skip. + * + * @note If the len argument is greater than the number of available octets + * remaining, the Reader will advance to the end of the buffer + * without entering a failed-status state. + */ + BufferReader & Skip(size_t len) + { + len = std::min(len, mAvailable); + mReadPtr += len; + mAvailable = static_cast(mAvailable - len); + return *this; + } + +protected: + /// Our buffer start. + const uint8_t * const mBufStart; + + /// Our current read point. + const uint8_t * mReadPtr; + + /// The number of octets we can still read starting at mReadPtr. + size_t mAvailable; + + /// Our current status. + CHIP_ERROR mStatus = CHIP_NO_ERROR; + + /// Make sure we have at least the given number of bytes available (does not consume them) + bool EnsureAvailable(size_t size) + { + if (mAvailable < size) + { + mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; + // Ensure that future reads all fail. + mAvailable = 0; + return false; + } + return true; + } +}; + +namespace LittleEndian { + +/** + * @class Reader + * + * Simple reader for reading little-endian things out of buffers. + */ +class Reader : public BufferReader +{ +public: + /** + * Create a buffer reader from a given buffer and length. + * + * @param buffer The octet buffer from which to read. The caller must ensure + * (most simply by allocating the reader on the stack) that + * the buffer outlives the reader. If `buffer` is nullptr, + * length is automatically overridden to zero, to avoid accesses. + * @param buf_len The number of octets in the buffer. + */ + Reader(const uint8_t * buffer, size_t buf_len) : BufferReader(buffer, buf_len) {} + + /** + * Create a buffer reader from a given byte span. + * + * @param buffer The octet buffer byte span from which to read. The caller must ensure + * that the buffer outlives the reader. The buffer's ByteSpan .data() pointer + * is is nullptr, length is automatically overridden to zero, to avoid accesses. + */ + Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} + /** * Read a bool, assuming single byte storage. * @@ -267,20 +358,6 @@ class Reader return *this; } - /** - * Read a byte string from the BufferReader - * - * @param [out] dest Where the bytes read - * @param [in] size How many bytes to read - * - * @note The read can put the reader in a failed-status state if there are - * not enough octets available. Callers must either continue to do - * more reads on the return value or check its status to see whether - * the sequence of reads that has been performed succeeded. - */ - CHECK_RETURN_VALUE - Reader & ReadBytes(uint8_t * dest, size_t size); - /** * Helper for our various APIs so we don't have to write out various logic * multiple times. This is public so that consumers that want to read into @@ -290,46 +367,80 @@ class Reader */ template void RawReadLowLevelBeCareful(T * retval); +}; + +} // namespace LittleEndian +namespace BigEndian { + +/** + * @class Reader + * + * Simple reader for reading big-endian things out of buffers. + */ +class Reader : public BufferReader +{ +public: /** - * Advance the Reader forward by the specified number of octets. - * - * @param len The number of octets to skip. + * Create a buffer reader from a given buffer and length. * - * @note If the len argument is greater than the number of available octets - * remaining, the Reader will advance to the end of the buffer - * without entering a failed-status state. + * @param buffer The octet buffer from which to read. The caller must ensure + * (most simply by allocating the reader on the stack) that + * the buffer outlives the reader. If `buffer` is nullptr, + * length is automatically overridden to zero, to avoid accesses. + * @param buf_len The number of octets in the buffer. */ - Reader & Skip(size_t len) - { - len = std::min(len, mAvailable); - mReadPtr += len; - mAvailable = static_cast(mAvailable - len); - return *this; - } + Reader(const uint8_t * buffer, size_t buf_len) : BufferReader(buffer, buf_len) {} -private: /** - * Our buffer start. + * Create a buffer reader from a given byte span. + * + * @param buffer The octet buffer byte span from which to read. The caller must ensure + * that the buffer outlives the reader. If the buffer's ByteSpan .data() pointer + * is nullptr, length is automatically overridden to zero, to avoid accesses. */ - const uint8_t * const mBufStart; + Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} /** - * Our current read point. + * Read a single 8-bit unsigned integer. + * + * @param [out] dest Where the 8-bit integer goes. + * + * @note The read can put the reader in a failed-status state if there are + * not enough octets available. Callers must either continue to do + * more reads on the return value or check its status to see whether + * the sequence of reads that has been performed succeeded. */ - const uint8_t * mReadPtr; + CHECK_RETURN_VALUE + Reader & Read8(uint8_t * dest) + { + (void) ReadBytes(dest, 1); + return *this; + } - /** - * The number of octets we can still read starting at mReadPtr. - */ - size_t mAvailable; + CHECK_RETURN_VALUE + Reader & ReadChar(char * dest) + { + (void) ReadBytes(reinterpret_cast(dest), 1); + return *this; + } - /** - * Our current status. - */ - CHIP_ERROR mStatus = CHIP_NO_ERROR; + CHECK_RETURN_VALUE + Reader & ReadBool(char * dest) + { + (void) ReadBytes(reinterpret_cast(dest), 1); + return *this; + } + + /// NOTE: only a subset of reads are supported here, more can be added if used/needed + CHECK_RETURN_VALUE + Reader & Read16(uint16_t * dest); + + CHECK_RETURN_VALUE + Reader & Read32(uint32_t * dest); }; -} // namespace LittleEndian +} // namespace BigEndian + } // namespace Encoding } // namespace chip diff --git a/src/lib/support/tests/TestBufferReader.cpp b/src/lib/support/tests/TestBufferReader.cpp index 97db9cf09737b9..ee100e1506bada 100644 --- a/src/lib/support/tests/TestBufferReader.cpp +++ b/src/lib/support/tests/TestBufferReader.cpp @@ -30,21 +30,21 @@ #include using namespace chip; -using namespace chip::Encoding::LittleEndian; +using namespace chip::Encoding; static const uint8_t test_buffer[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; -struct TestReader : public Reader +struct LittleEndianTestReader : public LittleEndian::Reader { - TestReader() : Reader(test_buffer, std::extent::value) {} + LittleEndianTestReader() : LittleEndian::Reader(test_buffer, std::extent::value) {} }; -struct TestSpanReader : public Reader +struct LittleEndianTestSpanReader : public LittleEndian::Reader { - TestSpanReader() : Reader(ByteSpan{ test_buffer, std::extent::value }) {} + LittleEndianTestSpanReader() : LittleEndian::Reader(ByteSpan{ test_buffer, std::extent::value }) {} }; -static void TestBufferReader_BasicImpl(Reader & reader) +static void TestBufferReader_BasicImpl(LittleEndian::Reader & reader) { uint8_t first; uint16_t second; @@ -75,21 +75,21 @@ static void TestBufferReader_BasicImpl(Reader & reader) TEST(TestBufferReader, TestBufferReader_Basic) { - TestReader reader; + LittleEndianTestReader reader; TestBufferReader_BasicImpl(reader); } TEST(TestBufferReader, TestBufferReader_BasicSpan) { - TestSpanReader reader; + LittleEndianTestSpanReader reader; TestBufferReader_BasicImpl(reader); } TEST(TestBufferReader, TestBufferReader_Saturation) { - TestReader reader; + LittleEndianTestReader reader; uint64_t temp; // Read some bytes out so we can get to the end of the buffer. CHIP_ERROR err = reader.Read64(&temp).StatusCode(); @@ -113,12 +113,13 @@ TEST(TestBufferReader, TestBufferReader_Saturation) TEST(TestBufferReader, TestBufferReader_Skip) { - TestReader reader; + LittleEndianTestReader reader; uint8_t temp = 0; uint16_t firstSkipLen = 2; // Verify Skip() advances the start pointer the correct amount. - CHIP_ERROR err = reader.Skip(firstSkipLen).Read8(&temp).StatusCode(); + reader.Skip(firstSkipLen); + CHIP_ERROR err = reader.Read8(&temp).StatusCode(); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(temp, test_buffer[firstSkipLen]); EXPECT_EQ(reader.OctetsRead(), (firstSkipLen + 1u)); @@ -175,7 +176,8 @@ TEST(TestBufferReader, TestBufferReader_LittleEndianScalars) uint32_t val1 = 0; uint32_t val2 = 0; - EXPECT_TRUE(reader.Skip(1).Read32(&val1).Read32(&val2).IsSuccess()); + reader.Skip(1); + EXPECT_TRUE(reader.Read32(&val1).Read32(&val2).IsSuccess()); EXPECT_EQ(reader.Remaining(), 1u); EXPECT_EQ(val1, static_cast(0xfffffffeUL)); EXPECT_EQ(val2, static_cast(0xffffffffUL)); @@ -227,7 +229,8 @@ TEST(TestBufferReader, TestBufferReader_LittleEndianScalars) int32_t val1 = 0; int32_t val2 = 0; - EXPECT_TRUE(reader.Skip(1).ReadSigned32(&val1).ReadSigned32(&val2).IsSuccess()); + reader.Skip(1); + EXPECT_TRUE(reader.ReadSigned32(&val1).ReadSigned32(&val2).IsSuccess()); EXPECT_EQ(reader.Remaining(), 1u); EXPECT_EQ(val1, static_cast(-2L)); EXPECT_EQ(val2, static_cast(-1L)); @@ -272,3 +275,23 @@ TEST(TestBufferReader, TestBufferReader_LittleEndianScalars) EXPECT_EQ(val3, '\xff'); } } + +TEST(TestBigEndianBufferReader, GenericTests) +{ + uint8_t test_buf[] = { 0x12, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xBC, 1, 2, 3 }; + + chip::Encoding::BigEndian::Reader reader{ ByteSpan{ test_buf } }; + + uint16_t v1; + uint32_t v2; + uint8_t v3; + + EXPECT_TRUE(reader.Read16(&v1).Read32(&v2).Read8(&v3).IsSuccess()); + EXPECT_EQ(reader.Remaining(), 3u); + EXPECT_EQ(v1, 0x1223u); + EXPECT_EQ(v2, 0x456789ABu); + EXPECT_EQ(v3, 0xBCu); + + // Insufficient buffer after that + EXPECT_FALSE(reader.Read32(&v2).IsSuccess()); +} diff --git a/src/platform/silabs/BLEManagerImpl.h b/src/platform/silabs/BLEManagerImpl.h index 6d901db16e95db..9380accce38e55 100644 --- a/src/platform/silabs/BLEManagerImpl.h +++ b/src/platform/silabs/BLEManagerImpl.h @@ -58,12 +58,12 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #if (SLI_SI91X_ENABLE_BLE || RSI_BLE_ENABLE) // Used for posting the event in the BLE queue void BlePostEvent(SilabsBleWrapper::BleEvent_t * event); - void HandleConnectEvent(SilabsBleWrapper::sl_wfx_msg_t * evt); - void HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * evt); - void HandleWriteEvent(SilabsBleWrapper::sl_wfx_msg_t * evt); - void UpdateMtu(SilabsBleWrapper::sl_wfx_msg_t * evt); + void HandleConnectEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt); + void HandleConnectionCloseEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt); + void HandleWriteEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt); + void UpdateMtu(const SilabsBleWrapper::sl_wfx_msg_t & evt); void HandleTxConfirmationEvent(BLE_CONNECTION_OBJECT conId); - void HandleTXCharCCCDWrite(SilabsBleWrapper::sl_wfx_msg_t * evt); + void HandleTXCharCCCDWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt); void HandleSoftTimerEvent(void); int32_t SendBLEAdvertisementCommand(void); #else @@ -194,7 +194,7 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #endif #if (SLI_SI91X_ENABLE_BLE || RSI_BLE_ENABLE) - void HandleRXCharWrite(SilabsBleWrapper::sl_wfx_msg_t * evt); + void HandleRXCharWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt); #else void HandleRXCharWrite(volatile sl_bt_msg_t * evt); #endif diff --git a/src/platform/silabs/rs911x/BLEManagerImpl.cpp b/src/platform/silabs/rs911x/BLEManagerImpl.cpp index 44b2a17199b330..176f396f44cd1f 100644 --- a/src/platform/silabs/rs911x/BLEManagerImpl.cpp +++ b/src/platform/silabs/rs911x/BLEManagerImpl.cpp @@ -57,24 +57,7 @@ extern "C" { #define BLE_TIMEOUT_MS 400 #define BLE_SEND_INDICATION_TIMER_PERIOD_MS (5000) -// Used to send the Indication Confirmation -uint8_t dev_address[RSI_DEV_ADDR_LEN]; -uint16_t ble_measurement_hndl; - osSemaphoreId_t sl_rs_ble_init_sem; -osTimerId_t sbleAdvTimeoutTimer; - -static osThreadId_t sBleThread; -constexpr uint32_t kBleTaskSize = 2048; -static uint8_t bleStack[kBleTaskSize]; -static osThread_t sBleTaskControlBlock; -constexpr osThreadAttr_t kBleTaskAttr = { .name = "rsi_ble", - .attr_bits = osThreadDetached, - .cb_mem = &sBleTaskControlBlock, - .cb_size = osThreadCbSize, - .stack_mem = bleStack, - .stack_size = kBleTaskSize, - .priority = osPriorityHigh }; using namespace ::chip; using namespace ::chip::Ble; @@ -111,6 +94,84 @@ const uint8_t UUID_CHIPoBLEService[] = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00 0x00, 0x10, 0x00, 0x00, 0xF6, 0xFF, 0x00, 0x00 }; const uint8_t ShortUUID_CHIPoBLEService[] = { 0xF6, 0xFF }; +// Used to send the Indication Confirmation +uint8_t dev_address[RSI_DEV_ADDR_LEN]; +uint16_t rsi_ble_measurement_hndl; +uint16_t rsi_ble_gatt_server_client_config_hndl; + +osTimerId_t sbleAdvTimeoutTimer; + +osThreadId_t sBleThread; +constexpr uint32_t kBleTaskSize = 2560; +uint8_t bleStack[kBleTaskSize]; +osThread_t sBleTaskControlBlock; +constexpr osThreadAttr_t kBleTaskAttr = { .name = "rsi_ble", + .attr_bits = osThreadDetached, + .cb_mem = &sBleTaskControlBlock, + .cb_size = osThreadCbSize, + .stack_mem = bleStack, + .stack_size = kBleTaskSize, + .priority = osPriorityHigh }; + +void rsi_ble_add_matter_service(void) +{ + constexpr uuid_t custom_service = { .size = RSI_BLE_MATTER_CUSTOM_SERVICE_SIZE, + .val = { .val16 = RSI_BLE_MATTER_CUSTOM_SERVICE_VALUE_16 } }; + uint8_t data[RSI_BLE_MATTER_CUSTOM_SERVICE_DATA_LENGTH] = { RSI_BLE_MATTER_CUSTOM_SERVICE_DATA }; + + constexpr uuid_t custom_characteristic_RX = { .size = RSI_BLE_CUSTOM_CHARACTERISTIC_RX_SIZE, + .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_RESERVED }, + .val = { .val128 = { + .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_1 }, + .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_2 }, + .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_3 }, + .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_4 } } } }; + + rsi_ble_resp_add_serv_t new_serv_resp = { 0 }; + rsi_ble_add_service(custom_service, &new_serv_resp); + + // Adding custom characteristic declaration to the custom service + SilabsBleWrapper::rsi_ble_add_char_serv_att( + new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_ATTRIBUTE_HANDLE_LOCATION, + RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response + new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, custom_characteristic_RX); + + // Adding characteristic value attribute to the service + SilabsBleWrapper::rsi_ble_add_char_val_att( + new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, + custom_characteristic_RX, + RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response + data, sizeof(data), ATT_REC_IN_HOST); + + constexpr uuid_t custom_characteristic_TX = { .size = RSI_BLE_CUSTOM_CHARACTERISTIC_TX_SIZE, + .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_RESERVED }, + .val = { .val128 = { + .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_1 }, + .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_2 }, + .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_3 }, + .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_4 } } } }; + + // Adding custom characteristic declaration to the custom service + SilabsBleWrapper::rsi_ble_add_char_serv_att( + new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_ATTRIBUTE_HANDLE_LOCATION, + RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ | + RSI_BLE_ATT_PROPERTY_NOTIFY | RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response + new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION, custom_characteristic_TX); + + // Adding characteristic value attribute to the service + rsi_ble_measurement_hndl = new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION; + + // Adding characteristic value attribute to the service + rsi_ble_gatt_server_client_config_hndl = + new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_GATT_SERVER_CLIENT_HANDLE_LOCATION; + + SilabsBleWrapper::rsi_ble_add_char_val_att(new_serv_resp.serv_handler, rsi_ble_measurement_hndl, custom_characteristic_TX, + RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | + RSI_BLE_ATT_PROPERTY_READ | RSI_BLE_ATT_PROPERTY_NOTIFY | + RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response + data, sizeof(data), ATT_REC_MAINTAIN_IN_HOST); +} + } // namespace BLEManagerImpl BLEManagerImpl::sInstance; @@ -120,15 +181,14 @@ void BLEManagerImpl::ProcessEvent(SilabsBleWrapper::BleEvent_t inEvent) switch (inEvent.eventType) { case SilabsBleWrapper::BleEventType::RSI_BLE_CONN_EVENT: { - BLEMgrImpl().HandleConnectEvent((inEvent.eventData)); + BLEMgrImpl().HandleConnectEvent(inEvent.eventData); // Requests the connection parameters change with the remote device - rsi_ble_conn_params_update(inEvent.eventData->resp_enh_conn.dev_addr, BLE_MIN_CONNECTION_INTERVAL_MS, + rsi_ble_conn_params_update(inEvent.eventData.resp_enh_conn.dev_addr, BLE_MIN_CONNECTION_INTERVAL_MS, BLE_MAX_CONNECTION_INTERVAL_MS, BLE_SLAVE_LATENCY_MS, BLE_TIMEOUT_MS); - rsi_ble_set_data_len(inEvent.eventData->resp_enh_conn.dev_addr, RSI_BLE_TX_OCTETS, RSI_BLE_TX_TIME); + rsi_ble_set_data_len(inEvent.eventData.resp_enh_conn.dev_addr, RSI_BLE_TX_OCTETS, RSI_BLE_TX_TIME); // Used to send the Indication confirmation - memcpy(dev_address, inEvent.eventData->resp_enh_conn.dev_addr, RSI_DEV_ADDR_LEN); - ble_measurement_hndl = inEvent.eventData->rsi_ble_measurement_hndl; + memcpy(dev_address, inEvent.eventData.resp_enh_conn.dev_addr, RSI_DEV_ADDR_LEN); } break; case SilabsBleWrapper::BleEventType::RSI_BLE_DISCONN_EVENT: { @@ -143,7 +203,7 @@ void BLEManagerImpl::ProcessEvent(SilabsBleWrapper::BleEvent_t inEvent) break; case SilabsBleWrapper::BleEventType::RSI_BLE_EVENT_GATT_RD: { #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING - if (inEvent.eventData->rsi_ble_read_req->type == 0) + if (inEvent.eventData.rsi_ble_read_req->type == 0) { BLEMgrImpl().HandleC3ReadRequest(inEvent.eventData); } @@ -220,10 +280,10 @@ void BLEManagerImpl::sl_ble_init() SilabsBleWrapper::rsi_ble_on_event_indication_confirmation, NULL); // Exchange of GATT info with BLE stack - SilabsBleWrapper::rsi_ble_add_matter_service(); + rsi_ble_add_matter_service(); rsi_ble_set_random_address_with_value(randomAddrBLE); - sInstance.sBleEventQueue = osMessageQueueNew(WFX_QUEUE_SIZE, sizeof(WfxEvent_t), NULL); + sInstance.sBleEventQueue = osMessageQueueNew(WFX_QUEUE_SIZE, sizeof(SilabsBleWrapper::BleEvent_t), NULL); VerifyOrDie(sInstance.sBleEventQueue != nullptr); chip::DeviceLayer::Internal::BLEMgrImpl().HandleBootEvent(); @@ -440,7 +500,7 @@ CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const Chi PacketBufferHandle data) { int32_t status = 0; - status = rsi_ble_indicate_value(dev_address, ble_measurement_hndl, data->DataLength(), data->Start()); + status = rsi_ble_indicate_value(dev_address, rsi_ble_measurement_hndl, data->DataLength(), data->Start()); if (status != RSI_SUCCESS) { ChipLogProgress(DeviceLayer, "indication failed with error code %lx ", status); @@ -734,9 +794,9 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising(void) return err; } -void BLEManagerImpl::UpdateMtu(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::UpdateMtu(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - CHIPoBLEConState * bleConnState = GetConnectionState(evt->connectionHandle); + CHIPoBLEConState * bleConnState = GetConnectionState(evt.connectionHandle); if (bleConnState != NULL) { // bleConnState->MTU is a 10-bit field inside a uint16_t. We're @@ -748,10 +808,10 @@ void BLEManagerImpl::UpdateMtu(SilabsBleWrapper::sl_wfx_msg_t * evt) // TODO: https://github.com/project-chip/connectedhomeip/issues/2569 // tracks making this safe with a check or explaining why no check // is needed. - ChipLogProgress(DeviceLayer, "DriveBLEState UpdateMtu %d", evt->rsi_ble_mtu.mtu_size); + ChipLogProgress(DeviceLayer, "DriveBLEState UpdateMtu %d", evt.rsi_ble_mtu.mtu_size); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" - bleConnState->mtu = evt->rsi_ble_mtu.mtu_size; + bleConnState->mtu = evt.rsi_ble_mtu.mtu_size; #pragma GCC diagnostic pop ; } @@ -763,14 +823,13 @@ void BLEManagerImpl::HandleBootEvent(void) PlatformMgr().ScheduleWork(DriveBLEState, 0); } -void BLEManagerImpl::HandleConnectEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleConnectEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - AddConnection(evt->connectionHandle, evt->bondingHandle); + AddConnection(evt.connectionHandle, evt.bondingHandle); PlatformMgr().ScheduleWork(DriveBLEState, 0); } -// TODO:: Implementation need to be done. -void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleConnectionCloseEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt) { uint8_t connHandle = 1; @@ -780,7 +839,7 @@ void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * event.Type = DeviceEventType::kCHIPoBLEConnectionError; event.CHIPoBLEConnectionError.ConId = connHandle; - switch (evt->reason) + switch (evt.reason) { case RSI_BT_CTRL_REMOTE_USER_TERMINATED: @@ -792,7 +851,7 @@ void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; } - ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %x)", connHandle, evt->reason); + ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %x)", connHandle, evt.reason); PlatformMgr().PostEventOrDie(&event); @@ -804,11 +863,11 @@ void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * } } -void BLEManagerImpl::HandleWriteEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleWriteEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - ChipLogProgress(DeviceLayer, "Char Write Req, packet type %d", evt->rsi_ble_write.pkt_type); + ChipLogProgress(DeviceLayer, "Char Write Req, packet type %d", evt.rsi_ble_write.pkt_type); - if (evt->rsi_ble_write.handle[0] == (uint8_t) evt->rsi_ble_gatt_server_client_config_hndl) // TODO:: compare the handle exactly + if (evt.rsi_ble_write.handle[0] == (uint8_t) rsi_ble_gatt_server_client_config_hndl) // TODO:: compare the handle exactly { HandleTXCharCCCDWrite(evt); } @@ -818,23 +877,22 @@ void BLEManagerImpl::HandleWriteEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) } } -// TODO:: Need to implement this -void BLEManagerImpl::HandleTXCharCCCDWrite(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleTXCharCCCDWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt) { CHIP_ERROR err = CHIP_NO_ERROR; bool isIndicationEnabled = false; ChipDeviceEvent event; CHIPoBLEConState * bleConnState; - bleConnState = GetConnectionState(evt->connectionHandle); + bleConnState = GetConnectionState(evt.connectionHandle); VerifyOrExit(bleConnState != NULL, err = CHIP_ERROR_NO_MEMORY); // Determine if the client is enabling or disabling notification/indication. - if (evt->rsi_ble_write.att_value[0] != 0) + if (evt.rsi_ble_write.att_value[0] != 0) { isIndicationEnabled = true; } - ChipLogProgress(DeviceLayer, "HandleTXcharCCCDWrite - Config Flags value : %d", evt->rsi_ble_write.att_value[0]); + ChipLogProgress(DeviceLayer, "HandleTXcharCCCDWrite - Config Flags value : %d", evt.rsi_ble_write.att_value[0]); ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", isIndicationEnabled ? "subscribe" : "unsubscribe"); if (isIndicationEnabled) @@ -864,13 +922,13 @@ void BLEManagerImpl::HandleTXCharCCCDWrite(SilabsBleWrapper::sl_wfx_msg_t * evt) } } -void BLEManagerImpl::HandleRXCharWrite(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleRXCharWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt) { uint8_t conId = 1; CHIP_ERROR err = CHIP_NO_ERROR; System::PacketBufferHandle buf; - uint16_t writeLen = evt->rsi_ble_write.length; - uint8_t * data = (uint8_t *) evt->rsi_ble_write.att_value; + uint16_t writeLen = evt.rsi_ble_write.length; + uint8_t * data = (uint8_t *) evt.rsi_ble_write.att_value; // Copy the data to a packet buffer. buf = System::PacketBufferHandle::NewWithData(data, writeLen, 0, 0); @@ -997,9 +1055,9 @@ CHIP_ERROR BLEManagerImpl::EncodeAdditionalDataTlv() return err; } -void BLEManagerImpl::HandleC3ReadRequest(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleC3ReadRequest(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - sl_status_t ret = rsi_ble_gatt_read_response(evt->rsi_ble_read_req->dev_addr, GATT_READ_RESP, evt->rsi_ble_read_req->handle, + sl_status_t ret = rsi_ble_gatt_read_response(evt.rsi_ble_read_req->dev_addr, GATT_READ_RESP, evt.rsi_ble_read_req->handle, GATT_READ_ZERO_OFFSET, sInstance.c3AdditionalDataBufferHandle->DataLength(), sInstance.c3AdditionalDataBufferHandle->Start()); if (ret != SL_STATUS_OK) diff --git a/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp b/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp index c1af13e2cd807c..971852592c3e2e 100644 --- a/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp +++ b/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp @@ -26,9 +26,6 @@ using namespace chip::DeviceLayer::Internal; -// Global Variables -SilabsBleWrapper::BleEvent_t bleEvent; - /*==============================================*/ /** * @fn rsi_ble_on_mtu_event @@ -40,8 +37,9 @@ SilabsBleWrapper::BleEvent_t bleEvent; */ void SilabsBleWrapper::rsi_ble_on_mtu_event(rsi_ble_event_mtu_t * rsi_ble_mtu) { - bleEvent.eventType = BleEventType::RSI_BLE_MTU_EVENT; - memcpy(&bleEvent.eventData->rsi_ble_mtu, rsi_ble_mtu, sizeof(rsi_ble_event_mtu_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_MTU_EVENT, + .eventData = { .connectionHandle = 1, .rsi_ble_mtu = *rsi_ble_mtu } }; + BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -57,9 +55,9 @@ void SilabsBleWrapper::rsi_ble_on_mtu_event(rsi_ble_event_mtu_t * rsi_ble_mtu) */ void SilabsBleWrapper::rsi_ble_on_gatt_write_event(uint16_t event_id, rsi_ble_event_write_t * rsi_ble_write) { - bleEvent.eventType = BleEventType::RSI_BLE_GATT_WRITE_EVENT; - bleEvent.eventData->event_id = event_id; - memcpy(&bleEvent.eventData->rsi_ble_write, rsi_ble_write, sizeof(rsi_ble_event_write_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_GATT_WRITE_EVENT, + .eventData = { + .connectionHandle = 1, .event_id = event_id, .rsi_ble_write = *rsi_ble_write } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -74,10 +72,12 @@ void SilabsBleWrapper::rsi_ble_on_gatt_write_event(uint16_t event_id, rsi_ble_ev */ void SilabsBleWrapper::rsi_ble_on_enhance_conn_status_event(rsi_ble_event_enhance_conn_status_t * resp_enh_conn) { - bleEvent.eventType = BleEventType::RSI_BLE_CONN_EVENT; - bleEvent.eventData->connectionHandle = 1; - bleEvent.eventData->bondingHandle = 255; - memcpy(bleEvent.eventData->resp_enh_conn.dev_addr, resp_enh_conn->dev_addr, RSI_DEV_ADDR_LEN); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_CONN_EVENT, + .eventData = { + .connectionHandle = 1, + .bondingHandle = 255, + } }; + memcpy(bleEvent.eventData.resp_enh_conn.dev_addr, resp_enh_conn->dev_addr, RSI_DEV_ADDR_LEN); BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -93,8 +93,7 @@ void SilabsBleWrapper::rsi_ble_on_enhance_conn_status_event(rsi_ble_event_enhanc */ void SilabsBleWrapper::rsi_ble_on_disconnect_event(rsi_ble_event_disconnect_t * resp_disconnect, uint16_t reason) { - bleEvent.eventType = BleEventType::RSI_BLE_DISCONN_EVENT; - bleEvent.eventData->reason = reason; + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_DISCONN_EVENT, .eventData = { .reason = reason } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -110,9 +109,9 @@ void SilabsBleWrapper::rsi_ble_on_disconnect_event(rsi_ble_event_disconnect_t * void SilabsBleWrapper::rsi_ble_on_event_indication_confirmation(uint16_t resp_status, rsi_ble_set_att_resp_t * rsi_ble_event_set_att_rsp) { - bleEvent.eventType = BleEventType::RSI_BLE_GATT_INDICATION_CONFIRMATION; - bleEvent.eventData->resp_status = resp_status; - memcpy(&bleEvent.eventData->rsi_ble_event_set_att_rsp, rsi_ble_event_set_att_rsp, sizeof(rsi_ble_set_att_resp_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_GATT_INDICATION_CONFIRMATION, + .eventData = { .resp_status = resp_status, + .rsi_ble_event_set_att_rsp = *rsi_ble_event_set_att_rsp } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -128,9 +127,8 @@ void SilabsBleWrapper::rsi_ble_on_event_indication_confirmation(uint16_t resp_st */ void SilabsBleWrapper::rsi_ble_on_read_req_event(uint16_t event_id, rsi_ble_read_req_t * rsi_ble_read_req) { - bleEvent.eventType = BleEventType::RSI_BLE_EVENT_GATT_RD; - bleEvent.eventData->event_id = event_id; - memcpy(&bleEvent.eventData->rsi_ble_read_req, rsi_ble_read_req, sizeof(rsi_ble_read_req_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_EVENT_GATT_RD, + .eventData = { .event_id = event_id, .rsi_ble_read_req = rsi_ble_read_req } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -282,77 +280,3 @@ void SilabsBleWrapper::rsi_ble_add_char_val_att(void * serv_handler, uint16_t ha return; } - -/*==============================================*/ -/** - * @fn rsi_ble_add_matter_service - * @brief this function is used to add service for matter - * @return status (uint32_t) 0 for success. - * @section description - * This function is used at application to create new service. - */ - -uint32_t SilabsBleWrapper::rsi_ble_add_matter_service(void) -{ - uuid_t custom_service = { RSI_BLE_MATTER_CUSTOM_SERVICE_UUID }; - custom_service.size = RSI_BLE_MATTER_CUSTOM_SERVICE_SIZE; - custom_service.val.val16 = RSI_BLE_MATTER_CUSTOM_SERVICE_VALUE_16; - uint8_t data[RSI_BLE_MATTER_CUSTOM_SERVICE_DATA_LENGTH] = { RSI_BLE_MATTER_CUSTOM_SERVICE_DATA }; - - static const uuid_t custom_characteristic_RX = { - .size = RSI_BLE_CUSTOM_CHARACTERISTIC_RX_SIZE, - .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_RESERVED }, - .val = { .val128 = { .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_1 }, - .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_2 }, - .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_3 }, - .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_4 } } } - }; - - rsi_ble_resp_add_serv_t new_serv_resp = { 0 }; - rsi_ble_add_service(custom_service, &new_serv_resp); - - // Adding custom characteristic declaration to the custom service - rsi_ble_add_char_serv_att( - new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_ATTRIBUTE_HANDLE_LOCATION, - RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, custom_characteristic_RX); - - // Adding characteristic value attribute to the service - rsi_ble_add_char_val_att(new_serv_resp.serv_handler, - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, custom_characteristic_RX, - RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response - data, sizeof(data), ATT_REC_IN_HOST); - - static const uuid_t custom_characteristic_TX = { - .size = RSI_BLE_CUSTOM_CHARACTERISTIC_TX_SIZE, - .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_RESERVED }, - .val = { .val128 = { .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_1 }, - .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_2 }, - .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_3 }, - .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_4 } } } - }; - - // Adding custom characteristic declaration to the custom service - rsi_ble_add_char_serv_att( - new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_ATTRIBUTE_HANDLE_LOCATION, - RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ | - RSI_BLE_ATT_PROPERTY_NOTIFY | RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION, custom_characteristic_TX); - - // Adding characteristic value attribute to the service - bleEvent.eventData->rsi_ble_measurement_hndl = - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION; - - // Adding characteristic value attribute to the service - bleEvent.eventData->rsi_ble_gatt_server_client_config_hndl = - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_GATT_SERVER_CLIENT_HANDLE_LOCATION; - - rsi_ble_add_char_val_att(new_serv_resp.serv_handler, bleEvent.eventData->rsi_ble_measurement_hndl, custom_characteristic_TX, - RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ | - RSI_BLE_ATT_PROPERTY_NOTIFY | - RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response - data, sizeof(data), ATT_REC_MAINTAIN_IN_HOST); - - memset(&data, 0, sizeof(data)); - return 0; -} diff --git a/src/platform/silabs/rs911x/wfx_sl_ble_init.h b/src/platform/silabs/rs911x/wfx_sl_ble_init.h index 1e770de0727100..54351674ef121e 100644 --- a/src/platform/silabs/rs911x/wfx_sl_ble_init.h +++ b/src/platform/silabs/rs911x/wfx_sl_ble_init.h @@ -104,15 +104,13 @@ class SilabsBleWrapper rsi_ble_event_disconnect_t * resp_disconnect; rsi_ble_read_req_t * rsi_ble_read_req; rsi_ble_set_att_resp_t rsi_ble_event_set_att_rsp; - uint16_t rsi_ble_measurement_hndl; - uint16_t rsi_ble_gatt_server_client_config_hndl; uint16_t subscribed; }; struct BleEvent_t { BleEventType eventType; - sl_wfx_msg_t * eventData; + sl_wfx_msg_t eventData; }; // ALL Ble functions @@ -129,7 +127,6 @@ class SilabsBleWrapper uuid_t att_val_uuid); static void rsi_ble_add_char_val_att(void * serv_handler, uint16_t handle, uuid_t att_type_uuid, uint8_t val_prop, uint8_t * data, uint8_t data_len, uint8_t auth_read); - static uint32_t rsi_ble_add_matter_service(void); }; } // namespace Internal diff --git a/src/python_testing/TC_DeviceBasicComposition.py b/src/python_testing/TC_DeviceBasicComposition.py index 59182fa4e2fcb2..0f227c2c672ea4 100644 --- a/src/python_testing/TC_DeviceBasicComposition.py +++ b/src/python_testing/TC_DeviceBasicComposition.py @@ -108,7 +108,8 @@ from chip.clusters.ClusterObjects import ClusterAttributeDescriptor, ClusterObjectFieldDescriptor from chip.interaction_model import InteractionModelError, Status from chip.testing.basic_composition import BasicCompositionTests -from chip.testing.global_attribute_ids import AttributeIdType, ClusterIdType, GlobalAttributeIds, attribute_id_type, cluster_id_type +from chip.testing.global_attribute_ids import (AttributeIdType, ClusterIdType, CommandIdType, GlobalAttributeIds, attribute_id_type, + cluster_id_type, command_id_type) from chip.testing.matter_testing import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, MatterBaseTest, TestStep, async_test_body, default_matter_test_main) from chip.testing.taglist_and_topology_test import (create_device_type_list_for_root, create_device_type_lists, @@ -503,7 +504,7 @@ class RequiredMandatoryAttribute: location = CommandPathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, command_id=bad_cmd_id) vendor_id = get_vendor_id(bad_cmd_id) self.record_error(self.get_test_name( - ), location=location, problem=f'Command 0x{bad_cmd_id:08x} with bad prefix 0x{vendor_id:04x} in cluster 0x{cluster_id:08x}', spec_location='Manufacturer Extensible Identifier (MEI)') + ), location=location, problem=f'Command 0x{bad_cmd_id:08x} with bad prefix 0x{vendor_id:04x} in cluster 0x{cluster_id:08x}' + (' (Test Vendor)' if command_id_type(bad_cmd_id) == CommandIdType.kTest else ''), spec_location='Manufacturer Extensible Identifier (MEI)') success = False self.print_step(7, "Validate that none of the MEI global attribute IDs contain values outside of the allowed suffix range") diff --git a/src/python_testing/TC_TSTAT_4_2.py b/src/python_testing/TC_TSTAT_4_2.py index 6dad144f3050c4..85ff487a9dc639 100644 --- a/src/python_testing/TC_TSTAT_4_2.py +++ b/src/python_testing/TC_TSTAT_4_2.py @@ -37,6 +37,7 @@ import copy import logging import random +from collections import namedtuple import chip.clusters as Clusters from chip import ChipDeviceCtrl # Needed before chip.FabricAdmin @@ -418,11 +419,6 @@ async def test_TC_TSTAT_4_2(self): logger.info( "Couldn't run test step 4 since there were no built-in presets") - # Send the SetActivePresetRequest command - await self.send_set_active_preset_handle_request_command(value=b'\x03') - - activePresetHandle = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.ActivePresetHandle) - self.step("5") if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")): @@ -714,6 +710,28 @@ async def test_TC_TSTAT_4_2(self): self.step("18") if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")): + ScenarioHeadroom = namedtuple("ScenarioHeadroom", "presetScenario remaining") + # Generate list of tuples of scenarios and number of remaining presets per scenario allowed + presetScenarioHeadrooms = list(ScenarioHeadroom(presetType.presetScenario, + presetType.numberOfPresets - presetScenarioCounts.get(presetType.presetScenario, 0)) for presetType in presetTypes) + + if presetScenarioHeadrooms: + # Find the preset scenario with the smallest number of remaining allowed presets + presetScenarioHeadrooms = sorted(presetScenarioHeadrooms, key=lambda psh: psh.remaining) + presetScenarioHeadroom = presetScenarioHeadrooms[0] + + # Add one more preset than is allowed by the preset type + test_presets = copy.deepcopy(current_presets) + test_presets.extend([cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=presetScenarioHeadroom.presetScenario, + coolingSetpoint=coolSetpoint, heatingSetpoint=heatSetpoint, builtIn=False)] * (presetScenarioHeadroom.remaining + 1)) + + await self.send_atomic_request_begin_command() + + await self.write_presets(endpoint=endpoint, presets=test_presets, expected_status=Status.ResourceExhausted) + + # Clear state for next test. + await self.send_atomic_request_rollback_command() + # Calculate the length of the Presets list that could be created using the preset scenarios in PresetTypes and numberOfPresets supported for each scenario. totalExpectedPresetsLength = sum(presetType.numberOfPresets for presetType in presetTypes) diff --git a/src/python_testing/TestIdChecks.py b/src/python_testing/TestIdChecks.py index eda01ef9556493..c86d4bfe6d0d0b 100644 --- a/src/python_testing/TestIdChecks.py +++ b/src/python_testing/TestIdChecks.py @@ -15,9 +15,9 @@ # limitations under the License. # -from chip.testing.global_attribute_ids import (AttributeIdType, ClusterIdType, DeviceTypeIdType, attribute_id_type, cluster_id_type, - device_type_id_type, is_valid_attribute_id, is_valid_cluster_id, - is_valid_device_type_id) +from chip.testing.global_attribute_ids import (AttributeIdType, ClusterIdType, CommandIdType, DeviceTypeIdType, attribute_id_type, + cluster_id_type, command_id_type, device_type_id_type, is_valid_attribute_id, + is_valid_cluster_id, is_valid_command_id, is_valid_device_type_id) from chip.testing.matter_testing import MatterBaseTest, default_matter_test_main from mobly import asserts @@ -210,6 +210,71 @@ def check_all_bad(id): for id in prefix_bad: check_all_bad(id) + def test_command_ids(self): + standard_global_good = [0x0000_00E0, 0x0000_00FF, 0x0000_00E1, 0x0000_00FE] + standard_global_bad = [0x0000_01E0, 0x0000_0FFF, 0x0000_AAE1, 0x0000_BBFE, 0x0000_FFFF] + scoped_non_global_good = [0x0000_0000, 0x0000_00DF, 0x0000_0001] + scoped_non_global_bad = [0x0000_0F00, 0x0000_01DF, 0x0000_0F01] + manufacturer_good = [0x0001_0000, 0x0001_00FF, 0xFFF0_0000, 0xFFF0_00FF, 0x0001_00FE] + manufacturer_bad = [0x0001_0A00, 0x0001_0BFF, 0x0001_FFFF, 0xFFF0_0C00, 0xFFF0_D0FF, 0x0001_F0FE] + test_good = [0xFFF1_0000, 0xFFF1_00E0, 0xFFF1_00FF, 0xFFF4_0000, 0xFFF4_00E0, 0xFFF4_00FF] + test_bad = [0xFFF1_5000, 0xFFF1_F000, 0xFFF1_FFFF, 0xFFF4_5000, 0xFFF4_F000, 0xFFF4_FFFF] + prefix_bad = [0xFFF5_0000, 0xFFF5_4FFF, 0xFFF5_5000, 0xFFF5_F000, 0xFFF5_FFFF] + + def check_standard_global(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting standard global {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kStandardGlobal, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=False), msg) + + def check_scoped_non_global(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting scoped non-global {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kScopedNonGlobal, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=False), msg) + + def check_manufacturer(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting manufacturer {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kManufacturer, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=False), msg) + + def check_test(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting test {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kTest, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_false(is_valid_command_id(id_type, allow_test=False), msg) + + def check_all_bad(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting invalid {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kInvalid, msg) + asserts.assert_false(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_false(is_valid_command_id(id_type, allow_test=False), msg) + + for id in standard_global_good: + check_standard_global(id) + for id in standard_global_bad: + check_all_bad(id) + for id in scoped_non_global_good: + check_scoped_non_global(id) + for id in scoped_non_global_bad: + check_all_bad(id) + for id in manufacturer_good: + check_manufacturer(id) + for id in manufacturer_bad: + check_all_bad(id) + for id in test_good: + check_test(id) + for id in test_bad: + check_all_bad(id) + for id in prefix_bad: + check_all_bad(id) + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py b/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py index e692adfdfb5a10..f9fbd2e2ade835 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py @@ -61,6 +61,15 @@ class AttributeIdType(Enum): kManufacturer = auto(), kTest = auto(), + +class CommandIdType(Enum): + kInvalid = auto() + kStandardGlobal = auto(), + kScopedNonGlobal = auto(), + kManufacturer = auto(), + kTest = auto(), + + # ID helper classes - this allows us to use the values from the prefix and suffix table directly # because the class handles the non-inclusive range. @@ -92,6 +101,9 @@ def __contains__(self, id: int): CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX = SuffixIdRange(0xFC00, 0xFFFE) ATTRIBUTE_ID_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0xF000, 0xFFFE) ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0x0000, 0x4FFF) +COMMAND_ID_GLOBAL_STANDARD_SUFFIX = SuffixIdRange(0x00E0, 0x00FF) +COMMAND_ID_NON_GLOBAL_SCOPED_SUFFIX = SuffixIdRange(0x0000, 0x00DF) +COMMAND_ID_SUFFIX = SuffixIdRange(0x0000, 0x00FF) def device_type_id_type(id: int) -> DeviceTypeIdType: @@ -145,3 +157,22 @@ def is_valid_attribute_id(id_type: AttributeIdType, allow_test: bool = False): if allow_test: valid.append(AttributeIdType.kTest) return id_type in valid + + +def command_id_type(id: int) -> CommandIdType: + if id in STANDARD_PREFIX and id in COMMAND_ID_GLOBAL_STANDARD_SUFFIX: + return CommandIdType.kStandardGlobal + if id in STANDARD_PREFIX and id in COMMAND_ID_NON_GLOBAL_SCOPED_SUFFIX: + return CommandIdType.kScopedNonGlobal + if id in MANUFACTURER_PREFIX and id in COMMAND_ID_SUFFIX: + return CommandIdType.kManufacturer + if id in TEST_PREFIX and id in COMMAND_ID_SUFFIX: + return CommandIdType.kTest + return CommandIdType.kInvalid + + +def is_valid_command_id(id_type: CommandIdType, allow_test: bool = False): + valid = [CommandIdType.kStandardGlobal, CommandIdType.kScopedNonGlobal, CommandIdType.kManufacturer] + if allow_test: + valid.append(CommandIdType.kTest) + return id_type in valid diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index 0a40b1688d74cf..053fa575c6452d 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -919,6 +919,9 @@ class TestStep: expectation: str = "" is_commissioning: bool = False + def __str__(self): + return f'{self.test_plan_number}: {self.description}\tExpected outcome: {self.expectation}' + @dataclass class TestInfo: @@ -1325,7 +1328,7 @@ def extract_error_text() -> tuple[str, str]: if not trace: return no_stack_trace - if isinstance(exception, signals.TestError): + if isinstance(exception, signals.TestError) or isinstance(exception, signals.TestFailure): # Exception gets raised by the mobly framework, so the proximal error is one line back in the stack trace assert_candidates = [idx for idx, line in enumerate(trace) if "asserts" in line and "asserts.py" not in line] if not assert_candidates: @@ -1343,6 +1346,9 @@ def extract_error_text() -> tuple[str, str]: return probable_error.strip(), trace[file_candidates[-1]].strip() probable_error, probable_file = extract_error_text() + test_steps = self.get_defined_test_steps(self.current_test_info.name) + test_step = str(test_steps[self.current_step_index-1] + ) if test_steps is not None else 'UNKNOWN - no test steps provided in test script' logging.error(textwrap.dedent(f""" ****************************************************************** @@ -1353,8 +1359,12 @@ def extract_error_text() -> tuple[str, str]: * {probable_file} * {probable_error} * + * Test step: + * {test_step} + * + * Endpoint: {self.matter_test_config.endpoint} + * ******************************************************************* - """)) def on_pass(self, record): diff --git a/third_party/openthread/platforms/efr32/BUILD.gn b/third_party/openthread/platforms/efr32/BUILD.gn index 69e55a5d76151d..e270db2ae8757f 100644 --- a/third_party/openthread/platforms/efr32/BUILD.gn +++ b/third_party/openthread/platforms/efr32/BUILD.gn @@ -65,7 +65,6 @@ source_set("libopenthread-efr32") { "${sl_ot_efr32_root}/flash.c", "${sl_ot_efr32_root}/ieee802154-packet-utils.cpp", "${sl_ot_efr32_root}/misc.c", - "${sl_ot_efr32_root}/radio.c", "${sl_ot_efr32_root}/radio_coex.c", "${sl_ot_efr32_root}/radio_extension.c", "${sl_ot_efr32_root}/radio_power_manager.c", @@ -73,6 +72,9 @@ source_set("libopenthread-efr32") { "${sl_ot_efr32_root}/sleep.c", "${sl_ot_efr32_root}/soft_source_match_table.c", "${sl_ot_efr32_root}/system.c", + + # Temporary file until the files in the SI SDK is fixed + "${sdk_support_root}/protocol/openthread/platform-abstraction/efr32/radio.c", ] include_dirs = [ "${openthread_root}/examples/platforms/utils" ] diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 2aeb8b833ba760..287dbfa25130ea 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 2aeb8b833ba760ec29d5f340dd1ce7bcb61c5d56 +Subproject commit 287dbfa25130ead5010877e934effbb0a2534265 diff --git a/third_party/silabs/BUILD.gn b/third_party/silabs/BUILD.gn index e08c7cd0bd11bd..16e0ba68c4607a 100644 --- a/third_party/silabs/BUILD.gn +++ b/third_party/silabs/BUILD.gn @@ -206,7 +206,9 @@ if (wifi_soc != true) { # CCP board "${openthread_root}/src/core/mac/mac_frame.cpp", "${openthread_root}/src/core/mac/sub_mac.cpp", "${openthread_root}/src/core/thread/mle.cpp", - "${sl_ot_platform_abstraction}/efr32/radio.c", + + # Temporary file until the files in the SI SDK is fixed + "${sdk_support_root}/protocol/openthread/platform-abstraction/efr32/radio.c", ] include_dirs = [ "${sl_ot_platform_abstraction}/include" ] diff --git a/third_party/silabs/lwip.gni b/third_party/silabs/lwip.gni index b0b6a0db0d2c9f..9a35e7c45f7a61 100644 --- a/third_party/silabs/lwip.gni +++ b/third_party/silabs/lwip.gni @@ -169,10 +169,8 @@ template("lwip_target") { "${_lwip_root}/src/core/ipv6/ip6.c", "${_lwip_root}/src/core/ipv6/ip6_addr.c", "${_lwip_root}/src/core/ipv6/ip6_frag.c", + "${_lwip_root}/src/core/ipv6/mld6.c", "${_lwip_root}/src/core/ipv6/nd6.c", - - # TODO: When updating to next Si SDK version, revert change. - "${sdk_support_root}/src/core/ipv6/mld6.c", ] } diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 8dd7b9bb5f8577..bf647de36d841e 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 8dd7b9bb5f8577834140bcc54f7497ae3f4b9bd0 +Subproject commit bf647de36d841e62fdac5d37c0cdfc5ebf9200bc diff --git a/third_party/silabs/simplicity_sdk b/third_party/silabs/simplicity_sdk index aa5ce2e835dfdc..36e12f01947c2b 160000 --- a/third_party/silabs/simplicity_sdk +++ b/third_party/silabs/simplicity_sdk @@ -1 +1 @@ -Subproject commit aa5ce2e835dfdce8c20fb828f27d3a261946f946 +Subproject commit 36e12f01947c2bed82922015e87b926df0745bc2 diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp index 0b5178d3bcb208..7c4c38ae6cec3f 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp @@ -6495,6 +6495,8 @@ char const * DeviceTypeIdToText(chip::DeviceTypeId id) return "EVSE"; case 0x0000050D: return "Device Energy Management"; + case 0x0000050F: + return "Water Heater"; case 0x00000510: return "Electrical Sensor"; case 0x00000840: