Matter SDK Coverage Report
Current view: top level - lib/format - protocol_decoder.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 100.0 % 37 37
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 18 18

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2023 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : #pragma once
      19              : 
      20              : #include <lib/core/TLVReader.h>
      21              : #include <lib/format/FlatTreePosition.h>
      22              : #include <lib/format/tlv_meta.h>
      23              : #include <lib/support/StringBuilder.h>
      24              : #include <protocols/Protocols.h>
      25              : 
      26              : namespace chip {
      27              : namespace Decoders {
      28              : 
      29              : /// Represents an individual decoded entry for IM Payloads
      30              : /// Generally a name + value + metadata tuple, where name and value are never NULL.
      31              : class PayloadEntry
      32              : {
      33              : public:
      34              :     static constexpr uint32_t kInvalidId = 0xFFFFFFFF;
      35              :     enum class IMPayloadType
      36              :     {
      37              :         kNone = 0, // generally should not be used except initial init
      38              :         kValue,    // represents a simple value to output
      39              : 
      40              :         kNestingEnter, // Nested struct enter. Has name, empty value
      41              :         kNestingExit,  // Nested struct exit (has no name/value)
      42              : 
      43              :         // Content payloads
      44              :         kAttribute,
      45              :         kCommand,
      46              :         kEvent,
      47              :     };
      48              :     PayloadEntry(const PayloadEntry &)             = default;
      49              :     PayloadEntry & operator=(const PayloadEntry &) = default;
      50              : 
      51              :     PayloadEntry() : mType(IMPayloadType::kNone), mName(""), mValue("") {}
      52              : 
      53         1015 :     IMPayloadType GetType() const { return mType; }
      54              : 
      55              :     const char * GetName() const { return mName; }
      56              :     const char * GetValueText() const { return mValue; }
      57              : 
      58              :     /// valid only if payload is an IM Payload
      59           25 :     uint32_t GetClusterId() const { return mClusterId; };
      60              : 
      61              :     /// valid only if payload as an Attribute ID
      62           31 :     uint32_t GetAttributeId() const
      63              :     {
      64           31 :         VerifyOrReturnValue(mType == IMPayloadType::kAttribute, kInvalidId);
      65           31 :         return mSubId;
      66              :     }
      67              : 
      68              :     /// valid only if payload as a Command ID
      69            4 :     uint32_t GetCommandId() const
      70              :     {
      71            4 :         VerifyOrReturnValue(mType == IMPayloadType::kCommand, kInvalidId);
      72            4 :         return mSubId;
      73              :     }
      74              : 
      75              :     /// valid only if payload as a Command ID
      76            4 :     uint32_t GetEventId() const
      77              :     {
      78            4 :         VerifyOrReturnValue(mType == IMPayloadType::kEvent, kInvalidId);
      79            4 :         return mSubId;
      80              :     }
      81              : 
      82          236 :     static PayloadEntry SimpleValue(const char * name, const char * value)
      83              :     {
      84          236 :         return PayloadEntry(IMPayloadType::kValue, name, value);
      85              :     }
      86              : 
      87          166 :     static PayloadEntry NestingEnter(const char * name) { return PayloadEntry(IMPayloadType::kNestingEnter, name, ""); }
      88              : 
      89          166 :     static PayloadEntry NestingExit() { return PayloadEntry(IMPayloadType::kNestingExit, "", ""); }
      90              : 
      91           20 :     static PayloadEntry AttributePayload(uint32_t cluster_id, uint32_t attribute_id)
      92              :     {
      93           20 :         PayloadEntry result(IMPayloadType::kAttribute, "ATTR_DATA", "");
      94           20 :         result.mClusterId = cluster_id;
      95           20 :         result.mSubId     = attribute_id;
      96              : 
      97           20 :         return result;
      98              :     }
      99              : 
     100            2 :     static PayloadEntry CommandPayload(uint32_t cluster_id, uint32_t command_id)
     101              :     {
     102            2 :         PayloadEntry result(IMPayloadType::kCommand, "COMMAND_DATA", "");
     103            2 :         result.mClusterId = cluster_id;
     104            2 :         result.mSubId     = command_id;
     105            2 :         return result;
     106              :     }
     107              : 
     108            2 :     static PayloadEntry EventPayload(uint32_t cluster_id, uint32_t event_id)
     109              :     {
     110            2 :         PayloadEntry result(IMPayloadType::kEvent, "EVENT_DATA", "");
     111            2 :         result.mClusterId = cluster_id;
     112            2 :         result.mSubId     = event_id;
     113            2 :         return result;
     114              :     }
     115              : 
     116              : private:
     117          592 :     PayloadEntry(IMPayloadType type, const char * name, const char * value) : mType(type), mName(name), mValue(value) {}
     118              : 
     119              :     IMPayloadType mType = IMPayloadType::kValue;
     120              :     const char * mName  = nullptr;
     121              :     const char * mValue = nullptr;
     122              : 
     123              :     uint32_t mClusterId = 0;
     124              :     uint32_t mSubId     = 0; // attribute, command or event id
     125              : };
     126              : 
     127              : /// Sets up decoding of some Matter data payload
     128              : class PayloadDecoderInitParams
     129              : {
     130              : public:
     131              :     using DecodeTree           = const FlatTree::Node<chip::TLVMeta::ItemInfo> *;
     132              :     PayloadDecoderInitParams() = default;
     133              : 
     134              :     PayloadDecoderInitParams & SetProtocol(Protocols::Id value)
     135              :     {
     136              :         mProtocol = value;
     137              :         return *this;
     138              :     }
     139              : 
     140              :     PayloadDecoderInitParams & SetMessageType(uint8_t value)
     141              :     {
     142              :         mMessageType = value;
     143              :         return *this;
     144              :     }
     145              : 
     146              :     PayloadDecoderInitParams & SetProtocolDecodeTree(DecodeTree tree, size_t s)
     147              :     {
     148              :         mProtocolTree     = tree;
     149              :         mProtocolTreeSize = s;
     150              :         return *this;
     151              :     }
     152              : 
     153              :     template <size_t N>
     154              :     PayloadDecoderInitParams & SetProtocolDecodeTree(const std::array<const FlatTree::Node<chip::TLVMeta::ItemInfo>, N> & a)
     155              :     {
     156              :         return SetProtocolDecodeTree(a.data(), N);
     157              :     }
     158              : 
     159              :     PayloadDecoderInitParams & SetClusterDecodeTree(DecodeTree tree, size_t s)
     160              :     {
     161              :         mClusterTree     = tree;
     162              :         mClusterTreeSize = s;
     163              :         return *this;
     164              :     }
     165              : 
     166              :     template <size_t N>
     167              :     PayloadDecoderInitParams & SetClusterDecodeTree(const std::array<const FlatTree::Node<chip::TLVMeta::ItemInfo>, N> & a)
     168              :     {
     169              :         return SetClusterDecodeTree(a.data(), N);
     170              :     }
     171              : 
     172           28 :     DecodeTree GetProtocolDecodeTree() const { return mProtocolTree; }
     173           28 :     size_t GetProtocolDecodeTreeSize() const { return mProtocolTreeSize; }
     174           28 :     DecodeTree GetClusterDecodeTree() const { return mClusterTree; }
     175           28 :     size_t GetClusterDecodeTreeSize() const { return mClusterTreeSize; }
     176              : 
     177           28 :     Protocols::Id GetProtocol() const { return mProtocol; }
     178           28 :     uint8_t GetMessageType() const { return mMessageType; }
     179              : 
     180              : private:
     181              :     DecodeTree mProtocolTree = nullptr;
     182              :     size_t mProtocolTreeSize = 0;
     183              : 
     184              :     DecodeTree mClusterTree = nullptr;
     185              :     size_t mClusterTreeSize = 0;
     186              : 
     187              :     Protocols::Id mProtocol = Protocols::NotSpecified;
     188              :     uint8_t mMessageType    = 0;
     189              : };
     190              : 
     191              : class PayloadDecoderBase
     192              : {
     193              : public:
     194              :     static constexpr size_t kMaxDecodeDepth = 16;
     195              :     using DecodePosition                    = chip::FlatTree::Position<chip::TLVMeta::ItemInfo, kMaxDecodeDepth>;
     196              : 
     197              :     PayloadDecoderBase(const PayloadDecoderInitParams & params, StringBuilderBase & nameBuilder, StringBuilderBase & valueBuilder);
     198              : 
     199              :     /// Initialize decoding from the given reader
     200              :     /// Will create a copy of the reader, however the copy will contain
     201              :     /// pointers in the original reader (so data must stay valid while Next is called)
     202              :     void StartDecoding(const TLV::TLVReader & reader);
     203              : 
     204              :     void StartDecoding(chip::ByteSpan data)
     205              :     {
     206              :         TLV::TLVReader reader;
     207              :         reader.Init(data);
     208              :         StartDecoding(reader);
     209              :     }
     210              : 
     211              :     /// Get the next decoded entry from the underlying TLV
     212              :     ///
     213              :     /// If a cluster decoder is set, then kAttribute/kCommand/kEvent are ALWAYS decoded
     214              :     /// (even if unknown tags), otherwise they will be returned as separate PayloadEntry values.
     215              :     ///
     216              :     /// Returns false when decoding finished.
     217              :     bool Next(PayloadEntry & entry);
     218              : 
     219              :     const TLV::TLVReader & ReadState() const { return mReader; }
     220              : 
     221              : private:
     222              :     enum class State
     223              :     {
     224              :         kStarting,
     225              :         kValueRead,   // reading value for Payload
     226              :         kContentRead, // reading value for IMContent (i.e. decoded attr/cmd/event)
     227              :         kDone,
     228              :     };
     229              : 
     230              :     /// Move to the given attribute/event/command entry.
     231              :     ///
     232              :     /// [entry] MUST be of type command/attribute/event.
     233              :     ///
     234              :     /// This call either moves to "ContentDecoding mode" if content tree is available
     235              :     /// or leaves entry unchanged if content decoding tree is not available.
     236              :     void MoveToContent(PayloadEntry & entry);
     237              : 
     238              :     void NextFromStarting(PayloadEntry & entry);
     239              :     void NextFromValueRead(PayloadEntry & entry);
     240              :     void NextFromContentRead(PayloadEntry & entry);
     241              : 
     242              :     /// Enter the container in mReader.
     243              :     ///
     244              :     /// May change entry/state in case of errors.
     245              :     ///
     246              :     /// Returns false on error (and entry is changed in that case)
     247              :     bool ReaderEnterContainer(PayloadEntry & entry);
     248              : 
     249              :     /// Returns a "nesting enter" value, making sure that
     250              :     /// nesting depth is sufficient.
     251              :     void EnterContainer(PayloadEntry & entry);
     252              : 
     253              :     /// Returns a "nesting exit" value, making sure that
     254              :     /// nesting depth is sufficient.
     255              :     void ExitContainer(PayloadEntry & entry);
     256              : 
     257              :     const chip::Protocols::Id mProtocol;
     258              :     const uint8_t mMessageType;
     259              : 
     260              :     StringBuilderBase & mNameBuilder;
     261              :     StringBuilderBase & mValueBuilder;
     262              : 
     263              :     State mState = State::kStarting;
     264              :     TLV::TLVReader mReader;
     265              :     DecodePosition mPayloadPosition;
     266              :     DecodePosition mIMContentPosition;
     267              :     TLV::TLVType mNestingEnters[kMaxDecodeDepth];
     268              :     size_t mCurrentNesting = 0;
     269              : 
     270              :     /// incremental state for parsing of paths
     271              :     uint32_t mClusterId   = 0;
     272              :     uint32_t mAttributeId = 0;
     273              :     uint32_t mEventId     = 0;
     274              :     uint32_t mCommandId   = 0;
     275              : };
     276              : 
     277              : template <size_t kNameBufferSize, size_t kValueBufferSize>
     278              : class PayloadDecoder : public PayloadDecoderBase
     279              : {
     280              : public:
     281              :     PayloadDecoder(const PayloadDecoderInitParams & params) : PayloadDecoderBase(std::move(params), mName, mValue) {}
     282              : 
     283              : private:
     284              :     chip::StringBuilder<kNameBufferSize> mName;
     285              :     chip::StringBuilder<kValueBufferSize> mValue;
     286              : };
     287              : 
     288              : } // namespace Decoders
     289              : } // namespace chip
        

Generated by: LCOV version 2.0-1