From 2cdfde6637801a7b02e5bdbe140fd2e4331c9c4c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 8 Feb 2021 23:44:30 -0800 Subject: [PATCH] htc: add remaining worker receive thread logic --- .../source/htclow/ctrl/htclow_ctrl_packet.hpp | 2 +- .../ctrl/htclow_ctrl_packet_factory.cpp | 127 ++++++++++++++ .../ctrl/htclow_ctrl_packet_factory.hpp | 19 ++- .../htclow/ctrl/htclow_ctrl_send_buffer.cpp | 54 ++++++ .../htclow/ctrl/htclow_ctrl_send_buffer.hpp | 10 +- .../htclow/ctrl/htclow_ctrl_service.cpp | 160 +++++++++++++++++- .../htclow/ctrl/htclow_ctrl_service.hpp | 15 +- .../ctrl/htclow_ctrl_service_channels.hpp | 40 +++++ .../htclow/ctrl/htclow_ctrl_state_machine.cpp | 76 ++++++--- .../htclow/ctrl/htclow_ctrl_state_machine.hpp | 6 + .../vapours/results/htclow_results.hpp | 4 +- 11 files changed, 477 insertions(+), 36 deletions(-) create mode 100644 libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.cpp create mode 100644 libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.cpp create mode 100644 libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service_channels.hpp diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet.hpp index bb12eb3dd..0689920bf 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet.hpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet.hpp @@ -39,7 +39,7 @@ namespace ams::htclow::ctrl { struct HtcctrlPacketHeader { u32 signature; - u32 offset; + u32 sequence_id; u32 reserved; u32 body_size; s16 version; diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.cpp new file mode 100644 index 000000000..7c18ed574 --- /dev/null +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "htclow_ctrl_packet_factory.hpp" + +namespace ams::htclow::ctrl { + + std::unique_ptr HtcctrlPacketFactory::MakeSendPacketCommon(int body_size) { + /* Allocate memory for the packet. */ + if (void *buffer = m_allocator->Allocate(sizeof(HtcctrlPacket), alignof(HtcctrlPacket)); buffer != nullptr) { + /* Convert the buffer to a packet. */ + HtcctrlPacket *packet = static_cast(buffer); + + /* Construct the packet. */ + std::construct_at(packet, m_allocator, body_size + sizeof(HtcctrlPacketHeader)); + + /* Create the unique pointer. */ + std::unique_ptr ptr(packet, HtcctrlPacketDeleter{m_allocator}); + + /* Set packet header fields. */ + if (ptr && ptr->IsAllocationSucceeded()) { + HtcctrlPacketHeader *header = ptr->GetHeader(); + + header->signature = HtcctrlSignature; + header->sequence_id = m_sequence_id++; + header->reserved = 0; + header->body_size = body_size; + header->version = 1; + header->channel = {}; + header->share = 0; + } + + return ptr; + } else { + return std::unique_ptr(nullptr, HtcctrlPacketDeleter{m_allocator}); + } + } + + std::unique_ptr HtcctrlPacketFactory::MakeSuspendPacket() { + auto packet = this->MakeSendPacketCommon(0); + if (packet && packet->IsAllocationSucceeded()) { + packet->GetHeader()->packet_type = HtcctrlPacketType_SuspendFromTarget; + } + + return packet; + } + + std::unique_ptr HtcctrlPacketFactory::MakeResumePacket() { + auto packet = this->MakeSendPacketCommon(0); + if (packet && packet->IsAllocationSucceeded()) { + packet->GetHeader()->packet_type = HtcctrlPacketType_SuspendFromTarget; + } + + return packet; + } + + std::unique_ptr HtcctrlPacketFactory::MakeReadyPacket(const void *body, int body_size) { + auto packet = this->MakeSendPacketCommon(0); + if (packet && packet->IsAllocationSucceeded()) { + packet->GetHeader()->packet_type = HtcctrlPacketType_ReadyFromTarget; + + std::memcpy(packet->GetBody(), body, packet->GetBodySize()); + } + + return packet; + } + + std::unique_ptr HtcctrlPacketFactory::MakeInformationPacket(const void *body, int body_size) { + auto packet = this->MakeSendPacketCommon(0); + if (packet && packet->IsAllocationSucceeded()) { + packet->GetHeader()->packet_type = HtcctrlPacketType_InformationFromTarget; + + std::memcpy(packet->GetBody(), body, packet->GetBodySize()); + } + + return packet; + } + + std::unique_ptr HtcctrlPacketFactory::MakeDisconnectPacket() { + auto packet = this->MakeSendPacketCommon(0); + if (packet) { + packet->GetHeader()->packet_type = HtcctrlPacketType_DisconnectFromTarget; + } + + return packet; + } + + std::unique_ptr HtcctrlPacketFactory::MakeConnectPacket(const void *body, int body_size) { + auto packet = this->MakeSendPacketCommon(0); + if (packet && packet->IsAllocationSucceeded()) { + packet->GetHeader()->packet_type = HtcctrlPacketType_ConnectFromTarget; + + std::memcpy(packet->GetBody(), body, packet->GetBodySize()); + } + + return packet; + } + + std::unique_ptr HtcctrlPacketFactory::MakeBeaconResponsePacket(const void *body, int body_size) { + auto packet = this->MakeSendPacketCommon(0); + if (packet && packet->IsAllocationSucceeded()) { + packet->GetHeader()->packet_type = HtcctrlPacketType_BeaconResponse; + + std::memcpy(packet->GetBody(), body, packet->GetBodySize()); + } + + return packet; + } + + void HtcctrlPacketFactory::Delete(HtcctrlPacket *packet) { + HtcctrlPacketDeleter{m_allocator}(packet); + } + +} diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.hpp index 8670672d7..5ed6834d6 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.hpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.hpp @@ -15,26 +15,39 @@ */ #pragma once #include +#include "htclow_ctrl_packet.hpp" namespace ams::htclow::ctrl { class HtcctrlPacketFactory { private: mem::StandardAllocator *m_allocator; - u32 m_seed; + u32 m_sequence_id; public: HtcctrlPacketFactory(mem::StandardAllocator *allocator) : m_allocator(allocator) { /* Get the current time. */ const u64 time = os::GetSystemTick().GetInt64Value(); - /* Set the random seed. */ + /* Set a random sequence id. */ { util::TinyMT rng; rng.Initialize(reinterpret_cast(std::addressof(time)), sizeof(time) / sizeof(u32)); - m_seed = rng.GenerateRandomU32(); + m_sequence_id = rng.GenerateRandomU32(); } } + public: + std::unique_ptr MakeSuspendPacket(); + std::unique_ptr MakeResumePacket(); + std::unique_ptr MakeReadyPacket(const void *body, int body_size); + std::unique_ptr MakeInformationPacket(const void *body, int body_size); + std::unique_ptr MakeDisconnectPacket(); + std::unique_ptr MakeConnectPacket(const void *body, int body_size); + std::unique_ptr MakeBeaconResponsePacket(const void *body, int body_size); + + void Delete(HtcctrlPacket *packet); + private: + std::unique_ptr MakeSendPacketCommon(int body_size); }; } diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.cpp new file mode 100644 index 000000000..77de070c7 --- /dev/null +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "htclow_ctrl_send_buffer.hpp" + +namespace ams::htclow::ctrl { + + bool HtcctrlSendBuffer::IsPriorPacket(HtcctrlPacketType packet_type) const { + return packet_type == HtcctrlPacketType_DisconnectFromTarget; + } + + bool HtcctrlSendBuffer::IsPosteriorPacket(HtcctrlPacketType packet_type) const { + switch (packet_type) { + case HtcctrlPacketType_ConnectFromTarget: + case HtcctrlPacketType_ReadyFromTarget: + case HtcctrlPacketType_SuspendFromTarget: + case HtcctrlPacketType_ResumeFromTarget: + case HtcctrlPacketType_BeaconResponse: + case HtcctrlPacketType_InformationFromTarget: + default: + return false; + } + } + + void HtcctrlSendBuffer::AddPacket(std::unique_ptr ptr) { + /* Get the packet. */ + HtcctrlPacket *packet = ptr.release(); + + /* Get the packet type. */ + const auto packet_type = packet->GetHeader()->packet_type; + + /* Add the packet to the appropriate list. */ + if (this->IsPriorPacket(packet_type)) { + m_prior_packet_list.push_back(*packet); + } else { + AMS_ABORT_UNLESS(this->IsPosteriorPacket(packet_type)); + m_posterior_packet_list.push_back(*packet); + } + } + +} diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.hpp index abe1cf239..d5c8c4798 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.hpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.hpp @@ -26,9 +26,15 @@ namespace ams::htclow::ctrl { using PacketList = util::IntrusiveListBaseTraits::ListType; private: HtcctrlPacketFactory *m_packet_factory; - PacketList m_packet_list; + PacketList m_prior_packet_list; + PacketList m_posterior_packet_list; + private: + bool IsPriorPacket(HtcctrlPacketType packet_type) const; + bool IsPosteriorPacket(HtcctrlPacketType packet_type) const; public: - HtcctrlSendBuffer(HtcctrlPacketFactory *pf) : m_packet_factory(pf), m_packet_list() { /* ... */ } + HtcctrlSendBuffer(HtcctrlPacketFactory *pf) : m_packet_factory(pf), m_prior_packet_list(), m_posterior_packet_list() { /* ... */ } + + void AddPacket(std::unique_ptr ptr); }; } diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp index 55bb00d02..e1fd3b7cc 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp @@ -17,6 +17,9 @@ #include "htclow_ctrl_service.hpp" #include "htclow_ctrl_state.hpp" #include "htclow_ctrl_state_machine.hpp" +#include "htclow_ctrl_packet_factory.hpp" +#include "htclow_service_channel_parser.hpp" +#include "htclow_ctrl_service_channels.hpp" #include "../mux/htclow_mux.hpp" namespace ams::htclow::ctrl { @@ -38,7 +41,7 @@ namespace ams::htclow::ctrl { HtcctrlService::HtcctrlService(HtcctrlPacketFactory *pf, HtcctrlStateMachine *sm, mux::Mux *mux) : m_settings_holder(), m_beacon_response(), m_1100(), m_packet_factory(pf), m_state_machine(sm), m_mux(mux), m_event(os::EventClearMode_ManualClear), - m_send_buffer(pf), m_mutex(), m_condvar(), m_2170(), m_version(ProtocolVersion) + m_send_buffer(pf), m_mutex(), m_condvar(), m_service_channels_packet(), m_version(ProtocolVersion) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); @@ -110,8 +113,150 @@ namespace ams::htclow::ctrl { } Result HtcctrlService::ProcessReceivePacket(const HtcctrlPacketHeader &header, const void *body, size_t body_size) { - /* TODO */ - AMS_ABORT("HtcctrlService::ProcessReceivePacket"); + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + switch (header.packet_type) { + case HtcctrlPacketType_ConnectFromHost: + return this->ProcessReceiveConnectPacket(); + case HtcctrlPacketType_ReadyFromHost: + return this->ProcessReceiveReadyPacket(body, body_size); + case HtcctrlPacketType_SuspendFromHost: + return this->ProcessReceiveSuspendPacket(); + case HtcctrlPacketType_ResumeFromHost: + return this->ProcessReceiveResumePacket(); + case HtcctrlPacketType_DisconnectFromHost: + return this->ProcessReceiveDisconnectPacket(); + case HtcctrlPacketType_BeaconQuery: + return this->ProcessReceiveBeaconQueryPacket(); + default: + return this->ProcessReceiveUnexpectedPacket(); + } + } + + Result HtcctrlService::ProcessReceiveConnectPacket() { + /* Try to transition to sent connect state. */ + if (R_FAILED(this->SetState(HtcctrlState_SentConnectFromHost))) { + /* We couldn't transition to sent connect. */ + return this->ProcessReceiveUnexpectedPacket(); + } + + /* Send a connect packet. */ + m_send_buffer.AddPacket(m_packet_factory->MakeConnectPacket(m_beacon_response, util::Strnlen(m_beacon_response, sizeof(m_beacon_response)) + 1)); + + /* Signal our event. */ + m_event.Signal(); + + return ResultSuccess(); + } + + Result HtcctrlService::ProcessReceiveReadyPacket(const void *body, size_t body_size) { + /* Update our service channels. */ + this->UpdateServiceChannels(body, body_size); + + /* Check that our version is correct. */ + if (m_version < ProtocolVersion) { + return this->ProcessReceiveUnexpectedPacket(); + } + + /* Set our version. */ + m_version = ProtocolVersion; + m_mux->SetVersion(m_version); + + /* Set our state. */ + if (R_FAILED(this->SetState(HtcctrlState_SentReadyFromHost))) { + return this->ProcessReceiveUnexpectedPacket(); + } + + /* Ready ourselves. */ + this->TryReadyInternal(); + return ResultSuccess(); + } + + Result HtcctrlService::ProcessReceiveSuspendPacket() { + /* Try to set our state to enter sleep. */ + if (R_FAILED(this->SetState(HtcctrlState_EnterSleep))) { + /* We couldn't transition to sleep. */ + return this->ProcessReceiveUnexpectedPacket(); + } + + return ResultSuccess(); + } + + Result HtcctrlService::ProcessReceiveResumePacket() { + /* If our state is sent-resume, change to readied. */ + if (m_state_machine->GetHtcctrlState() != HtcctrlState_SentResumeFromTarget || R_FAILED(this->SetState(HtcctrlState_Ready))) { + /* We couldn't perform a valid resume transition. */ + return this->ProcessReceiveUnexpectedPacket(); + } + + return ResultSuccess(); + } + + Result HtcctrlService::ProcessReceiveDisconnectPacket() { + /* Set our state. */ + R_TRY(this->SetState(HtcctrlState_Disconnected)); + + return ResultSuccess(); + } + + Result HtcctrlService::ProcessReceiveBeaconQueryPacket() { + /* Send a beacon response packet. */ + m_send_buffer.AddPacket(m_packet_factory->MakeBeaconResponsePacket(m_beacon_response, util::Strnlen(m_beacon_response, sizeof(m_beacon_response)) + 1)); + + /* Signal our event. */ + m_event.Signal(); + + return ResultSuccess(); + } + + Result HtcctrlService::ProcessReceiveUnexpectedPacket() { + /* Set our state. */ + R_TRY(this->SetState(HtcctrlState_Error)); + + /* Send a disconnection packet. */ + m_send_buffer.AddPacket(m_packet_factory->MakeDisconnectPacket()); + + /* Signal our event. */ + m_event.Signal(); + + /* Return unexpected packet error. */ + return htclow::ResultHtcctrlReceiveUnexpectedPacket(); + } + + void HtcctrlService::UpdateServiceChannels(const void *body, size_t body_size) { + /* Copy the packet body to our member. */ + std::memcpy(m_service_channels_packet, body, body_size); + + /* Parse service channels. */ + impl::ChannelInternalType channels[10]; + int num_channels; + s16 version = m_version; + ctrl::ParseServiceChannel(std::addressof(version), channels, std::addressof(num_channels), util::size(channels), m_service_channels_packet, body_size); + + /* Update version. */ + m_version = version; + + /* Notify state machine of supported channels. */ + m_state_machine->NotifySupportedServiceChannels(channels, num_channels); + } + + void HtcctrlService::TryReadyInternal() { + /* If we can send ready, do so. */ + if (m_state_machine->IsPossibleToSendReady()) { + /* Print the channels. */ + char channel_str[0x100]; + this->PrintServiceChannels(channel_str, sizeof(channel_str)); + + /* Send a ready packet. */ + m_send_buffer.AddPacket(m_packet_factory->MakeReadyPacket(channel_str, util::Strnlen(channel_str, sizeof(channel_str)) + 1)); + + /* Signal our event. */ + m_event.Signal(); + + /* Set connecting checked in state machine. */ + m_state_machine->SetConnectingChecked(); + } } Result HtcctrlService::NotifyDriverConnected() { @@ -168,4 +313,13 @@ namespace ams::htclow::ctrl { m_condvar.Broadcast(); } + void HtcctrlService::PrintServiceChannels(char *dst, size_t dst_size) { + size_t ofs = 0; + ofs += util::SNPrintf(dst + ofs, dst_size - ofs, "{\r\n \"Chan\" : [\r\n \"%d:%d:%d\"", static_cast(ServiceChannels[0].module_id), ServiceChannels[0].reserved, static_cast(ServiceChannels[0].channel_id)); + for (size_t i = 1; i < util::size(ServiceChannels); ++i) { + ofs += util::SNPrintf(dst + ofs, dst_size - ofs, ",\r\n \"%d:%d:%d\"", static_cast(ServiceChannels[i].module_id), ServiceChannels[i].reserved, static_cast(ServiceChannels[i].channel_id)); + } + ofs += util::SNPrintf(dst + ofs, dst_size - ofs, "\r\n],\r\n \"Prot\" : %d\r\n}\r\n", ProtocolVersion); + } + } diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.hpp index b39fb6f41..b94dc58a8 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.hpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.hpp @@ -50,13 +50,26 @@ namespace ams::htclow::ctrl { HtcctrlSendBuffer m_send_buffer; os::SdkMutex m_mutex; os::SdkConditionVariable m_condvar; - u8 m_2170[0x1000]; + char m_service_channels_packet[0x1000]; s16 m_version; private: const char *GetConnectionType(impl::DriverType driver_type) const; void UpdateBeaconResponse(const char *connection); + Result ProcessReceiveConnectPacket(); + Result ProcessReceiveReadyPacket(const void *body, size_t body_size); + Result ProcessReceiveSuspendPacket(); + Result ProcessReceiveResumePacket(); + Result ProcessReceiveDisconnectPacket(); + Result ProcessReceiveBeaconQueryPacket(); + Result ProcessReceiveUnexpectedPacket(); + + void UpdateServiceChannels(const void *body, size_t body_size); + void TryReadyInternal(); + + void PrintServiceChannels(char *dst, size_t dst_size); + Result SetState(HtcctrlState state); void ReflectState(); public: diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service_channels.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service_channels.hpp new file mode 100644 index 000000000..bcaf32b9f --- /dev/null +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service_channels.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::htclow::ctrl { + + constexpr inline const impl::ChannelInternalType ServiceChannels[] = { + { + .channel_id = 0, + .module_id = static_cast(1), + }, + { + .channel_id = 1, + .module_id = static_cast(3), + }, + { + .channel_id = 2, + .module_id = static_cast(3), + }, + { + .channel_id = 0, + .module_id = static_cast(4), + }, + }; + +} diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp index c80bd784b..1836dbeeb 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp @@ -15,33 +15,10 @@ */ #include #include "htclow_ctrl_state_machine.hpp" +#include "htclow_ctrl_service_channels.hpp" namespace ams::htclow::ctrl { - namespace { - - /* TODO: Real module id names */ - constexpr const impl::ChannelInternalType ServiceChannels[] = { - { - .channel_id = 0, - .module_id = static_cast(1), - }, - { - .channel_id = 1, - .module_id = static_cast(3), - }, - { - .channel_id = 2, - .module_id = static_cast(3), - }, - { - .channel_id = 0, - .module_id = static_cast(4), - }, - }; - - } - HtcctrlStateMachine::HtcctrlStateMachine() : m_map(), m_state(HtcctrlState_DriverDisconnected), m_prev_state(HtcctrlState_DriverDisconnected), m_mutex() { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); @@ -67,7 +44,7 @@ namespace ams::htclow::ctrl { std::scoped_lock lk(m_mutex); /* Check that the transition is allowed. */ - R_UNLESS(ctrl::IsStateTransitionAllowed(m_state, state), htclow::ResultStateTransitionNotAllowed()); + R_UNLESS(ctrl::IsStateTransitionAllowed(m_state, state), htclow::ResultHtcctrlStateTransitionNotAllowed()); /* Get the state pre-transition. */ const auto old_state = m_state; @@ -149,6 +126,13 @@ namespace ams::htclow::ctrl { } } + bool HtcctrlStateMachine::IsPossibleToSendReady() { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + return m_state == HtcctrlState_SentReadyFromHost && this->AreServiceChannelsConnecting(); + } + bool HtcctrlStateMachine::IsUnsupportedServiceChannelToShutdown(const impl::ChannelInternalType &channel) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); @@ -175,4 +159,46 @@ namespace ams::htclow::ctrl { } } + void HtcctrlStateMachine::SetConnectingChecked() { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + for (auto &pair : m_map) { + pair.second.connect = ServiceChannelConnect_ConnectingChecked; + } + } + + void HtcctrlStateMachine::NotifySupportedServiceChannels(const impl::ChannelInternalType *channels, int num_channels) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + auto IsSupportedServiceChannel = [] ALWAYS_INLINE_LAMBDA (const impl::ChannelInternalType &channel, const impl::ChannelInternalType *supported, int num_supported) -> bool { + for (auto i = 0; i < num_supported; ++i) { + if (channel.module_id == supported[i].module_id && channel.channel_id == supported[i].channel_id) { + return true; + } + } + + return false; + }; + + for (auto &pair : m_map) { + if (IsSupportedServiceChannel(pair.first, channels, num_channels)) { + pair.second.support = ServiceChannelSupport_Suppported; + } else { + pair.second.support = ServiceChannelSupport_Unsupported; + } + } + } + + bool HtcctrlStateMachine::AreServiceChannelsConnecting() { + for (auto &pair : m_map) { + if (pair.second.connect != ServiceChannelConnect_Connecting) { + return false; + } + } + + return true; + } + } diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp index 6651eff6e..aed8d5068 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp @@ -64,13 +64,19 @@ namespace ams::htclow::ctrl { bool IsDisconnected(); bool IsSleeping(); + bool IsPossibleToSendReady(); bool IsUnsupportedServiceChannelToShutdown(const impl::ChannelInternalType &channel); bool IsConnectable(const impl::ChannelInternalType &channel); void SetNotConnecting(const impl::ChannelInternalType &channel); + void SetConnectingChecked(); + + void NotifySupportedServiceChannels(const impl::ChannelInternalType *channels, int num_channels); private: void SetStateWithoutCheckInternal(HtcctrlState state); + bool AreServiceChannelsConnecting(); + void ClearServiceChannelStates(); }; diff --git a/libraries/libvapours/include/vapours/results/htclow_results.hpp b/libraries/libvapours/include/vapours/results/htclow_results.hpp index 383d343c4..30e976b20 100644 --- a/libraries/libvapours/include/vapours/results/htclow_results.hpp +++ b/libraries/libvapours/include/vapours/results/htclow_results.hpp @@ -49,6 +49,8 @@ namespace ams::htclow { R_DEFINE_ERROR_RESULT(UsbDriverReceiveError, 1403); R_DEFINE_ERROR_RESULT(UsbDriverSendError, 1404); - R_DEFINE_ERROR_RESULT(StateTransitionNotAllowed, 2001); + R_DEFINE_ERROR_RESULT(HtcctrlError, 2000); /* TODO: Range? */ + R_DEFINE_ERROR_RESULT(HtcctrlStateTransitionNotAllowed, 2001); + R_DEFINE_ERROR_RESULT(HtcctrlReceiveUnexpectedPacket, 2002); }