1 /* 2 * Copyright (c) 2023, 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 of the SPI frame. 31 */ 32 33 #ifndef SPINEL_SPI_FRAME_HPP_ 34 #define SPINEL_SPI_FRAME_HPP_ 35 36 #include <stdint.h> 37 38 #include "lib/utils/endian.hpp" 39 40 namespace ot { 41 namespace Spinel { 42 43 /* 44 * SPI Framing Protocol 45 * 46 * Each SPI frame starts with a 5-byte frame header: 47 * 48 * +---------+-----+----------+----------+ 49 * | Octets: | 1 | 2 | 2 | 50 * +---------+-----+----------+----------+ 51 * | Fields: | HDR | RECV_LEN | DATA_LEN | 52 * +---------+-----+----------+----------+ 53 * 54 * - "HDR": The first byte is the header byte (defined below) 55 * - "RECV_LEN": The second and third bytes indicate the largest frame 56 * size that that device is ready to receive. If zero, then the 57 * other device must not send any data. (Little endian) 58 * - "DATA_LEN": The fourth and fifth bytes indicate the size of the 59 * pending data frame to be sent to the other device. If this value 60 * is equal-to or less-than the number of bytes that the other device 61 * is willing to receive, then the data of the frame is immediately 62 * after the header. (Little Endian) 63 * 64 * The "HDR" byte is defined as: 65 * 66 * 0 1 2 3 4 5 6 7 67 * +---+---+---+---+---+---+---+---+ 68 * |RST|CRC|CCF| RESERVED |PATTERN| 69 * +---+---+---+---+---+---+---+---+ 70 * 71 * - "RST": This bit is set when that device has been reset since the 72 * last time `CS` (chip select) was asserted. 73 * - "CRC": This bit is set when that device supports writing a 16-bit 74 * CRC at the end of the data. The CRC length is NOT included in 75 * DATA_LEN. 76 * - "CCF": "CRC Check Failure". Set if the CRC check on the last 77 * received frame failed, cleared to zero otherwise. This bit is 78 * only used if both sides support CRC. 79 * - "RESERVED": These bits are all reserved for future used. They 80 * MUST be cleared to zero and MUST be ignored if set. 81 * - "PATTERN": These bits are set to a fixed value to help distinguish 82 * valid SPI frames from garbage (by explicitly making "0xFF" and 83 * "0x00" invalid values). Bit 6 MUST be set to be one and bit 7 84 * MUST be cleared (0). A frame received that has any other values 85 * for these bits MUST be dropped. 86 * 87 * Prior to a sending or receiving a frame, the master MAY send a 88 * 5-octet frame with zeros for both the max receive frame size and the 89 * the contained frame length. This will induce the slave device to 90 * indicate the length of the frame it wants to send (if any) and 91 * indicate the largest frame it is capable of receiving at the moment. 92 * This allows the master to calculate the size of the next transaction. 93 * Alternatively, if the master has a frame to send it can just go ahead 94 * and send a frame of that length and determine if the frame was 95 * accepted by checking that the "RECV_LEN" from the slave frame is 96 * larger than the frame the master just tried to send. If the 97 * "RECV_LEN" is smaller then the frame wasn't accepted and will need to 98 * be transmitted again. 99 * 100 * This protocol can be used either unidirectionally or bidirectionally, 101 * determined by the behavior of the master and the slave. 102 * 103 * If the the master notices "PATTERN" is not set correctly, the master 104 * should consider the transaction to have failed and try again after 10 105 * milliseconds, retrying up to 200 times. After unsuccessfully trying 106 * 200 times in a row, the master MAY take appropriate remedial action 107 * (like a NCP hardware reset, or indicating a communication failure to 108 * a user interface). 109 * 110 * At the end of the data of a frame is an optional 16-bit CRC, support 111 * for which is indicated by the "CRC" bit of the "HDR" byte being set. 112 * If these bits are set for both the master and slave frames, then CRC 113 * checking is enabled on both sides, effectively requiring that frame 114 * sizes be two bytes longer than would be otherwise required. The CRC 115 * is calculated using the same mechanism used for the CRC calculation 116 * in HDLC-Lite (See Appendix A.1.2). When both of the "CRC" bits are 117 * set, both sides must verify that the "CRC" is valid before accepting 118 * the frame. If not enough bytes were clocked out for the CRC to be 119 * read, then the frame must be ignored. If enough bytes were clocked 120 * out to perform a CRC check, but the CRC check fails, then the frame 121 * must be rejected and the "CRC_FAIL" bit on the next frame (and ONLY 122 * the next frame) MUST be set. 123 */ 124 125 /** 126 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 Lib::Utils::LittleEndian::WriteUint16(aAcceptLen, mBuffer + kIndexAcceptLen); 201 } 202 203 /** 204 * 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 Lib::Utils::LittleEndian::ReadUint16(mBuffer + kIndexAcceptLen); } 210 211 /** 212 * 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) 220 { 221 Lib::Utils::LittleEndian::WriteUint16(aDataLen, mBuffer + kIndexDataLen); 222 } 223 224 /** 225 * Gets the "data len" field in the SPI frame header. 226 * 227 * @returns The data length in bytes. 228 * 229 */ GetHeaderDataLen(void) const230 uint16_t GetHeaderDataLen(void) const { return Lib::Utils::LittleEndian::ReadUint16(mBuffer + kIndexDataLen); } 231 232 private: 233 enum 234 { 235 kIndexFlagByte = 0, // flag byte (uint8_t). 236 kIndexAcceptLen = 1, // accept len (uint16_t little-endian encoding). 237 kIndexDataLen = 3, // data len (uint16_t little-endian encoding). 238 239 kFlagReset = (1 << 7), // Flag byte RESET bit. 240 kFlagPattern = 0x02, // Flag byte PATTERN bits. 241 kFlagPatternMask = 0x03, // Flag byte PATTERN mask. 242 }; 243 244 uint8_t *mBuffer; 245 }; 246 247 } // namespace Spinel 248 } // namespace ot 249 #endif // SPINEL_SPI_FRAME_HPP_ 250