1 /* 2 * Copyright (c) 2021, The OpenThread Authors. 3 * Copyright (c) 2022-2024, NXP. 4 * 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holder nor the 15 * names of its contributors may be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef OT_SPINEL_HDLC_HPP_ 32 #define OT_SPINEL_HDLC_HPP_ 33 34 #include <zephyr/kernel.h> 35 #include <zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h> 36 37 #include "lib/url/url.hpp" 38 #include "lib/hdlc/hdlc.hpp" 39 #include "lib/spinel/spinel.h" 40 #include "lib/spinel/spinel_interface.hpp" 41 42 namespace ot { 43 44 namespace Hdlc { 45 46 typedef uint8_t HdlcSpinelContext; 47 48 /** 49 * This class defines an HDLC spinel interface to the Radio Co-processor (RCP). 50 * 51 */ 52 class HdlcInterface : public ot::Spinel::SpinelInterface 53 { 54 public: 55 /** 56 * This constructor initializes the object. 57 * 58 * @param[in] aRadioUrl Radio url 59 * 60 */ 61 HdlcInterface(const Url::Url &aRadioUrl); 62 63 /** 64 * This destructor deinitializes the object. 65 * 66 */ 67 virtual ~HdlcInterface(void); 68 69 /** 70 * This method initializes the HDLC interface. 71 * 72 */ 73 otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer); 74 75 /** 76 * This method deinitializes the HDLC interface. 77 * 78 */ 79 void Deinit(void); 80 81 /** 82 * This method performs radio driver processing. 83 * 84 * @param[in] aInstance The ot instance 85 * 86 */ 87 void Process(const void *aInstance); 88 89 /** 90 * This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. 91 * 92 * This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for 93 * up to `kMaxWaitTime` interval. 94 * 95 * @param[in] aFrame A pointer to buffer containing the spinel frame to send. 96 * @param[in] aLength The length (number of bytes) in the frame. 97 * 98 * @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame. 99 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame. 100 * @retval OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`. 101 * 102 */ 103 otError SendFrame(const uint8_t *aFrame, uint16_t aLength); 104 105 /** 106 * This method waits for receiving part or all of spinel frame within specified timeout. 107 * 108 * @param[in] aTimeoutUs The timeout value in microseconds. 109 * 110 * @retval OT_ERROR_NONE Part or all of spinel frame is received. 111 * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeoutUs. 112 * 113 */ 114 otError WaitForFrame(uint64_t aTimeoutUs); 115 116 /** 117 * This method is called by the HDLC RX Callback when a HDLC message has been received 118 * 119 * It will decode and store the Spinel frames in a temporary Spinel frame buffer (mRxSpinelFrameBuffer) 120 * This buffer will be then copied to the OpenThread Spinel frame buffer, from the OpenThread task context 121 * 122 * @param[in] data A pointer to buffer containing the HDLC message to decode. 123 * @param[in] len The length (number of bytes) in the message. 124 */ 125 void ProcessRxData(uint8_t *data, uint16_t len); 126 127 /** 128 * This method is called when RCP failure detected and resets internal states of the interface. 129 * 130 */ 131 void OnRcpReset(void); 132 133 /** 134 * This method is called when RCP is reset to recreate the connection with it. 135 * Intentionally empty. 136 * 137 */ ResetConnection(void)138 otError ResetConnection(void) { return OT_ERROR_NONE; } 139 140 /** 141 * This method hardware resets the RCP. 142 * 143 * @retval OT_ERROR_NONE Successfully reset the RCP. 144 * @retval OT_ERROR_NOT_IMPLEMENTED The hardware reset is not implemented. 145 * 146 */ HardwareReset(void)147 otError HardwareReset(void) { return OT_ERROR_NOT_IMPLEMENTED; } 148 149 private: 150 151 enum 152 { 153 /* HDLC encoder buffer must be larger than the max spinel frame size to be able to handle the HDLC overhead 154 * As a host, a TX frame will always contain only 1 spinel frame + HDLC overhead 155 * Sizing the buffer for 2 spinel frames should be large enough to handle this */ 156 kEncoderBufferSize = SPINEL_FRAME_MAX_SIZE * 2, 157 kMaxMultiFrameSize = 2048, 158 k_spinel_hdlc_frame_ready_event = 1 << 0, 159 }; 160 161 ot::Spinel::FrameBuffer<kEncoderBufferSize> mEncoderBuffer; 162 ot::Hdlc::Encoder mHdlcEncoder; 163 hdlc_rx_callback_t hdlc_rx_callback; 164 ot::Spinel::SpinelInterface::RxFrameBuffer *mReceiveFrameBuffer; 165 ot::Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback; 166 void *mReceiveFrameContext; 167 ot::Spinel::MultiFrameBuffer<kMaxMultiFrameSize> mRxSpinelFrameBuffer; 168 ot::Hdlc::Decoder mHdlcSpinelDecoder; 169 bool mIsInitialized; 170 uint8_t *mSavedFrame; 171 uint16_t mSavedFrameLen; 172 bool mIsSpinelBufferFull; 173 const Url::Url &mRadioUrl; 174 175 /* Spinel HDLC interface */ 176 const struct device *radio_dev; 177 struct hdlc_api *hdlc_api; 178 179 struct k_event spinel_hdlc_event; 180 struct k_mutex spinel_hdlc_wr_lock; 181 struct k_mutex spinel_hdlc_rd_lock; 182 struct k_msgq spinel_hdlc_msgq; 183 char spinel_hdlc_msgq_buffer; 184 185 otError Write(const uint8_t *aFrame, uint16_t aLength); 186 uint32_t TryReadAndDecode(bool fullRead); 187 void HandleHdlcFrame(otError aError); 188 static void HandleHdlcFrame(void *aContext, otError aError); 189 static void HdlcRxCallback(uint8_t *data, uint16_t len, void *param); 190 GetRcpInterfaceMetrics(void) const191 const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return nullptr;} GetBusSpeed(void) const192 uint32_t GetBusSpeed(void) const { return 0; } UpdateFdSet(void * aMainloopContext)193 void UpdateFdSet(void *aMainloopContext) 194 { 195 (void)aMainloopContext; 196 } 197 198 protected: 199 virtual void HandleUnknownHdlcContent(uint8_t *buffer, uint16_t len); 200 }; 201 202 } // namespace Zephyr 203 204 } // namespace ot 205 206 #endif // OT_SPINEL_HDLC_HPP_ 207