blob: 811ffa75612e55036a983caed9d07b512b1c2c28 [file] [log] [blame]
// Copyright 2020 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_OT_STACK_SRC_APP_H_
#define SRC_CONNECTIVITY_OPENTHREAD_OT_STACK_SRC_APP_H_
#include <fuchsia/lowpan/spinel/llcpp/fidl.h>
#include <fuchsia/openthread/devmgr/llcpp/fidl.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/ot-stack/ot-stack-callback.h>
#include <lib/svc/outgoing.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/port.h>
#include <list>
#include <thread>
#include <fbl/mutex.h>
#include <fbl/unique_fd.h>
#include "bootstrap_fidl_impl.h"
#include "ncp_fidl.h"
namespace otstack {
namespace fidl_spinel = fuchsia_lowpan_spinel;
constexpr uint32_t kOutboundAllowanceInit = 4;
constexpr uint32_t kOutboundAllowanceInc = 2;
constexpr uint32_t kInboundAllowanceInit = 4;
constexpr uint32_t kInboundAllowanceInc = 2;
constexpr uint32_t kMaxFrameSize = 1300;
enum {
kPortRadioChannelRead = 1,
kPortSendClientEvent,
kPortTerminate,
};
class OtStackApp : public fidl::WireSyncEventHandler<fidl_spinel::Device> {
public:
OtStackApp() = default;
zx_status_t Init(const std::string& path, bool is_test_env);
async::Loop* loop() { return &loop_; }
void EventLoopHandleInboundFrame(::fidl::VectorView<uint8_t> data);
void HandleRadioOnReadyForSendFrame(uint32_t allowance);
void HandleClientReadyToReceiveFrames(uint32_t allowance);
void PushFrameToOtLib();
private:
zx_status_t InitOutgoingAndServe();
zx_status_t SetupFidlService();
zx_status_t SetupBootstrapFidlService();
zx_status_t ConnectToOtRadioDev();
zx_status_t SetDeviceSetupClientInDevmgr(const std::string& path);
zx_status_t SetDeviceSetupClientInIsolatedDevmgr(const std::string& path);
zx_status_t SetupOtRadioDev();
zx_status_t InitRadioDriver();
void InitOpenThreadLibrary(bool reset_rcp);
// Events.
void OnReadyForSendFrames(
fidl::WireResponse<fidl_spinel::Device::OnReadyForSendFrames>* event) override;
void OnReceiveFrame(fidl::WireResponse<fidl_spinel::Device::OnReceiveFrame>* event) override;
void OnError(fidl::WireResponse<fidl_spinel::Device::OnError>* event) override;
zx_status_t Unknown() override;
void ClientAllowanceInit();
void RadioAllowanceInit();
void UpdateRadioOutboundAllowance();
void UpdateRadioInboundAllowance();
void UpdateClientOutboundAllowance();
void UpdateClientInboundAllowance();
void SendOneFrameToClient();
void AlarmTask();
void EventThread();
void TerminateEventThread();
void DisconnectDevice();
void Shutdown();
class LowpanSpinelDeviceFidlImpl : public fidl::WireInterface<fidl_spinel::Device> {
public:
explicit LowpanSpinelDeviceFidlImpl(OtStackApp& ot_stack_app);
private:
// FIDL request handlers
void Open(OpenCompleter::Sync& completer) override;
void Close(CloseCompleter::Sync& completer) override;
void GetMaxFrameSize(GetMaxFrameSizeCompleter::Sync& completer) override;
void SendFrame(::fidl::VectorView<uint8_t> data, SendFrameCompleter::Sync& completer) override;
void ReadyToReceiveFrames(uint32_t number_of_frames,
ReadyToReceiveFramesCompleter::Sync& completer) override;
OtStackApp& app_;
};
class OtStackCallBackImpl : public OtStackCallBack {
public:
explicit OtStackCallBackImpl(OtStackApp& ot_stack_app);
~OtStackCallBackImpl() override = default;
void SendOneFrameToRadio(uint8_t* buffer, uint32_t size) override;
std::vector<uint8_t> WaitForFrameFromRadio(uint64_t timeout_us) override;
std::vector<uint8_t> Process() override;
void SendOneFrameToClient(uint8_t* buffer, uint32_t size) override;
void PostNcpFidlInboundTask() override;
void PostOtLibTaskletProcessTask() override;
void PostDelayedAlarmTask(zx::duration delay) override;
private:
OtStackApp& app_;
};
async::Loop loop_{&kAsyncLoopConfigAttachToCurrentThread};
std::unique_ptr<ot::Fuchsia::BootstrapThreadImpl> bootstrap_impl_;
zx::port port_;
std::thread event_thread_;
std::optional<fidl::ServerBindingRef<fidl_spinel::Device>> binding_;
std::unique_ptr<LowpanSpinelDeviceFidlImpl> fidl_request_handler_ptr_;
std::string device_path_;
bool connected_to_device_ = false;
std::unique_ptr<fidl::WireSyncClient<fidl_spinel::DeviceSetup>> device_setup_client_ptr_ =
nullptr;
std::unique_ptr<fidl::WireSyncClient<fidl_spinel::Device>> device_client_ptr_ = nullptr;
zx::unowned_channel device_channel_ = zx::unowned_channel(ZX_HANDLE_INVALID);
std::unique_ptr<svc::Outgoing> outgoing_ = nullptr;
sync_completion_t radio_rx_complete_;
std::unique_ptr<OtStackCallBackImpl> lowpan_spinel_ptr_ = nullptr;
uint32_t radio_inbound_allowance_ = 0;
uint32_t radio_inbound_cnt = 0;
uint32_t radio_outbound_allowance_ = 0;
uint32_t radio_outbound_cnt = 0;
uint32_t client_inbound_allowance_ = 0;
uint32_t client_inbound_cnt = 0;
uint32_t client_outbound_allowance_ = 0;
uint32_t client_outbound_cnt = 0;
fbl::Mutex radio_q_mtx_;
std::list<std::vector<uint8_t>> radio_inbound_queue_ __TA_GUARDED(radio_q_mtx_);
std::list<std::vector<uint8_t>> client_outbound_queue_;
std::list<std::vector<uint8_t>> client_inbound_queue_;
std::optional<void*> ot_instance_ptr_ = nullptr;
bool is_test_env_;
zx_status_t handler_status_ = ZX_OK;
};
} // namespace otstack
#endif // SRC_CONNECTIVITY_OPENTHREAD_OT_STACK_SRC_APP_H_