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 * This class defines a spinel encoder. 50 * 51 */ 52 class Encoder 53 { 54 public: 55 /** 56 * This constructor initializes a `Encoder` object. 57 * 58 * @param[in] aNcpBuffer A reference to a `Spinel::Buffer` where the frames are written. 59 * 60 */ Encoder(Spinel::Buffer & aNcpBuffer)61 explicit Encoder(Spinel::Buffer &aNcpBuffer) 62 : mNcpBuffer(aNcpBuffer) 63 , mNumOpenStructs(0) 64 , mSavedNumOpenStructs(0) 65 { 66 } 67 68 /** 69 * This method begins a new frame to be added/written to the frame buffer. 70 * 71 * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling 72 * `BeginFrame()` will discard and clear the previous unfinished frame. 73 * 74 * @param[in] aPriority Priority level of the new input frame. 75 * 76 * @retval OT_ERROR_NONE Successfully started a new frame. 77 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. 78 * 79 */ 80 otError BeginFrame(Spinel::Buffer::Priority aPriority); 81 82 /** 83 * This method begins a new spinel command frame to be added/written to the frame buffer. 84 * 85 * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling 86 * `BeginFrame()` will discard and clear the previous unfinished frame. 87 * 88 * The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new 89 * frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level. 90 * 91 * @param[in] aHeader Spinel header for new the command frame. 92 * @param[in] aCommand Spinel command. 93 * 94 * @retval OT_ERROR_NONE Successfully started a new frame. 95 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. 96 * 97 */ 98 otError BeginFrame(uint8_t aHeader, unsigned int aCommand); 99 100 /** 101 * This method begins a new spinel property update command frame to be added/written to the frame buffer. 102 * 103 * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling 104 * `BeginFrame()` will discard and clear the previous unfinished frame. 105 * 106 * The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new 107 * frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level. 108 * 109 * This method saves the write position before the property key (see also `SavePosition()`) so that if fetching the 110 * property fails and the property key should be switched to `LAST_STATUS` with an error status, the saved 111 * position can be used to update the property key in the frame (see also `OverwriteWithLastStatusError()`) 112 * 113 * @param[in] aHeader Spinel header for new the command frame. 114 * @param[in] aCommand Spinel command. 115 * @param[in] aKey Spinel property key 116 * 117 * @retval OT_ERROR_NONE Successfully started a new frame. 118 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. 119 * 120 */ 121 otError BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey); 122 123 /** 124 * This method overwrites the property key with `LAST_STATUS` in a property update command frame. 125 * 126 * This method should be only used after a successful `BeginFrame(aHeader, aCommand, aPropertKey)`, otherwise, its 127 * behavior is undefined. 128 * 129 * This method moves the write position back to saved position by `BeginFrame()` and replaces the property key 130 * `SPINEL_PROP_LAST_STATUS` and writes the given spinel status error. 131 * 132 * @param[in] aStatus Spinel error status 133 * 134 * @retval OT_ERROR_NONE Successfully updated the frame. 135 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to update the frame. 136 * 137 */ 138 otError OverwriteWithLastStatusError(spinel_status_t aStatus); 139 140 /** 141 * This method finalizes/ends the current frame being written to the buffer. 142 * 143 * Before using this method `BeginFrame()` must be called to start and prepare a new frame. Otherwise, this method 144 * does nothing and returns error status `OT_ERROR_INVALID_STATE`. 145 * 146 * If no buffer space is available, this method will discard and clear the frame and return error status 147 * `OT_ERROR_NO_BUFS`. 148 * 149 * This method ensures to close any open structure (previously opened using `OpenStruct()` but not closed using 150 * `CloseStruct()`). 151 * 152 * @retval OT_ERROR_NONE Successfully ended the input frame. 153 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. 154 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 155 * 156 */ 157 otError EndFrame(void); 158 159 /** 160 * This method encodes and writes a boolean value to current input frame. 161 * 162 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 163 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 164 * 165 * If no buffer space is available, this method will discard and clear the current input frame and return the 166 * error status `OT_ERROR_NO_BUFS`. 167 * 168 * @param[in] aBool The boolean value to add to input frame. 169 * 170 * @retval OT_ERROR_NONE Successfully added given byte to the frame. 171 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 172 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 173 * 174 */ WriteBool(bool aBool)175 otError WriteBool(bool aBool) { return mNcpBuffer.InFrameFeedByte(aBool ? 0x01 : 0x00); } 176 177 /** 178 * This method encodes and writes a `uint8_t` value to current input frame. 179 * 180 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 181 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 182 * 183 * If no buffer space is available, this method will discard and clear the current input frame and return the 184 * error status `OT_ERROR_NO_BUFS`. 185 * 186 * @param[in] aUint8 The value to add to input frame. 187 * 188 * @retval OT_ERROR_NONE Successfully added given value to the frame. 189 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 190 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 191 * 192 */ WriteUint8(uint8_t aUint8)193 otError WriteUint8(uint8_t aUint8) { return mNcpBuffer.InFrameFeedByte(aUint8); } 194 195 /** 196 * This method encodes and writes an `int8_t` value to current input frame. 197 * 198 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 199 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 200 * 201 * If no buffer space is available, this method will discard and clear the current input frame and return the 202 * error status `OT_ERROR_NO_BUFS`. 203 * 204 * @param[in] aInt8 The value to add to input frame. 205 * 206 * @retval OT_ERROR_NONE Successfully added given value to the frame. 207 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 208 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 209 * 210 */ WriteInt8(int8_t aInt8)211 otError WriteInt8(int8_t aInt8) { return WriteUint8(static_cast<uint8_t>(aInt8)); } 212 213 /** 214 * This method encodes and writes a `uint16_t` value to current input frame. 215 * 216 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 217 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 218 * 219 * If no buffer space is available, this method will discard and clear the current input frame and return the 220 * error status `OT_ERROR_NO_BUFS`. 221 * 222 * @param[in] aUint16 The value to add to input frame. 223 * 224 * @retval OT_ERROR_NONE Successfully added given value to the frame. 225 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 226 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 227 * 228 */ 229 otError WriteUint16(uint16_t aUint16); 230 231 /** 232 * This method encodes and writes an `int16_t` value to current input frame. 233 * 234 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 235 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 236 * 237 * If no buffer space is available, this method will discard and clear the current input frame and return the 238 * error status `OT_ERROR_NO_BUFS`. 239 * 240 * @param[in] aInt16 The value to add to input frame. 241 * 242 * @retval OT_ERROR_NONE Successfully added given value to the frame. 243 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 244 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 245 * 246 */ WriteInt16(int16_t aInt16)247 otError WriteInt16(int16_t aInt16) { return WriteUint16(static_cast<uint16_t>(aInt16)); } 248 249 /** 250 * This method encodes and writes a `uint32_t` value to current input frame. 251 * 252 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 253 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 254 * 255 * If no buffer space is available, this method will discard and clear the current input frame and return the 256 * error status `OT_ERROR_NO_BUFS`. 257 * 258 * @param[in] aUint32 The value to add to input frame. 259 * 260 * @retval OT_ERROR_NONE Successfully added given value to the frame. 261 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 262 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 263 * 264 */ 265 otError WriteUint32(uint32_t aUint32); 266 267 /** 268 * This method encodes and writes an `int32_t` value to current input frame. 269 * 270 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 271 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 272 * 273 * If no buffer space is available, this method will discard and clear the current input frame and return the 274 * error status `OT_ERROR_NO_BUFS`. 275 * 276 * @param[in] aInt32 The value to add to input frame. 277 * 278 * @retval OT_ERROR_NONE Successfully added given value to the frame. 279 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 280 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 281 * 282 */ WriteInt32(int32_t aInt32)283 otError WriteInt32(int32_t aInt32) { return WriteUint32(static_cast<uint32_t>(aInt32)); } 284 285 /** 286 * This method encodes and writes a `uint64_t` value to current input frame. 287 * 288 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 289 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 290 * 291 * If no buffer space is available, this method will discard and clear the current input frame and return the 292 * error status `OT_ERROR_NO_BUFS`. 293 * 294 * @param[in] aUint64 The value to add to input frame. 295 * 296 * @retval OT_ERROR_NONE Successfully added given value to the frame. 297 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 298 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 299 * 300 */ 301 otError WriteUint64(uint64_t aUint64); 302 303 /** 304 * This method encodes and writes an `int64_t` value to current input frame. 305 * 306 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 307 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 308 * 309 * If no buffer space is available, this method will discard and clear the current input frame and return the 310 * error status `OT_ERROR_NO_BUFS`. 311 * 312 * @param[in] aInt64 The value to add to input frame. 313 * 314 * @retval OT_ERROR_NONE Successfully added given value to the frame. 315 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 316 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 317 * 318 */ WriteInt64(int64_t aInt64)319 otError WriteInt64(int64_t aInt64) { return WriteUint64(static_cast<uint64_t>(aInt64)); } 320 321 /** 322 * This method encodes (using spinel packed integer format) and writes a value to current input frame. 323 * 324 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 325 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 326 * 327 * If no buffer space is available, this method will discard and clear the current input frame and return the 328 * error status `OT_ERROR_NO_BUFS`. 329 * 330 * @param[in] aUint The value to add to input frame. 331 * 332 * @retval OT_ERROR_NONE Successfully added given value to the frame. 333 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. 334 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 335 * 336 */ 337 otError WriteUintPacked(unsigned int aUint); 338 339 /** 340 * This method 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 `spinel_ipv6addr_t`) 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 * 354 */ WriteIp6Address(const spinel_ipv6addr_t & aIp6Addr)355 otError WriteIp6Address(const spinel_ipv6addr_t &aIp6Addr) { return WriteIp6Address(aIp6Addr.bytes); } 356 357 /** 358 * This method encodes and writes an IPv6 address to current input frame. 359 * 360 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 361 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 362 * 363 * If no buffer space is available, this method will discard and clear the current input frame and return the 364 * error status `OT_ERROR_NO_BUFS`. 365 * 366 * @param[in] aIp6Addr A reference to the IPv6 address to be added (as `otIp6Address`) 367 * 368 * @retval OT_ERROR_NONE Successfully added given address to the frame. 369 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. 370 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 371 * 372 */ WriteIp6Address(const otIp6Address & aIp6Addr)373 otError WriteIp6Address(const otIp6Address &aIp6Addr) { return WriteIp6Address(aIp6Addr.mFields.m8); } 374 375 /** 376 * This method encodes and writes an IPv6 address to current input frame. 377 * 378 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 379 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 380 * 381 * If no buffer space is available, this method will discard and clear the current input frame and return the 382 * error status `OT_ERROR_NO_BUFS`. 383 * 384 * @param[in] aIp6AddrBuf A pointer to a buffer containing the IPv6 address. 385 * 386 * @retval OT_ERROR_NONE Successfully added given address to the frame. 387 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. 388 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 389 * 390 */ WriteIp6Address(const uint8_t * aIp6AddrBuf)391 otError WriteIp6Address(const uint8_t *aIp6AddrBuf) { return WriteData(aIp6AddrBuf, sizeof(spinel_ipv6addr_t)); } 392 393 /** 394 * This method encodes and writes an EUI64 value to current input frame. 395 * 396 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 397 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 398 * 399 * If no buffer space is available, this method will discard and clear the current input frame and return the 400 * error status `OT_ERROR_NO_BUFS`. 401 * 402 * @param[in] aEui64 A reference to the EUI64 value as a `spinel_eui64_t` type. 403 * 404 * @retval OT_ERROR_NONE Successfully added given value to the frame. 405 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. 406 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 407 * 408 */ WriteEui64(const spinel_eui64_t & aEui64)409 otError WriteEui64(const spinel_eui64_t &aEui64) { return WriteEui64(aEui64.bytes); } 410 411 /** 412 * This method encodes and writes an EUI64 value to current input frame. 413 * 414 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 415 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 416 * 417 * If no buffer space is available, this method will discard and clear the current input frame and return the 418 * error status `OT_ERROR_NO_BUFS`. 419 * 420 * @param[in] aExtAddress A reference to an `otExtAddress` 421 * 422 * @retval OT_ERROR_NONE Successfully added given value to the frame. 423 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. 424 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 425 * 426 */ WriteEui64(const otExtAddress & aExtAddress)427 otError WriteEui64(const otExtAddress &aExtAddress) { return WriteEui64(aExtAddress.m8); } 428 429 /** 430 * This method encodes and writes an EUI64 value to current input frame. 431 * 432 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 433 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 434 * 435 * If no buffer space is available, this method will discard and clear the current input frame and return the 436 * error status `OT_ERROR_NO_BUFS`. 437 * 438 * @param[in] aExtAddress A pointer to a buffer containing the EUI64 value. 439 * 440 * @retval OT_ERROR_NONE Successfully added given value to the frame. 441 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. 442 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 443 * 444 */ WriteEui64(const uint8_t * aEui64)445 otError WriteEui64(const uint8_t *aEui64) { return WriteData(aEui64, sizeof(spinel_eui64_t)); } 446 447 /** 448 * This method encodes and writes an EUI48 value to current input frame. 449 * 450 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 451 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 452 * 453 * If no buffer space is available, this method will discard and clear the current input frame and return the 454 * error status `OT_ERROR_NO_BUFS`. 455 * 456 * @param[in] aEui48 A reference to the EUI48 value. 457 * 458 * @retval OT_ERROR_NONE Successfully added given value to the frame. 459 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value. 460 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 461 * 462 */ WriteEui48(const spinel_eui48_t & aEui48)463 otError WriteEui48(const spinel_eui48_t &aEui48) { return WriteEui48(aEui48.bytes); } 464 465 /** 466 * This method encodes and writes an EUI48 value to current input frame. 467 * 468 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 469 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 470 * 471 * If no buffer space is available, this method will discard and clear the current input frame and return the 472 * error status `OT_ERROR_NO_BUFS`. 473 * 474 * @param[in] aEui48 A pointer to a buffer containing the EUI64 value. 475 * 476 * @retval OT_ERROR_NONE Successfully added given value to the frame. 477 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value. 478 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 479 * 480 */ WriteEui48(const uint8_t * aEui48)481 otError WriteEui48(const uint8_t *aEui48) { return WriteData(aEui48, sizeof(spinel_eui48_t)); } 482 483 /** 484 * This method encodes and writes a UTF8 string to current input frame. 485 * 486 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 487 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 488 * 489 * If no buffer space is available, this method will discard and clear the current input frame and return the 490 * error status `OT_ERROR_NO_BUFS`. 491 * 492 * @param[in] aUtf8 A const character pointer (C string). 493 * 494 * @retval OT_ERROR_NONE Successfully added given string to the frame. 495 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the string. 496 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 497 * 498 */ 499 otError WriteUtf8(const char *aUtf8); 500 501 /** 502 * This method encodes and writes a sequence of bytes to current input frame. 503 * 504 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 505 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 506 * 507 * If no buffer space is available, this method will discard and clear the current input frame and return the 508 * error status `OT_ERROR_NO_BUFS`. 509 * 510 * @param[in] aData A pointer to data buffer. 511 * @param[in] aDataLen The length (number of bytes) in the data buffer. 512 * 513 * @retval OT_ERROR_NONE Successfully added given data to the frame. 514 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 515 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 516 * 517 */ WriteData(const uint8_t * aData,uint16_t aDataLen)518 otError WriteData(const uint8_t *aData, uint16_t aDataLen) { return mNcpBuffer.InFrameFeedData(aData, aDataLen); } 519 520 /** 521 * This method encodes and writes a data blob (sequence of bytes) with its length prepended before the data. 522 * 523 * The length of the data (in bytes) is prepended (with the length encoded as a `uint16`). The size of the length 524 * field is not included in the length. This is similar to `SPINEL_DATATYPE_DATA_WLEN` type. 525 * 526 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 527 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 528 * 529 * If no buffer space is available, this method will discard and clear the current input frame and return the 530 * error status `OT_ERROR_NO_BUFS`. 531 * 532 * @param[in] aData A pointer to data buffer. 533 * @param[in] aDataLen The length (number of bytes) in the data buffer. 534 * 535 * @retval OT_ERROR_NONE Successfully added given data to the frame. 536 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 537 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 538 * 539 */ 540 otError WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen); 541 542 #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE 543 /** 544 * This method adds a message to the current input frame. 545 * 546 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 547 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 548 * 549 * If no buffer space is available, this method will discard and clear the frame and return error status 550 * `OT_ERROR_NO_BUFS`. 551 * 552 * The ownership of the passed-in message @p aMessage changes to underlying `Spinel::Buffer` ONLY when the entire 553 * frame is successfully finished (i.e., with a successful call to `EndFrame()` for the current frame being 554 * written), and in this case the `otMessage` instance will be freed once the frame is removed from the 555 * `Spinel::Buffer`. However, if the frame gets discarded before it is finished (e.g., running out of buffer space), 556 * the `otMessage` instance remains unchanged. 557 * 558 * @param[in] aMessage A message to be added to current frame. 559 * 560 * @retval OT_ERROR_NONE Successfully added the message to the frame. 561 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message. 562 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 563 * @retval OT_ERROR_INVALID_ARGS If @p aMessage is nullptr. 564 * 565 */ WriteMessage(otMessage * aMessage)566 otError WriteMessage(otMessage *aMessage) { return mNcpBuffer.InFrameFeedMessage(aMessage); } 567 #endif 568 569 /** 570 * This method encodes and writes a set of variables to the current input frame using a given spinel packing format 571 * string. 572 * 573 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 574 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 575 * 576 * If no buffer space is available, this method will discard and clear the current input frame and return the 577 * error status `OT_ERROR_NO_BUFS`. 578 * 579 * Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes. 580 * 581 * @param[in] aPackFormat A string giving the spinel packing format. 582 * @param[in] ... Variable arguments corresponding to the types given in @p aPackFormat (see 583 * `spinel_datatype_pack()`). 584 * 585 * @retval OT_ERROR_NONE Successfully added given data to the frame. 586 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 587 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 588 * 589 */ 590 otError WritePacked(const char *aPackFormat, ...); 591 592 /** 593 * This method encodes and writes a set of variables to the current input frame using a given spinel packing format 594 * string. 595 * 596 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 597 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 598 * 599 * If no buffer space is available, this method will discard and clear the current input frame and return the 600 * error status `OT_ERROR_NO_BUFS`. 601 * 602 * Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes. 603 * 604 * @param[in] aPackFormat A string giving the spinel packing format. 605 * @param[in] aArgs Variable arguments corresponding to the types given in @p aPackFormat (see 606 * `spinel_datatype_pack()`). 607 * 608 * @retval OT_ERROR_NONE Successfully added given data to the frame. 609 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 610 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 611 * 612 */ 613 otError WriteVPacked(const char *aPackFormat, va_list aArgs); 614 615 /** 616 * This method opens a struct in the current input frame. 617 * 618 * After a successful call to this method, all the subsequent `Write<SomeType>()` methods add the field/value to 619 * the current open struct until the struct is closed using `CloseStruct()` method. Structures can be nested. Up to 620 * `kMaxNestedStructs` nested structs can be opened at the same time. 621 * 622 * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this 623 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 624 * 625 * If no buffer space is available, this method will discard and clear the frame and return error status 626 * `OT_ERROR_NO_BUFS`. 627 * 628 * @retval OT_ERROR_NONE Successfully opened the struct. 629 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. 630 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if we reached 631 * the maximum number of nested open structures. 632 * 633 */ 634 otError OpenStruct(void); 635 636 /** 637 * This method closes the most recently opened struct (using `OpenStruct()`) in the current input frame. 638 * 639 * Each call to `CloseStruct()` must correspond to an earlier successfully opened struct. If a frame is ended using 640 * `EndFrame()` with remaining open structs, the `EndFrame()` method will close all the remaining structs. 641 * 642 * If no buffer space is available, this method will discard and clear the frame and return error status 643 * `OT_ERROR_NO_BUFS`. 644 * 645 * @retval OT_ERROR_NONE Successfully closed the most recently opened struct. 646 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. 647 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if there is no 648 * open struct to close 649 */ 650 otError CloseStruct(void); 651 652 /** 653 * This method saves the current write position in the input frame. 654 * 655 * The saved position can later be used to discard a portion of written/encoded frame and move the write pointer 656 * back to the saved position (using `ResetToSaved()`). 657 * 658 * @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition. 659 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 660 * 661 */ 662 otError SavePosition(void); 663 664 /** 665 * This method resets the write position of input frame back to a previously saved position. Any added content 666 * after the write position is discarded. 667 * 668 * The saved position must belong to the same input frame saved earlier with `SavePosition()`. This method cannot 669 * be used if the input frame has an added `otMessage`. 670 * 671 * @retval OT_ERROR_NONE Successfully reset the write position of current input frame. 672 * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. 673 * @retval OT_ERROR_INVALID_ARGS The saved position is not valid (does not belong to same input frame), or 674 * the input frame has an added `otMessage`. 675 * 676 */ 677 otError ResetToSaved(void); 678 679 private: 680 enum 681 { 682 kPackFormatBufferSize = 96, ///< Size of buffer used when encoding using `WritePacked()` or `WriteVPacked()`. 683 kMaxNestedStructs = 4, ///< Maximum number of nested structs. 684 }; 685 686 Spinel::Buffer & mNcpBuffer; 687 Spinel::Buffer::WritePosition mStructPosition[kMaxNestedStructs]; 688 uint8_t mNumOpenStructs; 689 690 uint8_t mSavedNumOpenStructs; 691 Spinel::Buffer::WritePosition mSavedPosition; 692 }; 693 694 } // namespace Spinel 695 } // namespace ot 696 697 #endif // SPINEL_ENCODER_HPP_ 698