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