LCOV - code coverage report
Current view: top level - lib/format - protocol_decoder.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 37 37 100.0 %
Date: 2024-02-15 08:20:41 Functions: 18 18 100.0 %

          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 1.14