• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *    Copyright (c) 2016, 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 includes definitions for an HDLC-lite encoder and decoder.
31  */
32 
33 #ifndef HDLC_HPP_
34 #define HDLC_HPP_
35 
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <openthread/error.h>
41 
42 #include "common/array.hpp"
43 #include "common/code_utils.hpp"
44 #include "common/debug.hpp"
45 #include "common/encoding.hpp"
46 
47 namespace ot {
48 
49 /**
50  * @namespace ot::Hdlc
51  *
52  * @brief
53  *   This namespace includes definitions for the HDLC-lite encoder and decoder.
54  *
55  */
56 namespace Hdlc {
57 
58 /**
59  * This class defines a frame write pointer used by `Hdlc::Encoder` or `Hdlc::Decoder`.
60  *
61  * This class defines the minimum set of APIs used by `Encoder/Decoder` for writing an encoded/decoded frame. It is
62  * simply a wrapper over a pointer into a buffer indicating where next byte should be written. Along with a write
63  * pointer, this class stores a remaining length variable indicating number of remaining bytes that can be written into
64  * the buffer.
65  *
66  * @note This class does NOT define the underlying buffer space or how it is being managed.
67  *
68  * `Encoder` or `Decoder` users are expected to use sub-classes of this class adding the buffer space and implementing
69  * the frame buffer management scheme.
70  *
71  * Two template sub-class `FrameBuffer` and `MultiFrameBuffer` are defined which respectively allow storing a single
72  * frame or multiple frames (FIFO queue of frame) in a buffer of a given size.
73  *
74  */
75 class FrameWritePointer
76 {
77 public:
78     /**
79      * This method indicates whether there is buffer space available to write @p aWriteLength bytes.
80      *
81      * param[in] aWriteLength       Number of bytes to write.
82      *
83      * @retval TRUE                 Enough buffer space is available to write the requested number of bytes.
84      * @retval FALSE                Insufficient buffer space to write the requested number of bytes.
85      *
86      */
CanWrite(uint16_t aWriteLength) const87     bool CanWrite(uint16_t aWriteLength) const { return (mRemainingLength >= aWriteLength); }
88 
89     /**
90      * This method writes a byte into the buffer and updates the write pointer (if space is available).
91      *
92      * @retval OT_ERROR_NONE     Successfully wrote the byte and updated the pointer.
93      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space to write the byte.
94      *
95      */
WriteByte(uint8_t aByte)96     otError WriteByte(uint8_t aByte)
97     {
98         return CanWrite(sizeof(uint8_t)) ? (*mWritePointer++ = aByte, mRemainingLength--, OT_ERROR_NONE)
99                                          : OT_ERROR_NO_BUFS;
100     }
101 
102     /**
103      * This method undoes the last @p aUndoLength writes, removing them from frame.
104      *
105      * @note Caller should ensure that @p aUndoLength is less than or equal to the number of previously written bytes
106      * into the frame. This method does not perform any checks and its behavior is undefined if @p aUndoLength is
107      * larger than the number of bytes previously written into the frame.
108      *
109      * @param[in]  aUndoLength   Number of bytes to remove (number of last `WriteByte()` calls to undo).
110      *
111      */
UndoLastWrites(uint16_t aUndoLength)112     void UndoLastWrites(uint16_t aUndoLength)
113     {
114         mWritePointer -= aUndoLength;
115         mRemainingLength += aUndoLength;
116     }
117 
118 protected:
FrameWritePointer(void)119     FrameWritePointer(void)
120         : mWritePointer(nullptr)
121         , mRemainingLength(0)
122     {
123     }
124 
125     uint8_t *mWritePointer;    ///< A pointer to current write position in the buffer.
126     uint16_t mRemainingLength; ///< Number of remaining bytes available to write.
127 };
128 
129 /**
130  * This class defines a template frame buffer of a given size for storing a single frame.
131  *
132  * The template parameter `kSize` specifies the size of the buffer.
133  *
134  */
135 template <uint16_t kSize> class FrameBuffer : public FrameWritePointer
136 {
137 public:
138     /**
139      * This constructor initializes the `FrameBuffer` object.
140      *
141      */
FrameBuffer(void)142     FrameBuffer(void)
143         : FrameWritePointer()
144     {
145         Clear();
146     }
147 
148     /**
149      * This method clears the buffer, moving the write pointer to the beginning of the buffer.
150      *
151      */
Clear(void)152     void Clear(void)
153     {
154         mWritePointer    = mBuffer;
155         mRemainingLength = sizeof(mBuffer);
156     }
157 
158     /**
159      * This method indicates whether the buffer is empty or contains a frame.
160      *
161      * @retval TRUE  Buffer is empty
162      * @retval FALSE Buffer contains a frame
163      *
164      */
IsEmpty(void) const165     bool IsEmpty(void) const { return (mWritePointer == mBuffer); }
166 
167     /**
168      * This method gets the length (number of bytes) in the frame.
169      *
170      * @returns The length (number of bytes) in the frame.
171      *
172      */
GetLength(void) const173     uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mBuffer); }
174 
175     /**
176      * This method gets a pointer to start of the frame.
177      *
178      * @returns A pointer to start of the frame.
179      *
180      */
GetFrame(void)181     uint8_t *GetFrame(void) { return mBuffer; }
182 
183 private:
184     uint8_t mBuffer[kSize];
185 };
186 
187 /**
188  * This class defines a template frame buffer of a given size for storing multiple frames.
189  *
190  * The template parameter `kSize` specifies the total size of the buffer.
191  *
192  * Unlike `FrameBuffer` class where a single frame can be stored, this class is capable of saving multiple frames
193  * in a FIFO queue format.
194  *
195  */
196 template <uint16_t kSize> class MultiFrameBuffer : public FrameWritePointer
197 {
198 public:
199     /**
200      * This constructor initializes the `MultiFrameBuffer` object.
201      *
202      */
MultiFrameBuffer(void)203     MultiFrameBuffer(void)
204         : FrameWritePointer()
205     {
206         Clear();
207     }
208 
209     /**
210      * This method clears the buffer, removing current frame and all previously saved frames.
211      *
212      * It moves the write pointer to the beginning of the buffer.
213      *
214      */
Clear(void)215     void Clear(void)
216     {
217         mWriteFrameStart = mBuffer;
218         mWritePointer    = mBuffer + kHeaderSize;
219         mRemainingLength = kSize - kHeaderSize;
220 
221         IgnoreError(SetSkipLength(0));
222     }
223 
224     /**
225      * This method indicates whether the current frame (being written) is empty or not.
226      *
227      * @retval TRUE  Current frame is empty.
228      * @retval FALSE Current frame is not empty.
229      *
230      */
HasFrame(void) const231     bool HasFrame(void) const { return (mWritePointer != GetFrame()); }
232 
233     /**
234      * This method sets the length (number of bytes) of the current frame being written.
235      *
236      * param[in] aLength  The length of current frame.
237      *
238      * @retval OT_ERROR_NONE     Successfully set the length of the current frame.
239      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space to hold a frame of length @p aLength.
240      *
241      */
SetLength(uint16_t aLength)242     otError SetLength(uint16_t aLength)
243     {
244         otError error = OT_ERROR_NO_BUFS;
245 
246         if (GetFrame() + aLength <= GetArrayEnd(mBuffer))
247         {
248             mWritePointer    = GetFrame() + aLength;
249             mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
250             error            = OT_ERROR_NONE;
251         }
252 
253         return error;
254     }
255 
256     /**
257      * This method gets the length (number of bytes) in the current frame being written into the buffer.
258      *
259      * @returns The length (number of bytes) in the frame.
260      *
261      */
GetLength(void) const262     uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - GetFrame()); }
263 
264     /**
265      * This method sets the length (number of bytes) of reserved buffer in front of the current frame being written.
266      *
267      * param[in] aSkipLength  The length of reserved buffer.
268      *
269      * @retval OT_ERROR_NONE     Successfully set the length of reserved buffer.
270      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space to hold a reserved buffer of length @p aLength.
271      *
272      */
SetSkipLength(uint16_t aSkipLength)273     otError SetSkipLength(uint16_t aSkipLength)
274     {
275         otError error = OT_ERROR_NO_BUFS;
276 
277         if (mWriteFrameStart + kHeaderSize + aSkipLength <= GetArrayEnd(mBuffer))
278         {
279             Encoding::LittleEndian::WriteUint16(aSkipLength, mWriteFrameStart + kHeaderSkipLengthOffset);
280             mWritePointer    = GetFrame();
281             mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
282             error            = OT_ERROR_NONE;
283         }
284 
285         return error;
286     }
287 
288     /**
289      * This method gets the length (number of bytes) of reserved buffer in front of the current frame being written.
290      *
291      * @returns The length (number of bytes) of the reserved buffer.
292      *
293      */
GetSkipLength(void) const294     uint16_t GetSkipLength(void) const
295     {
296         return Encoding::LittleEndian::ReadUint16(mWriteFrameStart + kHeaderSkipLengthOffset);
297     }
298 
299     /**
300      * This method gets a pointer to the start of the current frame.
301      *
302      * @returns A pointer to the start of the frame.
303      *
304      */
GetFrame(void) const305     uint8_t *GetFrame(void) const { return mWriteFrameStart + kHeaderSize + GetSkipLength(); }
306 
307     /**
308      * This method gets the maximum length of the current frame.
309      *
310      * @returns The maximum length of the current frame.
311      *
312      */
GetFrameMaxLength(void) const313     uint16_t GetFrameMaxLength(void) const { return static_cast<uint16_t>(mBuffer + kSize - GetFrame()); }
314 
315     /**
316      * This method saves the current frame and prepares the write pointer for a next frame to be written into the
317      * buffer.
318      *
319      * Saved frame can be retrieved later using `GetNextSavedFrame()`.
320      *
321      */
SaveFrame(void)322     void SaveFrame(void)
323     {
324         Encoding::LittleEndian::WriteUint16(GetSkipLength() + GetLength(), mWriteFrameStart + kHeaderTotalLengthOffset);
325         mWriteFrameStart = mWritePointer;
326         IgnoreError(SetSkipLength(0));
327         mWritePointer    = GetFrame();
328         mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
329     }
330 
331     /**
332      * This method discards the current frame and prepares the write pointer for a next frame to be written into the
333      * buffer.
334      *
335      */
DiscardFrame(void)336     void DiscardFrame(void)
337     {
338         IgnoreError(SetSkipLength(0));
339 
340         mWritePointer    = GetFrame();
341         mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
342     }
343 
344     /**
345      * This method indicates whether there are any saved frames in the buffer.
346      *
347      * @retval TRUE  There is at least one saved frame in the buffer.
348      * @retval FALSE There is no saved frame in the buffer.
349      *
350      */
HasSavedFrame(void) const351     bool HasSavedFrame(void) const { return (mWriteFrameStart != mBuffer); }
352 
353     /**
354      * This method iterates through previously saved frames in the buffer, getting a next frame in the queue.
355      *
356      * @param[in,out] aFrame   On entry, should point to a previous saved frame or nullptr to get the first frame.
357      *                         On exit, the pointer variable is updated to next frame or set to nullptr if there are
358      *                         none.
359      * @param[in,out] aLength  On entry, should be a reference to the frame length of the previous saved frame.
360      *                         On exit, the reference is updated to the frame length (number of bytes) of next frame.
361      *
362      * @retval OT_ERROR_NONE       Updated @aFrame and @aLength successfully with the next saved frame.
363      * @retval OT_ERROR_NOT_FOUND  No more saved frame in the buffer.
364      *
365      */
GetNextSavedFrame(uint8_t * & aFrame,uint16_t & aLength)366     otError GetNextSavedFrame(uint8_t *&aFrame, uint16_t &aLength)
367     {
368         otError error = OT_ERROR_NONE;
369 
370         OT_ASSERT(aFrame == nullptr || (mBuffer <= aFrame && aFrame < GetArrayEnd(mBuffer)));
371 
372         aFrame = (aFrame == nullptr) ? mBuffer : aFrame + aLength;
373 
374         if (aFrame != mWriteFrameStart)
375         {
376             uint16_t totalLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderTotalLengthOffset);
377             uint16_t skipLength  = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderSkipLengthOffset);
378 
379             aLength = totalLength - skipLength;
380             aFrame += kHeaderSize + skipLength;
381         }
382         else
383         {
384             aLength = 0;
385             aFrame  = nullptr;
386             error   = OT_ERROR_NOT_FOUND;
387         }
388 
389         return error;
390     }
391 
392     /**
393      * This method clears all saved frames from the buffer and adjusts all the pointers.
394      *
395      * @note This method moves the pointers into the buffer and also copies the content. Any previously retrieved
396      * pointer to buffer (from `GetFrame()` or `GetNextSavedFrame()`) should be considered invalid after calling this
397      * method.
398      *
399      */
ClearSavedFrames(void)400     void ClearSavedFrames(void)
401     {
402         uint16_t len = static_cast<uint16_t>(mWriteFrameStart - mBuffer);
403 
404         if (len > 0)
405         {
406             memmove(mBuffer, mWriteFrameStart, static_cast<uint16_t>(mWritePointer - mWriteFrameStart));
407             mWritePointer -= len;
408             mWriteFrameStart -= len;
409             mRemainingLength += len;
410         }
411     }
412 
413 private:
414     /*
415      * The diagram below illustrates the format of a saved frame.
416      *
417      *  +---------+-------------+------------+----------------+----------------------------+
418      *  | Octets: |      2      |      2     |   SkipLength   |  TotalLength - SkipLength  |
419      *  +---------+-------------+------------+----------------+----------------------------+
420      *  | Fields: | TotalLength | SkipLength | ReservedBuffer |         FrameBuffer        |
421      *  +---------+-------------+------------+----------------+----------------------------+
422      *
423      *   -  "TotalLength"   : The total length of the `ReservedBuffer` and `FrameBuffer`. It is stored in header bytes
424      *                        as a `uint16_t` value using little-endian encoding.
425      *   -  "SkipLength"    : The length of the `ReservedBuffer`. It is stored in header bytes as a `uint16_t` value
426      *                        using little-endian encoding.
427      *   -  "ReservedBuffer": A reserved buffer in front of `FrameBuffer`. User can use it to store extra header, etc.
428      *   -  "FrameBuffer"   : Frame buffer.
429      *
430      * The diagram below illustrates how the frames are saved in the buffer.
431      *
432      * The diagram shows `mBuffer` and different pointers into the buffer. It represents buffer state when there are
433      * two saved frames in the buffer.
434      *
435      *          Saved frame #1           Saved frame #2       Current frame being written
436      *   /                        \ /                      \ /                           \
437      *   +-----------+-------------+-----------+------------+---------+--------------------------------------------+
438      *   | header #1 |   ...       | header #2 |  ...       | header  |  ...             | ...                     |
439      *   +-----------+-------------+-----------+------------+---------+--------------------------------------------+
440      *   ^                                                  ^                            ^\                       /^
441      *   |                                                  |                            |   mRemainingLength      |
442      *  mBuffer[0]                                          mWriteFrameStart             |                         |
443      *                                                                                   |              mBuffer[kSize]
444      *                                                                                 mWritePointer
445      */
446 
447     enum
448     {
449         kHeaderTotalLengthOffset = 0,
450         kHeaderSkipLengthOffset  = sizeof(uint16_t),
451         kHeaderSize              = sizeof(uint16_t) + sizeof(uint16_t),
452     };
453 
454     uint8_t  mBuffer[kSize];
455     uint8_t *mWriteFrameStart; // Pointer to start of current frame being written.
456 };
457 
458 /**
459  * This class implements the HDLC-lite encoder.
460  *
461  */
462 class Encoder
463 {
464 public:
465     /**
466      * This constructor initializes the object.
467      *
468      * @param[in] aWritePointer   The `FrameWritePointer` used by `Encoder` to write the encoded frames.
469      *
470      */
471     explicit Encoder(FrameWritePointer &aWritePointer);
472 
473     /**
474      * This method begins an HDLC frame.
475      *
476      * @retval OT_ERROR_NONE     Successfully started the HDLC frame.
477      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to start the HDLC frame.
478      *
479      */
480     otError BeginFrame(void);
481 
482     /**
483      * This method encodes a single byte into current frame.
484      *
485      * If there is no space to add the byte, the write pointer in frame buffer remains the same.
486      *
487      * @param[in]    aByte       A byte value to encode and add to frame.
488      *
489      * @retval OT_ERROR_NONE     Successfully encoded and added the byte to frame buffer.
490      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to encode and add the byte.
491      *
492      */
493     otError Encode(uint8_t aByte);
494 
495     /**
496      * This method encodes a given block of data into current frame.
497      *
498      * This method returns success only if there is space in buffer to encode the entire block of data. If there is no
499      * space to encode the entire block of data, the write pointer in frame buffer remains the same.
500      *
501      * @param[in]    aData       A pointer to a buffer containing the data to encode.
502      * @param[in]    aLength     The number of bytes in @p aData.
503      *
504      * @retval OT_ERROR_NONE     Successfully encoded and added the data to frame.
505      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to add the frame.
506      *
507      */
508     otError Encode(const uint8_t *aData, uint16_t aLength);
509 
510     /**
511      * This method ends/finalizes the HDLC frame.
512      *
513      * @retval OT_ERROR_NONE     Successfully ended the HDLC frame.
514      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to end the HDLC frame.
515      *
516      */
517     otError EndFrame(void);
518 
519 private:
520     FrameWritePointer &mWritePointer;
521     uint16_t           mFcs;
522 };
523 
524 /**
525  * This class implements the HDLC-lite decoder.
526  *
527  */
528 class Decoder
529 {
530 public:
531     /**
532      * This function pointer is called when either a complete frame has been decoded or an error occurs during
533      * decoding.
534      *
535      * The decoded frame (or the partially decoded frame in case of an error) is available in `aFrameWritePointer`
536      * buffer given in `Decoder` constructor.
537      *
538      * @param[in] aContext A pointer to arbitrary context information.
539      * @param[in] aError   OT_ERROR_NONE    if the frame was decoded successfully,
540      *                     OT_ERROR_PARSE   if the Frame Check Sequence (FCS) was incorrect in decoded frame,
541      *                     OT_ERROR_NO_BUFS insufficient buffer space available to save the decoded frame.
542      *
543      */
544     typedef void (*FrameHandler)(void *aContext, otError aError);
545 
546     /**
547      * This constructor initializes the decoder.
548      *
549      * @param[in] aFrameWritePointer   The `FrameWritePointer` used by `Decoder` to write the decoded frames.
550      * @param[in] aFrameHandler        The frame handler callback function pointer.
551      * @param[in] aContext             A pointer to arbitrary context information.
552      *
553      */
554     Decoder(FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext);
555 
556     /**
557      * This method feeds a block of data into the decoder.
558      *
559      * If during decoding, a full HDLC frame is successfully decoded or an error occurs, the `FrameHandler` callback
560      * is called. The decoded frame (or the partially decoded frame in case of an error) is available in
561      * `aFrameWritePointer` buffer from the constructor. The `Decoder` user (if required) must update/reset the write
562      * pointer from this callback for the next frame to be decoded.
563      *
564      * @param[in]  aData    A pointer to a buffer containing data to be fed to decoder.
565      * @param[in]  aLength  The number of bytes in @p aData.
566      *
567      */
568     void Decode(const uint8_t *aData, uint16_t aLength);
569 
570     /**
571      * This method resets internal states of the decoder.
572      *
573      */
574     void Reset(void);
575 
576 private:
577     enum State
578     {
579         kStateNoSync,
580         kStateSync,
581         kStateEscaped,
582     };
583 
584     State              mState;
585     FrameWritePointer &mWritePointer;
586     FrameHandler       mFrameHandler;
587     void *             mContext;
588     uint16_t           mFcs;
589     uint16_t           mDecodedLength;
590 };
591 
592 } // namespace Hdlc
593 } // namespace ot
594 
595 #endif // HDLC_HPP_
596