1 /* 2 * Copyright (c) 2017, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /** 29 * @file 30 * This file contains the definitions of a spinel encoder. 31 */ 32 33 #ifndef SPINEL_ENCODER_HPP_ 34 #define SPINEL_ENCODER_HPP_ 35 36 #include "openthread-spinel-config.h" 37 38 #include <openthread/ip6.h> 39 #include <openthread/message.h> 40 #include <openthread/ncp.h> 41 42 #include "spinel.h" 43 #include "spinel_buffer.hpp" 44 45 namespace ot { 46 namespace Spinel { 47 48 /** 49 * Defines a spinel encoder. 50 */ 51 class Encoder 52 { 53 public: 54 /** 55 * Initializes a `Encoder` object. 56 * 57 * @param[in] aNcpBuffer A reference to a `Spinel::Buffer` where the frames are written. 58 */ Encoder(Spinel::Buffer & aNcpBuffer)59 explicit Encoder(Spinel::Buffer &aNcpBuffer) 60 : mNcpBuffer(aNcpBuffer) 61 , mNumOpenStructs(0) 62 , mSavedNumOpenStructs(0) 63 { 64 } 65 66 /** 67 * Begins a new frame to be added/written to the frame buffer. 68 * 69 * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling 70 * `BeginFrame()` will discard and clear the previous unfinished frame. 71 * 72 * @param[in] aPriority Priority level of the new input frame. 73 * 74 * @retval OT_ERROR_NONE Successfully started a new frame. 75 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. 76 */ 77 otError BeginFrame(Spinel::Buffer::Priority aPriority); 78 79 /** 80 * Begins a new spinel command frame to be added/written to the frame buffer. 81 * 82 * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling 83 * `BeginFrame()` will discard and clear the previous unfinished frame. 84 * 85 * The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new 86 * frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level. 87 * 88 * @param[in] aHeader Spinel header for new the command frame. 89 * @param[in] aCommand Spinel command. 90 * 91 * @retval OT_ERROR_NONE Successfully started a new frame. 92 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. 93 */ 94 otError BeginFrame(uint8_t aHeader, unsigned int aCommand); 95 96 /** 97 * Begins a new spinel property update command frame to be added/written to the frame buffer. 98 * 99 * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling 100 * `BeginFrame()` will discard and clear the previous unfinished frame. 101 * 102 * The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new 103 * frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level. 104 * 105 * Saves the write position before the property key (see also `SavePosition()`) so that if fetching the 106 * property fails and the property key should be switched to `LAST_STATUS` with an error status, the saved 107 * position can be used to update the property key in the frame (see also `OverwriteWithLastStatusError()`) 108 * 109 * @param[in] aHeader Spinel header for new the command frame. 110 * @param[in] aCommand Spinel command. 111 * @param[in] aKey Spinel property key 112 * 113 * @retval OT_ERROR_NONE Successfully started a new frame. 114 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. 115 */ 116 otError BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey); 117 118 /** 119 * Overwrites the property key with `LAST_STATUS` in a property update command frame. 120 * 121 * Should be only used after a successful `BeginFrame(aHeader, aCommand, aPropertyKey)`, otherwise, its 122 * behavior is undefined. 123 * 124 * Moves the write position back to saved position by `BeginFrame()` and replaces the property key 125 * `SPINEL_PROP_LAST_STATUS` and writes the given spinel status error. 126 * 127 * @param[in] aStatus Spinel error status 128 * 129 * @retval OT_ERROR_NONE Successfully updated the frame. 130 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to update the frame. 131 */ 132 otError OverwriteWithLastStatusError(spinel_status_t aStatus); 133 134 /** 135 * Finalizes/ends the current frame being written to the buffer. 136 * 137 * Before using this method `BeginFrame()` must be called to start and prepare a new frame. Otherwise, this method 138 * does nothing and returns error status `OT_ERROR_INVALID_STATE`. 139 * 140 * If no buffer space is available, this method will discard and clear the frame and return error status 141 * `OT_ERROR_NO_BUFS`. 142 * 143 * Ensures to close any open structure (previously opened using `OpenStruct()` but not closed using 144 * `CloseStruct()`). 145 * 146 * @retval OT_ERROR_NONE Successfully ended the input frame. 147 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. 148 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 149 */ 150 otError EndFrame(void); 151 152 /** 153 * Encodes and writes a boolean value to current input frame. 154 * 155 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 156 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 157 * 158 * If no buffer space is available, this method will discard and clear the current input frame and return the 159 * error status `OT_ERROR_NO_BUFS`. 160 * 161 * @param[in] aBool The boolean value to add to input frame. 162 * 163 * @retval OT_ERROR_NONE Successfully added given byte to the frame. 164 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 165 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 166 */ WriteBool(bool aBool)167 otError WriteBool(bool aBool) { return mNcpBuffer.InFrameFeedByte(aBool ? 0x01 : 0x00); } 168 169 /** 170 * Encodes and writes a `uint8_t` value to current input frame. 171 * 172 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 173 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 174 * 175 * If no buffer space is available, this method will discard and clear the current input frame and return the 176 * error status `OT_ERROR_NO_BUFS`. 177 * 178 * @param[in] aUint8 The value to add to input frame. 179 * 180 * @retval OT_ERROR_NONE Successfully added given value to the frame. 181 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 182 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 183 */ WriteUint8(uint8_t aUint8)184 otError WriteUint8(uint8_t aUint8) { return mNcpBuffer.InFrameFeedByte(aUint8); } 185 186 /** 187 * Encodes and writes an `int8_t` value to current input frame. 188 * 189 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 190 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 191 * 192 * If no buffer space is available, this method will discard and clear the current input frame and return the 193 * error status `OT_ERROR_NO_BUFS`. 194 * 195 * @param[in] aInt8 The value to add to input frame. 196 * 197 * @retval OT_ERROR_NONE Successfully added given value to the frame. 198 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 199 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 200 */ WriteInt8(int8_t aInt8)201 otError WriteInt8(int8_t aInt8) { return WriteUint8(static_cast<uint8_t>(aInt8)); } 202 203 /** 204 * Encodes and writes a `uint16_t` value to current input frame. 205 * 206 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 207 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 208 * 209 * If no buffer space is available, this method will discard and clear the current input frame and return the 210 * error status `OT_ERROR_NO_BUFS`. 211 * 212 * @param[in] aUint16 The value to add to input frame. 213 * 214 * @retval OT_ERROR_NONE Successfully added given value to the frame. 215 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 216 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 217 */ 218 otError WriteUint16(uint16_t aUint16); 219 220 /** 221 * Encodes and writes an `int16_t` value to current input frame. 222 * 223 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 224 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 225 * 226 * If no buffer space is available, this method will discard and clear the current input frame and return the 227 * error status `OT_ERROR_NO_BUFS`. 228 * 229 * @param[in] aInt16 The value to add to input frame. 230 * 231 * @retval OT_ERROR_NONE Successfully added given value to the frame. 232 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 233 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 234 */ WriteInt16(int16_t aInt16)235 otError WriteInt16(int16_t aInt16) { return WriteUint16(static_cast<uint16_t>(aInt16)); } 236 237 /** 238 * Encodes and writes a `uint32_t` value to current input frame. 239 * 240 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 241 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 242 * 243 * If no buffer space is available, this method will discard and clear the current input frame and return the 244 * error status `OT_ERROR_NO_BUFS`. 245 * 246 * @param[in] aUint32 The value to add to input frame. 247 * 248 * @retval OT_ERROR_NONE Successfully added given value to the frame. 249 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 250 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 251 */ 252 otError WriteUint32(uint32_t aUint32); 253 254 /** 255 * Encodes and writes an `int32_t` value to current input frame. 256 * 257 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 258 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 259 * 260 * If no buffer space is available, this method will discard and clear the current input frame and return the 261 * error status `OT_ERROR_NO_BUFS`. 262 * 263 * @param[in] aInt32 The value to add to input frame. 264 * 265 * @retval OT_ERROR_NONE Successfully added given value to the frame. 266 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 267 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 268 */ WriteInt32(int32_t aInt32)269 otError WriteInt32(int32_t aInt32) { return WriteUint32(static_cast<uint32_t>(aInt32)); } 270 271 /** 272 * Encodes and writes a `uint64_t` value to current input frame. 273 * 274 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 275 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 276 * 277 * If no buffer space is available, this method will discard and clear the current input frame and return the 278 * error status `OT_ERROR_NO_BUFS`. 279 * 280 * @param[in] aUint64 The value to add to input frame. 281 * 282 * @retval OT_ERROR_NONE Successfully added given value to the frame. 283 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 284 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 285 */ 286 otError WriteUint64(uint64_t aUint64); 287 288 /** 289 * Encodes and writes an `int64_t` value to current input frame. 290 * 291 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 292 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 293 * 294 * If no buffer space is available, this method will discard and clear the current input frame and return the 295 * error status `OT_ERROR_NO_BUFS`. 296 * 297 * @param[in] aInt64 The value to add to input frame. 298 * 299 * @retval OT_ERROR_NONE Successfully added given value to the frame. 300 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 301 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 302 */ WriteInt64(int64_t aInt64)303 otError WriteInt64(int64_t aInt64) { return WriteUint64(static_cast<uint64_t>(aInt64)); } 304 305 /** 306 * Encodes (using spinel packed integer format) and writes a value to current input frame. 307 * 308 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 309 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 310 * 311 * If no buffer space is available, this method will discard and clear the current input frame and return the 312 * error status `OT_ERROR_NO_BUFS`. 313 * 314 * @param[in] aUint The value to add to input frame. 315 * 316 * @retval OT_ERROR_NONE Successfully added given value to the frame. 317 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 318 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 319 */ 320 otError WriteUintPacked(unsigned int aUint); 321 322 /** 323 * Encodes and writes an IPv6 address to current input frame. 324 * 325 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 326 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 327 * 328 * If no buffer space is available, this method will discard and clear the current input frame and return the 329 * error status `OT_ERROR_NO_BUFS`. 330 * 331 * @param[in] aIp6Addr A reference to the IPv6 address to be added (as `spinel_ipv6addr_t`) 332 * 333 * @retval OT_ERROR_NONE Successfully added given address to the frame. 334 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. 335 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 336 */ WriteIp6Address(const spinel_ipv6addr_t & aIp6Addr)337 otError WriteIp6Address(const spinel_ipv6addr_t &aIp6Addr) { return WriteIp6Address(aIp6Addr.bytes); } 338 339 /** 340 * Encodes and writes an IPv6 address to current input frame. 341 * 342 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 343 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 344 * 345 * If no buffer space is available, this method will discard and clear the current input frame and return the 346 * error status `OT_ERROR_NO_BUFS`. 347 * 348 * @param[in] aIp6Addr A reference to the IPv6 address to be added (as `otIp6Address`) 349 * 350 * @retval OT_ERROR_NONE Successfully added given address to the frame. 351 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. 352 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 353 */ WriteIp6Address(const otIp6Address & aIp6Addr)354 otError WriteIp6Address(const otIp6Address &aIp6Addr) { return WriteIp6Address(aIp6Addr.mFields.m8); } 355 356 /** 357 * Encodes and writes an IPv6 address to current input frame. 358 * 359 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 360 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 361 * 362 * If no buffer space is available, this method will discard and clear the current input frame and return the 363 * error status `OT_ERROR_NO_BUFS`. 364 * 365 * @param[in] aIp6AddrBuf A pointer to a buffer containing the IPv6 address. 366 * 367 * @retval OT_ERROR_NONE Successfully added given address to the frame. 368 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. 369 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 370 */ WriteIp6Address(const uint8_t * aIp6AddrBuf)371 otError WriteIp6Address(const uint8_t *aIp6AddrBuf) { return WriteData(aIp6AddrBuf, sizeof(spinel_ipv6addr_t)); } 372 373 /** 374 * Encodes and writes an EUI64 value to current input frame. 375 * 376 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 377 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 378 * 379 * If no buffer space is available, this method will discard and clear the current input frame and return the 380 * error status `OT_ERROR_NO_BUFS`. 381 * 382 * @param[in] aEui64 A reference to the EUI64 value as a `spinel_eui64_t` type. 383 * 384 * @retval OT_ERROR_NONE Successfully added given value to the frame. 385 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. 386 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 387 */ WriteEui64(const spinel_eui64_t & aEui64)388 otError WriteEui64(const spinel_eui64_t &aEui64) { return WriteEui64(aEui64.bytes); } 389 390 /** 391 * Encodes and writes an EUI64 value to current input frame. 392 * 393 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 394 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 395 * 396 * If no buffer space is available, this method will discard and clear the current input frame and return the 397 * error status `OT_ERROR_NO_BUFS`. 398 * 399 * @param[in] aExtAddress A reference to an `otExtAddress` 400 * 401 * @retval OT_ERROR_NONE Successfully added given value to the frame. 402 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. 403 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 404 */ WriteEui64(const otExtAddress & aExtAddress)405 otError WriteEui64(const otExtAddress &aExtAddress) { return WriteEui64(aExtAddress.m8); } 406 407 /** 408 * Encodes and writes an EUI64 value to current input frame. 409 * 410 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 411 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 412 * 413 * If no buffer space is available, this method will discard and clear the current input frame and return the 414 * error status `OT_ERROR_NO_BUFS`. 415 * 416 * @param[in] aEui64 A pointer to a buffer containing the EUI64 value. 417 * 418 * @retval OT_ERROR_NONE Successfully added given value to the frame. 419 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. 420 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 421 */ WriteEui64(const uint8_t * aEui64)422 otError WriteEui64(const uint8_t *aEui64) { return WriteData(aEui64, sizeof(spinel_eui64_t)); } 423 424 /** 425 * Encodes and writes an EUI48 value to current input frame. 426 * 427 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 428 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 429 * 430 * If no buffer space is available, this method will discard and clear the current input frame and return the 431 * error status `OT_ERROR_NO_BUFS`. 432 * 433 * @param[in] aEui48 A reference to the EUI48 value. 434 * 435 * @retval OT_ERROR_NONE Successfully added given value to the frame. 436 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value. 437 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 438 */ WriteEui48(const spinel_eui48_t & aEui48)439 otError WriteEui48(const spinel_eui48_t &aEui48) { return WriteEui48(aEui48.bytes); } 440 441 /** 442 * Encodes and writes an EUI48 value to current input frame. 443 * 444 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 445 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 446 * 447 * If no buffer space is available, this method will discard and clear the current input frame and return the 448 * error status `OT_ERROR_NO_BUFS`. 449 * 450 * @param[in] aEui48 A pointer to a buffer containing the EUI64 value. 451 * 452 * @retval OT_ERROR_NONE Successfully added given value to the frame. 453 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value. 454 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 455 */ WriteEui48(const uint8_t * aEui48)456 otError WriteEui48(const uint8_t *aEui48) { return WriteData(aEui48, sizeof(spinel_eui48_t)); } 457 458 /** 459 * Encodes and writes a UTF8 string to current input frame. 460 * 461 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 462 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 463 * 464 * If no buffer space is available, this method will discard and clear the current input frame and return the 465 * error status `OT_ERROR_NO_BUFS`. 466 * 467 * @param[in] aUtf8 A const character pointer (C string). 468 * 469 * @retval OT_ERROR_NONE Successfully added given string to the frame. 470 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the string. 471 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 472 */ 473 otError WriteUtf8(const char *aUtf8); 474 475 /** 476 * Encodes and writes a sequence of bytes to current input frame. 477 * 478 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 479 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 480 * 481 * If no buffer space is available, this method will discard and clear the current input frame and return the 482 * error status `OT_ERROR_NO_BUFS`. 483 * 484 * @param[in] aData A pointer to data buffer. 485 * @param[in] aDataLen The length (number of bytes) in the data buffer. 486 * 487 * @retval OT_ERROR_NONE Successfully added given data to the frame. 488 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 489 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 490 */ WriteData(const uint8_t * aData,uint16_t aDataLen)491 otError WriteData(const uint8_t *aData, uint16_t aDataLen) { return mNcpBuffer.InFrameFeedData(aData, aDataLen); } 492 493 /** 494 * Encodes and writes a data blob (sequence of bytes) with its length prepended before the data. 495 * 496 * The length of the data (in bytes) is prepended (with the length encoded as a `uint16`). The size of the length 497 * field is not included in the length. This is similar to `SPINEL_DATATYPE_DATA_WLEN` type. 498 * 499 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 500 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 501 * 502 * If no buffer space is available, this method will discard and clear the current input frame and return the 503 * error status `OT_ERROR_NO_BUFS`. 504 * 505 * @param[in] aData A pointer to data buffer. 506 * @param[in] aDataLen The length (number of bytes) in the data buffer. 507 * 508 * @retval OT_ERROR_NONE Successfully added given data to the frame. 509 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 510 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 511 */ 512 otError WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen); 513 514 #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE 515 /** 516 * Adds a message to the current input frame. 517 * 518 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 519 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 520 * 521 * If no buffer space is available, this method will discard and clear the frame and return error status 522 * `OT_ERROR_NO_BUFS`. 523 * 524 * The ownership of the passed-in message @p aMessage changes to underlying `Spinel::Buffer` ONLY when the entire 525 * frame is successfully finished (i.e., with a successful call to `EndFrame()` for the current frame being 526 * written), and in this case the `otMessage` instance will be freed once the frame is removed from the 527 * `Spinel::Buffer`. However, if the frame gets discarded before it is finished (e.g., running out of buffer space), 528 * the `otMessage` instance remains unchanged. 529 * 530 * @param[in] aMessage A message to be added to current frame. 531 * 532 * @retval OT_ERROR_NONE Successfully added the message to the frame. 533 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message. 534 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 535 * @retval OT_ERROR_INVALID_ARGS If @p aMessage is nullptr. 536 */ WriteMessage(otMessage * aMessage)537 otError WriteMessage(otMessage *aMessage) { return mNcpBuffer.InFrameFeedMessage(aMessage); } 538 #endif 539 540 /** 541 * Encodes and writes a set of variables to the current input frame using a given spinel packing format 542 * string. 543 * 544 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 545 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 546 * 547 * If no buffer space is available, this method will discard and clear the current input frame and return the 548 * error status `OT_ERROR_NO_BUFS`. 549 * 550 * Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes. 551 * 552 * @param[in] aPackFormat A string giving the spinel packing format. 553 * @param[in] ... Variable arguments corresponding to the types given in @p aPackFormat (see 554 * `spinel_datatype_pack()`). 555 * 556 * @retval OT_ERROR_NONE Successfully added given data to the frame. 557 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 558 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 559 */ 560 otError WritePacked(const char *aPackFormat, ...); 561 562 /** 563 * Encodes and writes a set of variables to the current input frame using a given spinel packing format 564 * string. 565 * 566 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 567 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 568 * 569 * If no buffer space is available, this method will discard and clear the current input frame and return the 570 * error status `OT_ERROR_NO_BUFS`. 571 * 572 * Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes. 573 * 574 * @param[in] aPackFormat A string giving the spinel packing format. 575 * @param[in] aArgs Variable arguments corresponding to the types given in @p aPackFormat (see 576 * `spinel_datatype_pack()`). 577 * 578 * @retval OT_ERROR_NONE Successfully added given data to the frame. 579 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 580 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 581 */ 582 otError WriteVPacked(const char *aPackFormat, va_list aArgs); 583 584 /** 585 * Opens a struct in the current input frame. 586 * 587 * After a successful call to this method, all the subsequent `Write<SomeType>()` methods add the field/value to 588 * the current open struct until the struct is closed using `CloseStruct()` method. Structures can be nested. Up to 589 * `kMaxNestedStructs` nested structs can be opened at the same time. 590 * 591 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 592 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 593 * 594 * If no buffer space is available, this method will discard and clear the frame and return error status 595 * `OT_ERROR_NO_BUFS`. 596 * 597 * @retval OT_ERROR_NONE Successfully opened the struct. 598 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. 599 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if we reached 600 * the maximum number of nested open structures. 601 */ 602 otError OpenStruct(void); 603 604 /** 605 * Closes the most recently opened struct (using `OpenStruct()`) in the current input frame. 606 * 607 * Each call to `CloseStruct()` must correspond to an earlier successfully opened struct. If a frame is ended using 608 * `EndFrame()` with remaining open structs, the `EndFrame()` method will close all the remaining structs. 609 * 610 * If no buffer space is available, this method will discard and clear the frame and return error status 611 * `OT_ERROR_NO_BUFS`. 612 * 613 * @retval OT_ERROR_NONE Successfully closed the most recently opened struct. 614 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. 615 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if there is no 616 * open struct to close 617 */ 618 otError CloseStruct(void); 619 620 /** 621 * Saves the current write position in the input frame. 622 * 623 * The saved position can later be used to discard a portion of written/encoded frame and move the write pointer 624 * back to the saved position (using `ResetToSaved()`). 625 * 626 * @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition. 627 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 628 */ 629 otError SavePosition(void); 630 631 /** 632 * Resets the write position of input frame back to a previously saved position. Any added content 633 * after the write position is discarded. 634 * 635 * The saved position must belong to the same input frame saved earlier with `SavePosition()`. This method cannot 636 * be used if the input frame has an added `otMessage`. 637 * 638 * @retval OT_ERROR_NONE Successfully reset the write position of current input frame. 639 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 640 * @retval OT_ERROR_INVALID_ARGS The saved position is not valid (does not belong to same input frame), or 641 * the input frame has an added `otMessage`. 642 */ 643 otError ResetToSaved(void); 644 645 /** 646 * Clear NCP buffer on reset command. 647 */ 648 void ClearNcpBuffer(void); 649 650 private: 651 enum 652 { 653 kPackFormatBufferSize = 96, ///< Size of buffer used when encoding using `WritePacked()` or `WriteVPacked()`. 654 kMaxNestedStructs = 4, ///< Maximum number of nested structs. 655 }; 656 657 Spinel::Buffer &mNcpBuffer; 658 Spinel::Buffer::WritePosition mStructPosition[kMaxNestedStructs]; 659 uint8_t mNumOpenStructs; 660 661 uint8_t mSavedNumOpenStructs; 662 Spinel::Buffer::WritePosition mSavedPosition; 663 }; 664 665 } // namespace Spinel 666 } // namespace ot 667 668 #endif // SPINEL_ENCODER_HPP_ 669