mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-23 10:52:13 +00:00
htc: add remaining worker receive thread logic
This commit is contained in:
parent
6fc24d8883
commit
2cdfde6637
11 changed files with 477 additions and 36 deletions
|
@ -39,7 +39,7 @@ namespace ams::htclow::ctrl {
|
|||
|
||||
struct HtcctrlPacketHeader {
|
||||
u32 signature;
|
||||
u32 offset;
|
||||
u32 sequence_id;
|
||||
u32 reserved;
|
||||
u32 body_size;
|
||||
s16 version;
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "htclow_ctrl_packet_factory.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> 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<HtcctrlPacket *>(buffer);
|
||||
|
||||
/* Construct the packet. */
|
||||
std::construct_at(packet, m_allocator, body_size + sizeof(HtcctrlPacketHeader));
|
||||
|
||||
/* Create the unique pointer. */
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> 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<HtcctrlPacket, HtcctrlPacketDeleter>(nullptr, HtcctrlPacketDeleter{m_allocator});
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> HtcctrlPacketFactory::MakeSuspendPacket() {
|
||||
auto packet = this->MakeSendPacketCommon(0);
|
||||
if (packet && packet->IsAllocationSucceeded()) {
|
||||
packet->GetHeader()->packet_type = HtcctrlPacketType_SuspendFromTarget;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> HtcctrlPacketFactory::MakeResumePacket() {
|
||||
auto packet = this->MakeSendPacketCommon(0);
|
||||
if (packet && packet->IsAllocationSucceeded()) {
|
||||
packet->GetHeader()->packet_type = HtcctrlPacketType_SuspendFromTarget;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> 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<HtcctrlPacket, HtcctrlPacketDeleter> 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<HtcctrlPacket, HtcctrlPacketDeleter> HtcctrlPacketFactory::MakeDisconnectPacket() {
|
||||
auto packet = this->MakeSendPacketCommon(0);
|
||||
if (packet) {
|
||||
packet->GetHeader()->packet_type = HtcctrlPacketType_DisconnectFromTarget;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> 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<HtcctrlPacket, HtcctrlPacketDeleter> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,26 +15,39 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#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<const u32 *>(std::addressof(time)), sizeof(time) / sizeof(u32));
|
||||
|
||||
m_seed = rng.GenerateRandomU32();
|
||||
m_sequence_id = rng.GenerateRandomU32();
|
||||
}
|
||||
}
|
||||
public:
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeSuspendPacket();
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeResumePacket();
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeReadyPacket(const void *body, int body_size);
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeInformationPacket(const void *body, int body_size);
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeDisconnectPacket();
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeConnectPacket(const void *body, int body_size);
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeBeaconResponsePacket(const void *body, int body_size);
|
||||
|
||||
void Delete(HtcctrlPacket *packet);
|
||||
private:
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> MakeSendPacketCommon(int body_size);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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<HtcctrlPacket, HtcctrlPacketDeleter> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -26,9 +26,15 @@ namespace ams::htclow::ctrl {
|
|||
using PacketList = util::IntrusiveListBaseTraits<HtcctrlPacket>::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<HtcctrlPacket, HtcctrlPacketDeleter> ptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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<int>(ServiceChannels[0].module_id), ServiceChannels[0].reserved, static_cast<int>(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<int>(ServiceChannels[i].module_id), ServiceChannels[i].reserved, static_cast<int>(ServiceChannels[i].channel_id));
|
||||
}
|
||||
ofs += util::SNPrintf(dst + ofs, dst_size - ofs, "\r\n],\r\n \"Prot\" : %d\r\n}\r\n", ProtocolVersion);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
constexpr inline const impl::ChannelInternalType ServiceChannels[] = {
|
||||
{
|
||||
.channel_id = 0,
|
||||
.module_id = static_cast<ModuleId>(1),
|
||||
},
|
||||
{
|
||||
.channel_id = 1,
|
||||
.module_id = static_cast<ModuleId>(3),
|
||||
},
|
||||
{
|
||||
.channel_id = 2,
|
||||
.module_id = static_cast<ModuleId>(3),
|
||||
},
|
||||
{
|
||||
.channel_id = 0,
|
||||
.module_id = static_cast<ModuleId>(4),
|
||||
},
|
||||
};
|
||||
|
||||
}
|
|
@ -15,33 +15,10 @@
|
|||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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<ModuleId>(1),
|
||||
},
|
||||
{
|
||||
.channel_id = 1,
|
||||
.module_id = static_cast<ModuleId>(3),
|
||||
},
|
||||
{
|
||||
.channel_id = 2,
|
||||
.module_id = static_cast<ModuleId>(3),
|
||||
},
|
||||
{
|
||||
.channel_id = 0,
|
||||
.module_id = static_cast<ModuleId>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue