3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * This file implements the handler for data model messages.
23 #include "DataModelHandler.h"
25 #include <app/chip-zcl-zpro-codec.h>
26 #include <app/util/af-types.h>
27 #include <app/util/attribute-storage.h>
28 #include <app/util/util.h>
29 #include <lib/support/logging/CHIPLogging.h>
30 #include <support/logging/CHIPLogging.h>
31 #include <system/SystemPacketBuffer.h>
33 using namespace ::chip;
36 * A data model message has nonzero length and always has a first byte whose
37 * value is one of: 0x00, 0x01, 0x02, 0x03. See chipZclEncodeZclHeader for the
38 * construction of the message and in particular the first byte.
40 * Echo messages should generally not have a first byte with those values, so we
41 * can use that to try to distinguish between the two.
43 bool ContentMayBeADataModelMessage(const System::PacketBufferHandle & buffer)
45 const size_t data_len = buffer->DataLength();
46 const uint8_t * data = buffer->Start();
47 bool maybeDataModelMessage = true;
49 // Has to have nonzero length.
50 VerifyOrExit(data_len > 0, maybeDataModelMessage = false);
52 // Has to have a valid first byte value.
53 VerifyOrExit(data[0] < 0x04, maybeDataModelMessage = false);
56 return maybeDataModelMessage;
60 * @brief implements something like "od -c", changes an arbitrary byte string
61 * into a single-line of ascii. Destroys any byte-wise encoding that
62 * might be present, e.g. utf-8.
64 * @param bytes potentially unprintable buffer
65 * @param bytes_len length of bytes
66 * @param out where to put the printable string
67 * @param out_len length of out
68 * @return size_t required size of output buffer, including null-termination
70 static size_t BinaryBytesToPrintableString(const uint8_t * bytes, size_t bytes_len, char * out, size_t out_len)
72 size_t required = 1; // always need null termination
73 memset(out, 0, out_len);
75 for (; bytes_len > 0; bytes_len--, bytes++)
77 uint8_t byte = *bytes;
79 if ((byte >= '\t' && byte <= '\r') || byte == '\\')
81 static const char * kCodes = "tnvfr";
82 char code = (byte == '\\') ? '\\' : kCodes[byte - '\t'];
91 else if (byte >= ' ' && byte <= '~')
102 static const size_t kBinCodeLen = sizeof("\\xFF") - 1;
103 static const char * kCodes = "0123456789ABCDEF";
105 required += kBinCodeLen;
106 if (out_len > kBinCodeLen)
110 *out++ = kCodes[(byte & 0xf0) >> 4];
111 *out++ = kCodes[byte & 0xf];
112 out_len -= kBinCodeLen;
120 void ProcessOthersMessage(const PacketHeader & header, System::PacketBufferHandle & buffer, SecureSessionMgr * mgr)
125 BinaryBytesToPrintableString(buffer->Start(), buffer->DataLength(), logmsg, sizeof(logmsg));
127 ChipLogProgress(AppServer, "Client sent: %s", logmsg);
129 // Attempt to echo back
130 err = mgr->SendMessage(header.GetSourceNodeId().Value(), std::move(buffer));
131 if (err != CHIP_NO_ERROR)
133 ChipLogProgress(AppServer, "Unable to echo back to client: %s", ErrorStr(err));
137 ChipLogProgress(AppServer, "Echo sent");
141 void ProcessDataModelMessage(const PacketHeader & header, System::PacketBufferHandle & buffer)
144 bool ok = extractApsFrame(buffer->Start(), buffer->DataLength(), &frame) > 0;
147 ChipLogProgress(Zcl, "APS frame processing success!");
151 ChipLogProgress(Zcl, "APS frame processing failure!");
156 uint16_t messageLen = extractMessage(buffer->Start(), buffer->DataLength(), &message);
157 ok = emberAfProcessMessage(&frame,
160 header.GetSourceNodeId().Value(), // source identifier
165 ChipLogProgress(Zcl, "Data model processing success!");
169 ChipLogProgress(Zcl, "Data model processing failure!");
174 * Handle a message that should be processed via our data model processing
175 * codepath. This function will free the packet buffer.
177 * @param [in] buffer The buffer holding the message. This function guarantees
178 * that it will free the buffer before returning.
180 void HandleDataModelMessage(const PacketHeader & header, System::PacketBufferHandle buffer, SecureSessionMgr * mgr)
182 // FIXME: Long-term we shouldn't be guessing what sort of message this is
183 // based on the message bytes. We're doing this for now to support both
184 // data model messages and text echo messages, but in the long term we
185 // should either do echo via a data model command or do echo on a separate
186 // port from data model processing.
187 if (ContentMayBeADataModelMessage(buffer))
189 ProcessDataModelMessage(header, buffer);
193 ProcessOthersMessage(header, buffer, mgr);
197 void InitDataModelHandler()
199 emberAfEndpointConfigure();