| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_OPENTHREAD_DRIVERS_OT_RADIO_OT_RADIO_H_ |
| #define SRC_CONNECTIVITY_OPENTHREAD_DRIVERS_OT_RADIO_OT_RADIO_H_ |
| |
| #ifndef _ALL_SOURCE |
| #define _ALL_SOURCE // Enables thrd_create_with_name in <threads.h>. |
| #endif |
| #include <fuchsia/hardware/gpio/cpp/banjo.h> |
| #include <fuchsia/hardware/spi/cpp/banjo.h> |
| #include <fuchsia/lowpan/spinel/llcpp/fidl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/ddk/device.h> |
| #include <lib/sync/completion.h> |
| #include <lib/zx/interrupt.h> |
| #include <threads.h> |
| #include <zircon/compiler.h> |
| #include <zircon/types.h> |
| |
| #include <array> |
| #include <atomic> |
| #include <vector> |
| |
| #include <ddktl/device.h> |
| #include <fbl/mutex.h> |
| |
| #include "spinel_framer.h" |
| |
| enum { |
| OT_RADIO_INT_PIN, |
| OT_RADIO_RESET_PIN, |
| OT_RADIO_BOOTLOADER_PIN, |
| OT_RADIO_PIN_COUNT, |
| }; |
| |
| typedef enum { |
| OT_SPINEL_DEVICE_ON, |
| OT_SPINEL_DEVICE_OFF, |
| } ot_radio_power_status_e; |
| |
| namespace ot { |
| constexpr uint32_t kOutboundAllowanceInit = 4; |
| constexpr uint32_t kOutboundAllowanceInc = 2; |
| constexpr uint32_t kMaxFrameSize = 2048; |
| constexpr uint8_t kGetNcpVersionTID = 0xc; // 4 bit TID for GetNCP version spinel cmd |
| // chosen arbitrarily |
| constexpr int kGetNcpVersionMaxRetries = 5; |
| |
| enum { |
| PORT_KEY_RADIO_IRQ, |
| PORT_KEY_TX_TO_APP, |
| PORT_KEY_RX_FROM_APP, |
| PORT_KEY_TX_TO_RADIO, |
| PORT_KEY_EXIT_THREAD, |
| }; |
| |
| #ifdef INTERNAL_ACCESS |
| // Function defind in a generated source file |
| // generated by parsing firmware to return new firmware version |
| std::string GetNewFirmwareVersion(); |
| #endif |
| |
| class OtRadioDevice : public ddk::Device<OtRadioDevice, ddk::Unbindable, ddk::Messageable>, |
| public fidl::WireInterface<fuchsia_lowpan_spinel::DeviceSetup> { |
| public: |
| explicit OtRadioDevice(zx_device_t* device); |
| |
| static constexpr size_t spi_tx_rx_buffer_size = 2048; |
| static zx_status_t Create(void* ctx, zx_device_t* parent, std::unique_ptr<OtRadioDevice>* out); |
| static zx_status_t CreateBindAndStart(void* ctx, zx_device_t* parent); |
| zx_status_t CreateAndBindPortToIntr(); |
| zx_status_t Bind(); |
| zx_status_t Start(); |
| void StartRadioThread(); |
| static bool RunUnitTests(void* ctx, zx_device_t* parent, zx_handle_t channel); |
| zx_status_t Init(); |
| |
| void DdkRelease(); |
| void DdkUnbind(ddk::UnbindTxn txn); |
| zx_status_t DdkMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn); |
| zx_status_t ShutDown(); |
| void RemoveDevice(); |
| void FreeDevice(); |
| zx_status_t AssertResetPin(); |
| zx_status_t Reset(); |
| zx_status_t GetNCPVersion(); |
| zx_status_t DriverUnitTestGetNCPVersion(); |
| zx_status_t DriverUnitTestGetResetEvent(); |
| |
| zx::port port_; |
| zx::interrupt interrupt_; |
| ddk::SpiProtocolClient spi_; |
| sync_completion_t spi_rx_complete_; |
| |
| uint8_t spi_rx_buffer_[kMaxFrameSize]; |
| |
| std::array<ddk::GpioProtocolClient, OT_RADIO_PIN_COUNT> gpio_; |
| |
| private: |
| zx_status_t RadioThread(); |
| zx_status_t StartLoopThread(); |
| void StopLoopThread(); |
| void StopRadioThread(); |
| zx_status_t ReadRadioPacket(); |
| zx_status_t HandleRadioRxFrame(uint8_t* frameBuffer, uint16_t length); |
| zx_status_t RadioPacketTx(uint8_t* frameBuffer, uint16_t length); |
| zx_status_t InvokeInterruptHandler(); |
| bool IsInterruptAsserted(); |
| #ifdef INTERNAL_ACCESS |
| zx_status_t CheckFWUpdateRequired(bool* update_fw); |
| #endif |
| |
| // Status indicators set in Start function which are later used by |
| // ShutDown to determine what was running to shut down |
| struct ThrdStatus { |
| bool radio_thrd_running; |
| bool loop_thrd_running; |
| } thrd_status_ = {false, false}; |
| |
| // FIDL request handlers |
| void SetChannel(fidl::ServerEnd<fuchsia_lowpan_spinel::Device> request, |
| SetChannelCompleter::Sync& _completer) override; |
| |
| thrd_t thread_; |
| async::Loop loop_; |
| std::unique_ptr<ot::SpinelFramer> spinel_framer_; |
| |
| uint16_t spi_rx_buffer_len_ = 0; |
| uint16_t spi_tx_buffer_len_ = 0; |
| uint8_t spi_tx_buffer_[kMaxFrameSize]; |
| |
| class LowpanSpinelDeviceFidlImpl : public fidl::WireInterface<fuchsia_lowpan_spinel::Device> { |
| public: |
| LowpanSpinelDeviceFidlImpl(OtRadioDevice& ot_radio); |
| void Bind(async_dispatcher_t* dispatcher, |
| fidl::ServerEnd<fuchsia_lowpan_spinel::Device> channel); |
| |
| private: |
| // FIDL request handlers |
| void Open(OpenCompleter::Sync& completer); |
| void Close(CloseCompleter::Sync& completer); |
| void GetMaxFrameSize(GetMaxFrameSizeCompleter::Sync& completer); |
| void SendFrame(::fidl::VectorView<uint8_t> data, SendFrameCompleter::Sync& completer); |
| void ReadyToReceiveFrames(uint32_t number_of_frames, |
| ReadyToReceiveFramesCompleter::Sync& completer); |
| |
| OtRadioDevice& ot_radio_obj_; |
| }; |
| |
| uint32_t inbound_allowance_ = 0; |
| uint32_t outbound_allowance_ = kOutboundAllowanceInit; |
| uint64_t inbound_cnt_ = 0; |
| uint64_t outbound_cnt_ = 0; |
| std::optional<fidl::ServerBindingRef<fuchsia_lowpan_spinel::Device>> fidl_binding_; |
| std::unique_ptr<LowpanSpinelDeviceFidlImpl> fidl_impl_obj_ = 0; |
| ot_radio_power_status_e power_status_ = OT_SPINEL_DEVICE_OFF; |
| bool interrupt_is_asserted_ = false; |
| }; |
| |
| } // namespace ot |
| |
| #endif // SRC_CONNECTIVITY_OPENTHREAD_DRIVERS_OT_RADIO_OT_RADIO_H_ |