• 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 contains definitions for a SPI interface to the OpenThread stack.
31  */
32 
33 #ifndef NCP_SPI_HPP_
34 #define NCP_SPI_HPP_
35 
36 #include "openthread-core-config.h"
37 
38 #include "ncp/ncp_base.hpp"
39 
40 /*
41  *   SPI Framing Protocol
42  *
43  *   Each SPI frame starts with a 5-byte frame header:
44  *
45  *                  +---------+-----+----------+----------+
46  *                  | Octets: |  1  |    2     |    2     |
47  *                  +---------+-----+----------+----------+
48  *                  | Fields: | HDR | RECV_LEN | DATA_LEN |
49  *                  +---------+-----+----------+----------+
50  *
51  *   -  "HDR": The first byte is the header byte (defined below)
52  *   -  "RECV_LEN": The second and third bytes indicate the largest frame
53  *      size that that device is ready to receive.  If zero, then the
54  *      other device must not send any data. (Little endian)
55  *   -  "DATA_LEN": The fourth and fifth bytes indicate the size of the
56  *      pending data frame to be sent to the other device.  If this value
57  *      is equal-to or less-than the number of bytes that the other device
58  *      is willing to receive, then the data of the frame is immediately
59  *      after the header. (Little Endian)
60  *
61  *   The "HDR" byte is defined as:
62  *
63  *                       0   1   2   3   4   5   6   7
64  *                     +---+---+---+---+---+---+---+---+
65  *                     |RST|CRC|CCF|  RESERVED |PATTERN|
66  *                     +---+---+---+---+---+---+---+---+
67  *
68  *   -  "RST": This bit is set when that device has been reset since the
69  *      last time `CS` (chip select) was asserted.
70  *   -  "CRC": This bit is set when that device supports writing a 16-bit
71  *      CRC at the end of the data.  The CRC length is NOT included in
72  *      DATA_LEN.
73  *   -  "CCF": "CRC Check Failure".  Set if the CRC check on the last
74  *      received frame failed, cleared to zero otherwise.  This bit is
75  *      only used if both sides support CRC.
76  *   -  "RESERVED": These bits are all reserved for future used.  They
77  *      MUST be cleared to zero and MUST be ignored if set.
78  *   -  "PATTERN": These bits are set to a fixed value to help distinguish
79  *      valid SPI frames from garbage (by explicitly making "0xFF" and
80  *      "0x00" invalid values).  Bit 6 MUST be set to be one and bit 7
81  *      MUST be cleared (0).  A frame received that has any other values
82  *      for these bits MUST be dropped.
83  *
84  *   Prior to a sending or receiving a frame, the master MAY send a
85  *   5-octet frame with zeros for both the max receive frame size and the
86  *   the contained frame length.  This will induce the slave device to
87  *   indicate the length of the frame it wants to send (if any) and
88  *   indicate the largest frame it is capable of receiving at the moment.
89  *   This allows the master to calculate the size of the next transaction.
90  *   Alternatively, if the master has a frame to send it can just go ahead
91  *   and send a frame of that length and determine if the frame was
92  *   accepted by checking that the "RECV_LEN" from the slave frame is
93  *   larger than the frame the master just tried to send.  If the
94  *   "RECV_LEN" is smaller then the frame wasn't accepted and will need to
95  *   be transmitted again.
96  *
97  *   This protocol can be used either unidirectionally or bidirectionally,
98  *   determined by the behavior of the master and the slave.
99  *
100  *   If the the master notices "PATTERN" is not set correctly, the master
101  *   should consider the transaction to have failed and try again after 10
102  *   milliseconds, retrying up to 200 times.  After unsuccessfully trying
103  *   200 times in a row, the master MAY take appropriate remedial action
104  *   (like a NCP hardware reset, or indicating a communication failure to
105  *   a user interface).
106  *
107  *   At the end of the data of a frame is an optional 16-bit CRC, support
108  *   for which is indicated by the "CRC" bit of the "HDR" byte being set.
109  *   If these bits are set for both the master and slave frames, then CRC
110  *   checking is enabled on both sides, effectively requiring that frame
111  *   sizes be two bytes longer than would be otherwise required.  The CRC
112  *   is calculated using the same mechanism used for the CRC calculation
113  *   in HDLC-Lite (See Appendix A.1.2).  When both of the "CRC" bits are
114  *   set, both sides must verify that the "CRC" is valid before accepting
115  *   the frame.  If not enough bytes were clocked out for the CRC to be
116  *   read, then the frame must be ignored.  If enough bytes were clocked
117  *   out to perform a CRC check, but the CRC check fails, then the frame
118  *   must be rejected and the "CRC_FAIL" bit on the next frame (and ONLY
119  *   the next frame) MUST be set.
120  */
121 
122 namespace ot {
123 namespace Ncp {
124 
125 /**
126  * This class defines a SPI frame.
127  *
128  */
129 class SpiFrame
130 {
131 public:
132     enum
133     {
134         kHeaderSize = 5, ///< SPI header size (in bytes).
135     };
136 
137     /**
138      * This constructor initializes an `SpiFrame` instance.
139      *
140      * @param[in] aBuffer     Pointer to buffer containing the frame.
141      *
142      */
SpiFrame(uint8_t * aBuffer)143     explicit SpiFrame(uint8_t *aBuffer)
144         : mBuffer(aBuffer)
145     {
146     }
147 
148     /**
149      * This method gets a pointer to data portion in the SPI frame skipping the header.
150      *
151      * @returns  A pointer to data in the SPI frame.
152      *
153      */
GetData(void)154     uint8_t *GetData(void) { return mBuffer + kHeaderSize; }
155 
156     /**
157      * This method indicates whether or not the frame is valid.
158      *
159      * In a valid frame the flag byte should contain the pattern bits.
160      *
161      * @returns TRUE if the frame is valid, FALSE otherwise.
162      *
163      */
IsValid(void) const164     bool IsValid(void) const { return ((mBuffer[kIndexFlagByte] & kFlagPatternMask) == kFlagPattern); }
165 
166     /**
167      * This method indicates whether or not the "RST" bit is set.
168      *
169      * @returns TRUE if the "RST" bit is set, FALSE otherwise.
170      *
171      */
IsResetFlagSet(void) const172     bool IsResetFlagSet(void) const { return ((mBuffer[kIndexFlagByte] & kFlagReset) == kFlagReset); }
173 
174     /**
175      * This method sets the "flag byte" field in the SPI frame header.
176      *
177      * @param[in] aResetFlag     The status of reset flag (TRUE to set the flag, FALSE to clear flag).
178      *
179      */
SetHeaderFlagByte(bool aResetFlag)180     void SetHeaderFlagByte(bool aResetFlag) { mBuffer[kIndexFlagByte] = kFlagPattern | (aResetFlag ? kFlagReset : 0); }
181 
182     /**
183      * This method gets the "flag byte" field in the SPI frame header.
184      *
185      * @returns  The flag byte.
186      *
187      */
GetHeaderFlagByte(void) const188     uint8_t GetHeaderFlagByte(void) const { return mBuffer[kIndexFlagByte]; }
189 
190     /**
191      * This method sets the "accept len" field in the SPI frame header.
192      *
193      * "accept len" specifies number of bytes the sender of the SPI frame can receive.
194      *
195      * @param[in] aAcceptLen    The accept length in bytes.
196      *
197      */
SetHeaderAcceptLen(uint16_t aAcceptLen)198     void SetHeaderAcceptLen(uint16_t aAcceptLen)
199     {
200         Encoding::LittleEndian::WriteUint16(aAcceptLen, mBuffer + kIndexAcceptLen);
201     }
202 
203     /**
204      * This method gets the "accept len" field in the SPI frame header.
205      *
206      * @returns  The accept length in bytes.
207      *
208      */
GetHeaderAcceptLen(void) const209     uint16_t GetHeaderAcceptLen(void) const { return Encoding::LittleEndian::ReadUint16(mBuffer + kIndexAcceptLen); }
210 
211     /**
212      * This method sets the "data len" field in the SPI frame header.
213      *
214      * "Data len" specifies number of data bytes in the transmitted SPI frame.
215      *
216      * @param[in] aDataLen    The data length in bytes.
217      *
218      */
SetHeaderDataLen(uint16_t aDataLen)219     void SetHeaderDataLen(uint16_t aDataLen) { Encoding::LittleEndian::WriteUint16(aDataLen, mBuffer + kIndexDataLen); }
220 
221     /**
222      * This method gets the "data len" field in the SPI frame header.
223      *
224      * @returns  The data length in bytes.
225      *
226      */
GetHeaderDataLen(void) const227     uint16_t GetHeaderDataLen(void) const { return Encoding::LittleEndian::ReadUint16(mBuffer + kIndexDataLen); }
228 
229 private:
230     enum
231     {
232         kIndexFlagByte  = 0, // flag byte  (uint8_t).
233         kIndexAcceptLen = 1, // accept len (uint16_t little-endian encoding).
234         kIndexDataLen   = 3, // data len   (uint16_t little-endian encoding).
235 
236         kFlagReset       = (1 << 7), // Flag byte RESET bit.
237         kFlagPattern     = 0x02,     // Flag byte PATTERN bits.
238         kFlagPatternMask = 0x03,     // Flag byte PATTERN mask.
239     };
240 
241     uint8_t *mBuffer;
242 };
243 
244 class NcpSpi : public NcpBase
245 {
246 public:
247     /**
248      * This constructor initializes the object.
249      *
250      * @param[in]  aInstance  A pointer to the OpenThread instance structure.
251      *
252      */
253     explicit NcpSpi(Instance *aInstance);
254 
255 private:
256     enum
257     {
258         /**
259          * SPI tx and rx buffer size (should fit a max length frame + SPI header).
260          *
261          */
262         kSpiBufferSize = OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE,
263 
264         /**
265          * Size of the SPI header (in bytes).
266          *
267          */
268         kSpiHeaderSize = SpiFrame::kHeaderSize,
269     };
270 
271     enum TxState
272     {
273         kTxStateIdle,            // No frame to send.
274         kTxStateSending,         // A frame is ready to be sent.
275         kTxStateHandlingSendDone // The frame was sent successfully, waiting to prepare the next one (if any).
276     };
277 
278     typedef uint8_t LargeFrameBuffer[kSpiBufferSize];
279     typedef uint8_t EmptyFrameBuffer[kSpiHeaderSize];
280 
281     static bool SpiTransactionComplete(void *   aContext,
282                                        uint8_t *aOutputBuf,
283                                        uint16_t aOutputLen,
284                                        uint8_t *aInputBuf,
285                                        uint16_t aInputLen,
286                                        uint16_t aTransLen);
287     bool        SpiTransactionComplete(uint8_t *aOutputBuf,
288                                        uint16_t aOutputLen,
289                                        uint8_t *aInputBuf,
290                                        uint16_t aInputLen,
291                                        uint16_t aTransLen);
292 
293     static void SpiTransactionProcess(void *aContext);
294     void        SpiTransactionProcess(void);
295 
296     static void HandleFrameAddedToTxBuffer(void *                   aContext,
297                                            Spinel::Buffer::FrameTag aFrameTag,
298                                            Spinel::Buffer::Priority aPriority,
299                                            Spinel::Buffer *         aBuffer);
300 
301     static void PrepareTxFrame(Tasklet &aTasklet);
302     void        PrepareTxFrame(void);
303     void        HandleRxFrame(void);
304     void        PrepareNextSpiSendFrame(void);
305 
306     volatile TxState mTxState;
307     volatile bool    mHandlingRxFrame;
308     volatile bool    mResetFlag;
309 
310     Tasklet mPrepareTxFrameTask;
311 
312     uint16_t         mSendFrameLength;
313     LargeFrameBuffer mSendFrame;
314     EmptyFrameBuffer mEmptySendFrameFullAccept;
315     EmptyFrameBuffer mEmptySendFrameZeroAccept;
316 
317     LargeFrameBuffer mReceiveFrame;
318     EmptyFrameBuffer mEmptyReceiveFrame;
319 };
320 
321 } // namespace Ncp
322 } // namespace ot
323 
324 #endif // NCP_SPI_HPP_
325