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 "lib/spinel/multi_frame_buffer.hpp"
43 
44 namespace ot {
45 
46 /**
47  * @namespace ot::Hdlc
48  *
49  * @brief
50  *   This namespace includes definitions for the HDLC-lite encoder and decoder.
51  *
52  */
53 namespace Hdlc {
54 
55 /**
56  * Implements the HDLC-lite encoder.
57  *
58  */
59 class Encoder
60 {
61 public:
62     /**
63      * Initializes the object.
64      *
65      * @param[in] aWritePointer   The `FrameWritePointer` used by `Encoder` to write the encoded frames.
66      *
67      */
68     explicit Encoder(Spinel::FrameWritePointer &aWritePointer);
69 
70     /**
71      * Begins an HDLC frame.
72      *
73      * @retval OT_ERROR_NONE     Successfully started the HDLC frame.
74      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to start the HDLC frame.
75      *
76      */
77     otError BeginFrame(void);
78 
79     /**
80      * Encodes a single byte into current frame.
81      *
82      * If there is no space to add the byte, the write pointer in frame buffer remains the same.
83      *
84      * @param[in]    aByte       A byte value to encode and add to frame.
85      *
86      * @retval OT_ERROR_NONE     Successfully encoded and added the byte to frame buffer.
87      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to encode and add the byte.
88      *
89      */
90     otError Encode(uint8_t aByte);
91 
92     /**
93      * Encodes a given block of data into current frame.
94      *
95      * Returns success only if there is space in buffer to encode the entire block of data. If there is no
96      * space to encode the entire block of data, the write pointer in frame buffer remains the same.
97      *
98      * @param[in]    aData       A pointer to a buffer containing the data to encode.
99      * @param[in]    aLength     The number of bytes in @p aData.
100      *
101      * @retval OT_ERROR_NONE     Successfully encoded and added the data to frame.
102      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to add the frame.
103      *
104      */
105     otError Encode(const uint8_t *aData, uint16_t aLength);
106 
107     /**
108      * Ends/finalizes the HDLC frame.
109      *
110      * @retval OT_ERROR_NONE     Successfully ended the HDLC frame.
111      * @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to end the HDLC frame.
112      *
113      */
114     otError EndFrame(void);
115 
116 private:
117     Spinel::FrameWritePointer &mWritePointer;
118     uint16_t                   mFcs;
119 };
120 
121 /**
122  * Implements the HDLC-lite decoder.
123  *
124  */
125 class Decoder
126 {
127 public:
128     /**
129      * Pointer is called when either a complete frame has been decoded or an error occurs during
130      * decoding.
131      *
132      * The decoded frame (or the partially decoded frame in case of an error) is available in `aFrameWritePointer`
133      * buffer given in `Decoder` constructor.
134      *
135      * @param[in] aContext A pointer to arbitrary context information.
136      * @param[in] aError   OT_ERROR_NONE    if the frame was decoded successfully,
137      *                     OT_ERROR_PARSE   if the Frame Check Sequence (FCS) was incorrect in decoded frame,
138      *                     OT_ERROR_NO_BUFS insufficient buffer space available to save the decoded frame.
139      *
140      */
141     typedef void (*FrameHandler)(void *aContext, otError aError);
142 
143     /**
144      * Initializes the object.
145      *
146      */
147     Decoder(void);
148 
149     /**
150      * Initializes the decoder.
151      *
152      * @param[in] aFrameWritePointer   The `FrameWritePointer` used by `Decoder` to write the decoded frames.
153      * @param[in] aFrameHandler        The frame handler callback function pointer.
154      * @param[in] aContext             A pointer to arbitrary context information.
155      *
156      */
157     void Init(Spinel::FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext);
158 
159     /**
160      * Feeds a block of data into the decoder.
161      *
162      * If during decoding, a full HDLC frame is successfully decoded or an error occurs, the `FrameHandler` callback
163      * is called. The decoded frame (or the partially decoded frame in case of an error) is available in
164      * `aFrameWritePointer` buffer from the constructor. The `Decoder` user (if required) must update/reset the write
165      * pointer from this callback for the next frame to be decoded.
166      *
167      * @param[in]  aData    A pointer to a buffer containing data to be fed to decoder.
168      * @param[in]  aLength  The number of bytes in @p aData.
169      *
170      */
171     void Decode(const uint8_t *aData, uint16_t aLength);
172 
173     /**
174      * Resets internal states of the decoder.
175      *
176      */
177     void Reset(void);
178 
179 private:
180     enum State
181     {
182         kStateNoSync,
183         kStateSync,
184         kStateEscaped,
185     };
186 
187     State                      mState;
188     Spinel::FrameWritePointer *mWritePointer;
189     FrameHandler               mFrameHandler;
190     void                      *mContext;
191     uint16_t                   mFcs;
192     uint16_t                   mDecodedLength;
193 };
194 
195 } // namespace Hdlc
196 } // namespace ot
197 
198 #endif // HDLC_HPP_
199