Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include "../htclow_packet.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
enum HtcctrlPacketType : u16 {
|
||||
HtcctrlPacketType_ConnectFromHost = 16,
|
||||
HtcctrlPacketType_ConnectFromTarget = 17,
|
||||
HtcctrlPacketType_ReadyFromHost = 18,
|
||||
HtcctrlPacketType_ReadyFromTarget = 19,
|
||||
HtcctrlPacketType_SuspendFromHost = 20,
|
||||
HtcctrlPacketType_SuspendFromTarget = 21,
|
||||
HtcctrlPacketType_ResumeFromHost = 22,
|
||||
HtcctrlPacketType_ResumeFromTarget = 23,
|
||||
HtcctrlPacketType_DisconnectFromHost = 24,
|
||||
HtcctrlPacketType_DisconnectFromTarget = 25,
|
||||
HtcctrlPacketType_BeaconQuery = 28,
|
||||
HtcctrlPacketType_BeaconResponse = 29,
|
||||
HtcctrlPacketType_InformationFromTarget = 33,
|
||||
};
|
||||
|
||||
static constexpr inline u32 HtcctrlSignature = 0x78825637;
|
||||
|
||||
struct HtcctrlPacketHeader {
|
||||
u32 signature;
|
||||
u32 sequence_id;
|
||||
u32 reserved;
|
||||
u32 body_size;
|
||||
s16 version;
|
||||
HtcctrlPacketType packet_type;
|
||||
impl::ChannelInternalType channel;
|
||||
u64 share;
|
||||
};
|
||||
static_assert(util::is_pod<HtcctrlPacketHeader>::value);
|
||||
static_assert(sizeof(HtcctrlPacketHeader) == 0x20);
|
||||
|
||||
static constexpr inline size_t HtcctrlPacketBodySizeMax = 0x1000;
|
||||
|
||||
struct HtcctrlPacketBody {
|
||||
u8 data[HtcctrlPacketBodySizeMax];
|
||||
};
|
||||
|
||||
class HtcctrlPacket : public BasePacket<HtcctrlPacketHeader>, public util::IntrusiveListBaseNode<HtcctrlPacket> {
|
||||
public:
|
||||
using BasePacket<HtcctrlPacketHeader>::BasePacket;
|
||||
};
|
||||
|
||||
struct HtcctrlPacketDeleter {
|
||||
mem::StandardAllocator *m_allocator;
|
||||
|
||||
void operator()(HtcctrlPacket *packet) {
|
||||
std::destroy_at(packet);
|
||||
m_allocator->Free(packet);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_ResumeFromTarget;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> HtcctrlPacketFactory::MakeReadyPacket(const void *body, int body_size) {
|
||||
auto packet = this->MakeSendPacketCommon(body_size);
|
||||
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(body_size);
|
||||
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(body_size);
|
||||
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(body_size);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include "htclow_ctrl_packet.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
class HtcctrlPacketFactory {
|
||||
private:
|
||||
mem::StandardAllocator *m_allocator;
|
||||
u32 m_sequence_id;
|
||||
public:
|
||||
HtcctrlPacketFactory(mem::StandardAllocator *allocator) : m_allocator(allocator) {
|
||||
/* Get the current time. */
|
||||
const u64 time = os::GetSystemTick().GetInt64Value();
|
||||
|
||||
/* Set a random sequence id. */
|
||||
{
|
||||
util::TinyMT rng;
|
||||
rng.Initialize(reinterpret_cast<const u32 *>(std::addressof(time)), sizeof(time) / sizeof(u32));
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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"
|
||||
#include "htclow_ctrl_packet_factory.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:
|
||||
return true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlSendBuffer::RemovePacket(const HtcctrlPacketHeader &header) {
|
||||
/* Get the packet type. */
|
||||
const auto packet_type = header.packet_type;
|
||||
|
||||
/* Remove the front from the appropriate list. */
|
||||
HtcctrlPacket *packet;
|
||||
if (this->IsPriorPacket(packet_type)) {
|
||||
packet = std::addressof(m_prior_packet_list.front());
|
||||
m_prior_packet_list.pop_front();
|
||||
} else {
|
||||
AMS_ABORT_UNLESS(this->IsPosteriorPacket(packet_type));
|
||||
packet = std::addressof(m_posterior_packet_list.front());
|
||||
m_posterior_packet_list.pop_front();
|
||||
}
|
||||
|
||||
/* Delete the packet. */
|
||||
m_packet_factory->Delete(packet);
|
||||
}
|
||||
|
||||
bool HtcctrlSendBuffer::QueryNextPacket(HtcctrlPacketHeader *header, HtcctrlPacketBody *body, int *out_body_size) {
|
||||
if (!m_prior_packet_list.empty()) {
|
||||
this->CopyPacket(header, body, out_body_size, m_prior_packet_list.front());
|
||||
return true;
|
||||
} else if (!m_posterior_packet_list.empty()) {
|
||||
this->CopyPacket(header, body, out_body_size, m_posterior_packet_list.front());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlSendBuffer::CopyPacket(HtcctrlPacketHeader *header, HtcctrlPacketBody *body, int *out_body_size, const HtcctrlPacket &packet) {
|
||||
/* Get the body size. */
|
||||
const int body_size = packet.GetBodySize();
|
||||
AMS_ASSERT(0 <= body_size && body_size <= static_cast<int>(sizeof(*body)));
|
||||
|
||||
/* Copy the header. */
|
||||
std::memcpy(header, packet.GetHeader(), sizeof(*header));
|
||||
|
||||
/* Copy the body. */
|
||||
std::memcpy(body, packet.GetBody(), body_size);
|
||||
|
||||
/* Set the output body size. */
|
||||
*out_body_size = body_size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include "htclow_ctrl_packet.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
class HtcctrlPacketFactory;
|
||||
|
||||
class HtcctrlSendBuffer {
|
||||
private:
|
||||
using PacketList = util::IntrusiveListBaseTraits<HtcctrlPacket>::ListType;
|
||||
private:
|
||||
HtcctrlPacketFactory *m_packet_factory;
|
||||
PacketList m_prior_packet_list;
|
||||
PacketList m_posterior_packet_list;
|
||||
private:
|
||||
bool IsPriorPacket(HtcctrlPacketType packet_type) const;
|
||||
bool IsPosteriorPacket(HtcctrlPacketType packet_type) const;
|
||||
|
||||
void CopyPacket(HtcctrlPacketHeader *header, HtcctrlPacketBody *body, int *out_body_size, const HtcctrlPacket &packet);
|
||||
public:
|
||||
HtcctrlSendBuffer(HtcctrlPacketFactory *pf) : m_packet_factory(pf), m_prior_packet_list(), m_posterior_packet_list() { /* ... */ }
|
||||
|
||||
void AddPacket(std::unique_ptr<HtcctrlPacket, HtcctrlPacketDeleter> ptr);
|
||||
void RemovePacket(const HtcctrlPacketHeader &header);
|
||||
|
||||
bool QueryNextPacket(HtcctrlPacketHeader *header, HtcctrlPacketBody *body, int *out_body_size);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,502 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_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 {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char BeaconPacketResponseTemplate[] =
|
||||
"{\r\n"
|
||||
" \"Spec\" : \"%s\",\r\n"
|
||||
" \"Conn\" : \"%s\",\r\n"
|
||||
" \"HW\" : \"%s\",\r\n"
|
||||
" \"Name\" : \"%s\",\r\n"
|
||||
" \"SN\" : \"%s\",\r\n"
|
||||
" \"FW\" : \"%s\",\r\n"
|
||||
" \"Prot\" : \"%d\"\r\n"
|
||||
"}\r\n";
|
||||
|
||||
}
|
||||
|
||||
HtcctrlService::HtcctrlService(HtcctrlPacketFactory *pf, HtcctrlStateMachine *sm, mux::Mux *mux)
|
||||
: m_settings_holder(), m_beacon_response(), m_information_body(), 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_service_channels_packet(), m_version(ProtocolVersion)
|
||||
{
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Set the mux version. */
|
||||
m_mux->SetVersion(m_version);
|
||||
|
||||
/* Update our beacon response. */
|
||||
this->UpdateBeaconResponse(this->GetConnectionType(impl::DriverType::Unknown));
|
||||
}
|
||||
|
||||
const char *HtcctrlService::GetConnectionType(impl::DriverType driver_type) const {
|
||||
switch (driver_type) {
|
||||
case impl::DriverType::Socket: return "TCP";
|
||||
case impl::DriverType::Usb: return "USB-gen2";
|
||||
case impl::DriverType::PlainChannel: return "HBPC-gen2";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlService::UpdateBeaconResponse(const char *connection) {
|
||||
/* Load settings into the holder. */
|
||||
m_settings_holder.LoadSettings();
|
||||
|
||||
/* Print our beacon response. */
|
||||
util::SNPrintf(m_beacon_response, sizeof(m_beacon_response), BeaconPacketResponseTemplate,
|
||||
m_settings_holder.GetSpec(),
|
||||
connection,
|
||||
m_settings_holder.GetHardwareType(),
|
||||
m_settings_holder.GetTargetName(),
|
||||
m_settings_holder.GetSerialNumber(),
|
||||
m_settings_holder.GetFirmwareVersion(),
|
||||
ProtocolVersion
|
||||
);
|
||||
}
|
||||
|
||||
void HtcctrlService::UpdateInformationBody(const char *status) {
|
||||
util::SNPrintf(m_information_body, sizeof(m_information_body), "{\r\n \"Status\" : \"%s\"\r\n}\r\n", status);
|
||||
}
|
||||
|
||||
void HtcctrlService::SetDriverType(impl::DriverType driver_type) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Update our beacon response. */
|
||||
this->UpdateBeaconResponse(this->GetConnectionType(driver_type));
|
||||
}
|
||||
|
||||
Result HtcctrlService::CheckReceivedHeader(const HtcctrlPacketHeader &header) const {
|
||||
/* Check the packet signature. */
|
||||
AMS_ASSERT(header.signature == HtcctrlSignature);
|
||||
|
||||
/* Validate version. */
|
||||
R_UNLESS(header.version == 1, htclow::ResultProtocolError());
|
||||
|
||||
/* Switch on the packet type. */
|
||||
switch (header.packet_type) {
|
||||
case HtcctrlPacketType_ConnectFromHost:
|
||||
case HtcctrlPacketType_SuspendFromHost:
|
||||
case HtcctrlPacketType_ResumeFromHost:
|
||||
case HtcctrlPacketType_DisconnectFromHost:
|
||||
case HtcctrlPacketType_BeaconQuery:
|
||||
R_UNLESS(header.body_size == 0, htclow::ResultProtocolError());
|
||||
break;
|
||||
case HtcctrlPacketType_ReadyFromHost:
|
||||
R_UNLESS(header.body_size <= sizeof(HtcctrlPacketBody), htclow::ResultProtocolError());
|
||||
break;
|
||||
default:
|
||||
R_THROW(htclow::ResultProtocolError());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HtcctrlService::ProcessReceivePacket(const HtcctrlPacketHeader &header, const void *body, size_t body_size) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
switch (header.packet_type) {
|
||||
case HtcctrlPacketType_ConnectFromHost:
|
||||
R_RETURN(this->ProcessReceiveConnectPacket());
|
||||
case HtcctrlPacketType_ReadyFromHost:
|
||||
R_RETURN(this->ProcessReceiveReadyPacket(body, body_size));
|
||||
case HtcctrlPacketType_SuspendFromHost:
|
||||
R_RETURN(this->ProcessReceiveSuspendPacket());
|
||||
case HtcctrlPacketType_ResumeFromHost:
|
||||
R_RETURN(this->ProcessReceiveResumePacket());
|
||||
case HtcctrlPacketType_DisconnectFromHost:
|
||||
R_RETURN(this->ProcessReceiveDisconnectPacket());
|
||||
case HtcctrlPacketType_BeaconQuery:
|
||||
R_RETURN(this->ProcessReceiveBeaconQueryPacket());
|
||||
default:
|
||||
R_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. */
|
||||
R_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();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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) {
|
||||
R_RETURN(this->ProcessReceiveUnexpectedPacket());
|
||||
}
|
||||
|
||||
/* Set our version. */
|
||||
m_version = ProtocolVersion;
|
||||
m_mux->SetVersion(m_version);
|
||||
|
||||
/* Set our state. */
|
||||
if (R_FAILED(this->SetState(HtcctrlState_SentReadyFromHost))) {
|
||||
R_RETURN(this->ProcessReceiveUnexpectedPacket());
|
||||
}
|
||||
|
||||
/* Ready ourselves. */
|
||||
this->TryReadyInternal();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HtcctrlService::ProcessReceiveSuspendPacket() {
|
||||
/* Try to set our state to enter sleep. */
|
||||
if (R_FAILED(this->SetState(HtcctrlState_EnterSleep))) {
|
||||
/* We couldn't transition to sleep. */
|
||||
R_RETURN(this->ProcessReceiveUnexpectedPacket());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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. */
|
||||
R_RETURN(this->ProcessReceiveUnexpectedPacket());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HtcctrlService::ProcessReceiveDisconnectPacket() {
|
||||
/* Set our state. */
|
||||
R_TRY(this->SetState(HtcctrlState_Disconnected));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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. */
|
||||
R_THROW(htclow::ResultHtcctrlReceiveUnexpectedPacket());
|
||||
}
|
||||
|
||||
void HtcctrlService::ProcessSendConnectPacket() {
|
||||
/* Set our state. */
|
||||
const Result result = this->SetState(HtcctrlState_Connected);
|
||||
R_ASSERT(result);
|
||||
}
|
||||
|
||||
void HtcctrlService::ProcessSendReadyPacket() {
|
||||
/* Set our state. */
|
||||
if (m_state_machine->GetHtcctrlState() == HtcctrlState_SentReadyFromHost) {
|
||||
const Result result = this->SetState(HtcctrlState_Ready);
|
||||
R_ASSERT(result);
|
||||
}
|
||||
|
||||
/* Update channel states. */
|
||||
m_mux->UpdateChannelState();
|
||||
}
|
||||
|
||||
void HtcctrlService::ProcessSendSuspendPacket() {
|
||||
/* Set our state. */
|
||||
const Result result = this->SetState(HtcctrlState_SentSuspendFromTarget);
|
||||
R_ASSERT(result);
|
||||
}
|
||||
|
||||
void HtcctrlService::ProcessSendResumePacket() {
|
||||
/* Set our state. */
|
||||
const Result result = this->SetState(HtcctrlState_SentResumeFromTarget);
|
||||
R_ASSERT(result);
|
||||
}
|
||||
|
||||
void HtcctrlService::ProcessSendDisconnectPacket() {
|
||||
/* Set our state. */
|
||||
const Result result = this->SetState(HtcctrlState_Disconnected);
|
||||
R_ASSERT(result);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
bool HtcctrlService::QuerySendPacket(HtcctrlPacketHeader *header, HtcctrlPacketBody *body, int *out_body_size) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return m_send_buffer.QueryNextPacket(header, body, out_body_size);
|
||||
}
|
||||
|
||||
void HtcctrlService::RemovePacket(const HtcctrlPacketHeader &header) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Remove the packet from our buffer. */
|
||||
m_send_buffer.RemovePacket(header);
|
||||
|
||||
/* Switch on the packet type. */
|
||||
switch (header.packet_type) {
|
||||
case HtcctrlPacketType_ConnectFromTarget:
|
||||
this->ProcessSendConnectPacket();
|
||||
break;
|
||||
case HtcctrlPacketType_ReadyFromTarget:
|
||||
this->ProcessSendReadyPacket();
|
||||
break;
|
||||
case HtcctrlPacketType_SuspendFromTarget:
|
||||
this->ProcessSendSuspendPacket();
|
||||
break;
|
||||
case HtcctrlPacketType_ResumeFromTarget:
|
||||
this->ProcessSendResumePacket();
|
||||
break;
|
||||
case HtcctrlPacketType_DisconnectFromTarget:
|
||||
this->ProcessSendDisconnectPacket();
|
||||
break;
|
||||
case HtcctrlPacketType_BeaconResponse:
|
||||
case HtcctrlPacketType_InformationFromTarget:
|
||||
break;
|
||||
default:
|
||||
AMS_ABORT("Send unsupported packet 0x%04x\n", static_cast<u32>(header.packet_type));
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlService::TryReady() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
this->TryReadyInternal();
|
||||
}
|
||||
|
||||
void HtcctrlService::Disconnect() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
this->DisconnectInternal();
|
||||
}
|
||||
|
||||
void HtcctrlService::DisconnectInternal() {
|
||||
/* Disconnect, if we need to. */
|
||||
if (m_state_machine->IsDisconnectionNeeded()) {
|
||||
/* Send a disconnect packet. */
|
||||
m_send_buffer.AddPacket(m_packet_factory->MakeDisconnectPacket());
|
||||
|
||||
/* Signal our event. */
|
||||
m_event.Signal();
|
||||
|
||||
/* Wait for us to be disconnected. */
|
||||
while (!m_state_machine->IsDisconnected()) {
|
||||
m_condvar.Wait(m_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlService::Resume() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Send resume packet, if we can. */
|
||||
if (const auto state = m_state_machine->GetHtcctrlState(); state == HtcctrlState_Sleep || state == HtcctrlState_ExitSleep) {
|
||||
/* Send a resume packet. */
|
||||
m_send_buffer.AddPacket(m_packet_factory->MakeResumePacket());
|
||||
|
||||
/* Signal our event. */
|
||||
m_event.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlService::Suspend() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* If we can, perform a suspend. */
|
||||
if (m_state_machine->GetHtcctrlState() == HtcctrlState_Ready) {
|
||||
/* Send a suspend packet. */
|
||||
m_send_buffer.AddPacket(m_packet_factory->MakeSuspendPacket());
|
||||
|
||||
/* Signal our event. */
|
||||
m_event.Signal();
|
||||
|
||||
/* Wait for our state to transition. */
|
||||
for (auto state = m_state_machine->GetHtcctrlState(); state == HtcctrlState_Ready || state == HtcctrlState_SentSuspendFromTarget; state = m_state_machine->GetHtcctrlState()) {
|
||||
m_condvar.Wait(m_mutex);
|
||||
}
|
||||
} else {
|
||||
/* Otherwise, just disconnect. */
|
||||
this->DisconnectInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlService::NotifyAwake() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Update our information. */
|
||||
this->UpdateInformationBody("Awake");
|
||||
|
||||
/* Send information to host. */
|
||||
this->SendInformation();
|
||||
}
|
||||
|
||||
void HtcctrlService::NotifyAsleep() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Update our information. */
|
||||
this->UpdateInformationBody("Asleep");
|
||||
|
||||
/* Send information to host. */
|
||||
this->SendInformation();
|
||||
}
|
||||
|
||||
void HtcctrlService::SendInformation() {
|
||||
/* If we need information, send information. */
|
||||
if (m_state_machine->IsInformationNeeded()) {
|
||||
/* Send an information packet. */
|
||||
m_send_buffer.AddPacket(m_packet_factory->MakeInformationPacket(m_information_body, util::Strnlen(m_information_body, sizeof(m_information_body)) + 1));
|
||||
|
||||
/* Signal our event. */
|
||||
m_event.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
Result HtcctrlService::NotifyDriverConnected() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
if (m_state_machine->GetHtcctrlState() == HtcctrlState_Sleep) {
|
||||
R_TRY(this->SetState(HtcctrlState_ExitSleep));
|
||||
} else {
|
||||
R_TRY(this->SetState(HtcctrlState_DriverConnected));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HtcctrlService::NotifyDriverDisconnected() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
if (m_state_machine->GetHtcctrlState() == HtcctrlState_EnterSleep) {
|
||||
R_TRY(this->SetState(HtcctrlState_Sleep));
|
||||
} else {
|
||||
R_TRY(this->SetState(HtcctrlState_DriverDisconnected));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HtcctrlService::SetState(HtcctrlState state) {
|
||||
/* Set the state. */
|
||||
bool did_transition;
|
||||
R_TRY(m_state_machine->SetHtcctrlState(std::addressof(did_transition), state));
|
||||
|
||||
/* Reflect the state transition, if one occurred. */
|
||||
if (did_transition) {
|
||||
this->ReflectState();
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HtcctrlService::ReflectState() {
|
||||
/* If our connected status changed, update. */
|
||||
if (m_state_machine->IsConnectedStatusChanged()) {
|
||||
m_mux->UpdateChannelState();
|
||||
}
|
||||
|
||||
/* If our sleeping status changed, update. */
|
||||
if (m_state_machine->IsSleepingStatusChanged()) {
|
||||
m_mux->UpdateMuxState();
|
||||
}
|
||||
|
||||
/* Broadcast our state transition. */
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include "htclow_ctrl_settings_holder.hpp"
|
||||
#include "htclow_ctrl_send_buffer.hpp"
|
||||
#include "htclow_ctrl_state.hpp"
|
||||
|
||||
namespace ams::htclow {
|
||||
|
||||
namespace ctrl {
|
||||
|
||||
class HtcctrlPacketFactory;
|
||||
class HtcctrlStateMachine;
|
||||
|
||||
}
|
||||
|
||||
namespace mux {
|
||||
|
||||
class Mux;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
class HtcctrlService {
|
||||
private:
|
||||
SettingsHolder m_settings_holder;
|
||||
char m_beacon_response[0x1000];
|
||||
char m_information_body[0x1000];
|
||||
HtcctrlPacketFactory *m_packet_factory;
|
||||
HtcctrlStateMachine *m_state_machine;
|
||||
mux::Mux *m_mux;
|
||||
os::Event m_event;
|
||||
HtcctrlSendBuffer m_send_buffer;
|
||||
os::SdkMutex m_mutex;
|
||||
os::SdkConditionVariable m_condvar;
|
||||
char m_service_channels_packet[0x1000];
|
||||
s16 m_version;
|
||||
private:
|
||||
const char *GetConnectionType(impl::DriverType driver_type) const;
|
||||
|
||||
void UpdateBeaconResponse(const char *connection);
|
||||
void UpdateInformationBody(const char *status);
|
||||
|
||||
void SendInformation();
|
||||
|
||||
Result ProcessReceiveConnectPacket();
|
||||
Result ProcessReceiveReadyPacket(const void *body, size_t body_size);
|
||||
Result ProcessReceiveSuspendPacket();
|
||||
Result ProcessReceiveResumePacket();
|
||||
Result ProcessReceiveDisconnectPacket();
|
||||
Result ProcessReceiveBeaconQueryPacket();
|
||||
Result ProcessReceiveUnexpectedPacket();
|
||||
|
||||
void ProcessSendConnectPacket();
|
||||
void ProcessSendReadyPacket();
|
||||
void ProcessSendSuspendPacket();
|
||||
void ProcessSendResumePacket();
|
||||
void ProcessSendDisconnectPacket();
|
||||
|
||||
void UpdateServiceChannels(const void *body, size_t body_size);
|
||||
|
||||
void PrintServiceChannels(char *dst, size_t dst_size);
|
||||
|
||||
void TryReadyInternal();
|
||||
void DisconnectInternal();
|
||||
|
||||
Result SetState(HtcctrlState state);
|
||||
void ReflectState();
|
||||
public:
|
||||
HtcctrlService(HtcctrlPacketFactory *pf, HtcctrlStateMachine *sm, mux::Mux *mux);
|
||||
|
||||
void SetDriverType(impl::DriverType driver_type);
|
||||
|
||||
os::EventType *GetSendPacketEvent() { return m_event.GetBase(); }
|
||||
|
||||
Result CheckReceivedHeader(const HtcctrlPacketHeader &header) const;
|
||||
Result ProcessReceivePacket(const HtcctrlPacketHeader &header, const void *body, size_t body_size);
|
||||
|
||||
bool QuerySendPacket(HtcctrlPacketHeader *header, HtcctrlPacketBody *body, int *out_body_size);
|
||||
void RemovePacket(const HtcctrlPacketHeader &header);
|
||||
|
||||
void TryReady();
|
||||
void Disconnect();
|
||||
|
||||
void Resume();
|
||||
void Suspend();
|
||||
|
||||
void NotifyAwake();
|
||||
void NotifyAsleep();
|
||||
|
||||
Result NotifyDriverConnected();
|
||||
Result NotifyDriverDisconnected();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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, /* TODO: htcfs::ChannelId? */
|
||||
.module_id = ModuleId::Htcfs,
|
||||
},
|
||||
{
|
||||
.channel_id = 1, /* TODO: htcmisc::ClientChannelId? */
|
||||
.module_id = ModuleId::Htcmisc,
|
||||
},
|
||||
{
|
||||
.channel_id = 2, /* TODO: htcmisc::ServerChannelId? */
|
||||
.module_id = ModuleId::Htcmisc,
|
||||
},
|
||||
{
|
||||
.channel_id = 0, /* TODO: htcs::ChannelId? */
|
||||
.module_id = ModuleId::Htcs,
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_settings_holder.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
void SettingsHolder::LoadSettings() {
|
||||
/* Load configuration id. */
|
||||
{
|
||||
settings::factory::ConfigurationId1 cfg_id;
|
||||
settings::factory::GetConfigurationId1(std::addressof(cfg_id));
|
||||
|
||||
if (cfg_id.str[0]) {
|
||||
util::Strlcpy(m_hardware_type, cfg_id.str, sizeof(m_hardware_type));
|
||||
} else {
|
||||
util::Strlcpy(m_hardware_type, "Unknown", sizeof(m_hardware_type));
|
||||
}
|
||||
}
|
||||
|
||||
/* Load device name. */
|
||||
{
|
||||
char device_name[0x40];
|
||||
settings::fwdbg::GetSettingsItemValue(device_name, sizeof(device_name), "target_manager", "device_name");
|
||||
util::Strlcpy(m_target_name, device_name, sizeof(m_target_name));
|
||||
}
|
||||
|
||||
/* Load serial number. */
|
||||
{
|
||||
settings::factory::SerialNumber sn;
|
||||
if (R_SUCCEEDED(settings::factory::GetSerialNumber(std::addressof(sn)))) {
|
||||
util::Strlcpy(m_serial_number, sn.str, sizeof(m_serial_number));
|
||||
} else {
|
||||
m_serial_number[0] = '\x00';
|
||||
}
|
||||
}
|
||||
|
||||
/* Load firmware version. */
|
||||
{
|
||||
settings::system::FirmwareVersion fw_ver;
|
||||
settings::system::GetFirmwareVersion(std::addressof(fw_ver));
|
||||
util::Strlcpy(m_firmware_version, fw_ver.display_name, sizeof(m_firmware_version));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 {
|
||||
|
||||
class SettingsHolder {
|
||||
private:
|
||||
char m_hardware_type[0x40]{};
|
||||
char m_target_name[0x40]{};
|
||||
char m_serial_number[0x40]{};
|
||||
char m_firmware_version[0x40]{};
|
||||
public:
|
||||
constexpr SettingsHolder() = default;
|
||||
|
||||
void LoadSettings();
|
||||
|
||||
const char *GetSpec() { return "NX"; }
|
||||
const char *GetHardwareType() { return m_hardware_type; }
|
||||
const char *GetTargetName() { return m_target_name; }
|
||||
const char *GetSerialNumber() { return m_serial_number; }
|
||||
const char *GetFirmwareVersion() { return m_firmware_version; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 {
|
||||
|
||||
enum HtcctrlState : u32 {
|
||||
HtcctrlState_DriverConnected = 0,
|
||||
HtcctrlState_SentConnectFromHost = 1,
|
||||
HtcctrlState_Connected = 2,
|
||||
HtcctrlState_SentReadyFromHost = 3,
|
||||
HtcctrlState_Ready = 4,
|
||||
HtcctrlState_SentSuspendFromTarget = 5,
|
||||
HtcctrlState_EnterSleep = 6,
|
||||
HtcctrlState_Sleep = 7,
|
||||
HtcctrlState_ExitSleep = 8,
|
||||
HtcctrlState_SentResumeFromTarget = 9,
|
||||
HtcctrlState_Disconnected = 10,
|
||||
HtcctrlState_DriverDisconnected = 11,
|
||||
HtcctrlState_Error = 12,
|
||||
};
|
||||
|
||||
constexpr bool IsStateTransitionAllowed(HtcctrlState from, HtcctrlState to) {
|
||||
switch (from) {
|
||||
case HtcctrlState_DriverConnected:
|
||||
return to == HtcctrlState_SentConnectFromHost ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_SentConnectFromHost:
|
||||
return to == HtcctrlState_Connected ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_Connected:
|
||||
return to == HtcctrlState_SentReadyFromHost ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_SentReadyFromHost:
|
||||
return to == HtcctrlState_Ready ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_Ready:
|
||||
return to == HtcctrlState_SentSuspendFromTarget ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_SentSuspendFromTarget:
|
||||
return to == HtcctrlState_EnterSleep ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_EnterSleep:
|
||||
return to == HtcctrlState_Sleep ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_Sleep:
|
||||
return to == HtcctrlState_ExitSleep;
|
||||
case HtcctrlState_ExitSleep:
|
||||
return to == HtcctrlState_SentResumeFromTarget ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_SentResumeFromTarget:
|
||||
return to == HtcctrlState_Ready ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_Disconnected:
|
||||
return to == HtcctrlState_SentConnectFromHost ||
|
||||
to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
case HtcctrlState_DriverDisconnected:
|
||||
return to == HtcctrlState_DriverConnected;
|
||||
case HtcctrlState_Error:
|
||||
return to == HtcctrlState_Disconnected ||
|
||||
to == HtcctrlState_DriverDisconnected ||
|
||||
to == HtcctrlState_Error;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsDisconnected(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_Disconnected:
|
||||
case HtcctrlState_DriverDisconnected:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsConnecting(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_DriverConnected:
|
||||
case HtcctrlState_SentConnectFromHost:
|
||||
case HtcctrlState_Disconnected:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsConnected(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_Connected:
|
||||
case HtcctrlState_SentReadyFromHost:
|
||||
case HtcctrlState_Ready:
|
||||
case HtcctrlState_SentSuspendFromTarget:
|
||||
case HtcctrlState_EnterSleep:
|
||||
case HtcctrlState_Sleep:
|
||||
case HtcctrlState_ExitSleep:
|
||||
case HtcctrlState_SentResumeFromTarget:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsReadied(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_Ready:
|
||||
case HtcctrlState_SentSuspendFromTarget:
|
||||
case HtcctrlState_EnterSleep:
|
||||
case HtcctrlState_Sleep:
|
||||
case HtcctrlState_ExitSleep:
|
||||
case HtcctrlState_SentResumeFromTarget:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsSleeping(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_SentSuspendFromTarget:
|
||||
case HtcctrlState_EnterSleep:
|
||||
case HtcctrlState_Sleep:
|
||||
case HtcctrlState_ExitSleep:
|
||||
case HtcctrlState_SentResumeFromTarget:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_state_machine.hpp"
|
||||
#include "htclow_ctrl_service_channels.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
HtcctrlStateMachine::HtcctrlStateMachine() : m_map(), m_state(HtcctrlState_DriverDisconnected), m_prev_state(HtcctrlState_DriverDisconnected), m_mutex() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Initialize our map. */
|
||||
m_map.Initialize(MaxChannelCount, m_map_buffer, sizeof(m_map_buffer));
|
||||
|
||||
/* Insert each service channel the map. */
|
||||
for (const auto &channel : ServiceChannels) {
|
||||
m_map.insert(std::make_pair<impl::ChannelInternalType, ServiceChannelState>(impl::ChannelInternalType{channel}, ServiceChannelState{}));
|
||||
}
|
||||
}
|
||||
|
||||
HtcctrlState HtcctrlStateMachine::GetHtcctrlState() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return m_state;
|
||||
}
|
||||
|
||||
Result HtcctrlStateMachine::SetHtcctrlState(bool *out_transitioned, HtcctrlState state) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* Check that the transition is allowed. */
|
||||
R_UNLESS(ctrl::IsStateTransitionAllowed(m_state, state), htclow::ResultHtcctrlStateTransitionNotAllowed());
|
||||
|
||||
/* Get the state pre-transition. */
|
||||
const auto old_state = m_state;
|
||||
|
||||
/* Set the state. */
|
||||
this->SetStateWithoutCheckInternal(state);
|
||||
|
||||
/* Note whether we transitioned. */
|
||||
*out_transitioned = state != old_state;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsInformationNeeded() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return !ctrl::IsDisconnected(m_state) && m_state != HtcctrlState_DriverConnected;
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsDisconnectionNeeded() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return !ctrl::IsDisconnected(m_state) && m_state != HtcctrlState_Sleep && m_state != HtcctrlState_DriverConnected;
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsConnected() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return ctrl::IsConnected(m_state);
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsReadied() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return ctrl::IsReadied(m_state);
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsUnconnectable() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return !ctrl::IsConnected(m_state);
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsDisconnected() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return ctrl::IsDisconnected(m_state);
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsSleeping() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return ctrl::IsSleeping(m_state);
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsConnectedStatusChanged() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return ctrl::IsConnected(m_prev_state) ^ ctrl::IsConnected(m_state);
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsSleepingStatusChanged() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
return ctrl::IsSleeping(m_prev_state) ^ ctrl::IsSleeping(m_state);
|
||||
}
|
||||
|
||||
void HtcctrlStateMachine::SetStateWithoutCheckInternal(HtcctrlState state) {
|
||||
if (m_state != state) {
|
||||
/* Clear service channel states, if we should. */
|
||||
if (ctrl::IsDisconnected(state)) {
|
||||
this->ClearServiceChannelStates();
|
||||
}
|
||||
|
||||
/* Transition our state. */
|
||||
m_prev_state = m_state;
|
||||
m_state = state;
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlStateMachine::ClearServiceChannelStates() {
|
||||
/* Clear all values in our map. */
|
||||
for (auto &pair : m_map) {
|
||||
pair.second = {};
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
auto it = m_map.find(channel);
|
||||
return it != m_map.end() && it->second.connect == ServiceChannelConnect_ConnectingChecked && it->second.support == ServiceChannelSupport_Unsupported;
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsConnectable(const impl::ChannelInternalType &channel) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
auto it = m_map.find(channel);
|
||||
return ctrl::IsConnected(m_state) && (it == m_map.end() || it->second.connect != ServiceChannelConnect_ConnectingChecked);
|
||||
}
|
||||
|
||||
void HtcctrlStateMachine::SetConnecting(const impl::ChannelInternalType &channel) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
auto it = m_map.find(channel);
|
||||
if (it != m_map.end() && it->second.connect != ServiceChannelConnect_ConnectingChecked) {
|
||||
it->second.connect = ServiceChannelConnect_Connecting;
|
||||
}
|
||||
}
|
||||
|
||||
void HtcctrlStateMachine::SetNotConnecting(const impl::ChannelInternalType &channel) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
auto it = m_map.find(channel);
|
||||
if (it != m_map.end() && it->second.connect != ServiceChannelConnect_ConnectingChecked) {
|
||||
it->second.connect = ServiceChannelConnect_NotConnecting;
|
||||
}
|
||||
}
|
||||
|
||||
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 = [](const impl::ChannelInternalType &channel, const impl::ChannelInternalType *supported, int num_supported) ALWAYS_INLINE_LAMBDA -> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include "htclow_ctrl_state.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
class HtcctrlStateMachine {
|
||||
private:
|
||||
enum ServiceChannelSupport {
|
||||
ServiceChannelSupport_Unknown = 0,
|
||||
ServiceChannelSupport_Suppported = 1,
|
||||
ServiceChannelSupport_Unsupported = 2,
|
||||
};
|
||||
|
||||
enum ServiceChannelConnect {
|
||||
ServiceChannelConnect_NotConnecting = 0,
|
||||
ServiceChannelConnect_Connecting = 1,
|
||||
ServiceChannelConnect_ConnectingChecked = 2,
|
||||
};
|
||||
|
||||
struct ServiceChannelState {
|
||||
ServiceChannelSupport support;
|
||||
ServiceChannelConnect connect;
|
||||
};
|
||||
|
||||
static constexpr int MaxChannelCount = 10;
|
||||
|
||||
using MapType = util::FixedMap<impl::ChannelInternalType, ServiceChannelState>;
|
||||
|
||||
static constexpr size_t MapRequiredMemorySize = MapType::GetRequiredMemorySize(MaxChannelCount);
|
||||
private:
|
||||
u8 m_map_buffer[MapRequiredMemorySize];
|
||||
MapType m_map;
|
||||
HtcctrlState m_state;
|
||||
HtcctrlState m_prev_state;
|
||||
os::SdkMutex m_mutex;
|
||||
public:
|
||||
HtcctrlStateMachine();
|
||||
|
||||
HtcctrlState GetHtcctrlState();
|
||||
Result SetHtcctrlState(bool *out_transitioned, HtcctrlState state);
|
||||
|
||||
bool IsConnectedStatusChanged();
|
||||
bool IsSleepingStatusChanged();
|
||||
|
||||
bool IsInformationNeeded();
|
||||
bool IsDisconnectionNeeded();
|
||||
|
||||
bool IsConnected();
|
||||
bool IsReadied();
|
||||
bool IsUnconnectable();
|
||||
bool IsDisconnected();
|
||||
bool IsSleeping();
|
||||
|
||||
bool IsPossibleToSendReady();
|
||||
bool IsUnsupportedServiceChannelToShutdown(const impl::ChannelInternalType &channel);
|
||||
bool IsConnectable(const impl::ChannelInternalType &channel);
|
||||
|
||||
void SetConnecting(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();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_json.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char ChannelKey[] = "Chan";
|
||||
constexpr const char ProtocolVersionKey[] = "Prot";
|
||||
|
||||
}
|
||||
|
||||
bool JsonHandler::Key(const Ch *str, rapidjson::SizeType len, bool copy) {
|
||||
AMS_UNUSED(len, copy);
|
||||
|
||||
if (m_state == State::ParseObject) {
|
||||
if (!util::Strncmp(str, ChannelKey, sizeof(ChannelKey))) {
|
||||
m_state = State::ParseServiceChannels;
|
||||
}
|
||||
if (!util::Strncmp(str, ProtocolVersionKey, sizeof(ProtocolVersionKey))) {
|
||||
m_state = State::ParseProtocolVersion;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::Uint(unsigned val) {
|
||||
if (m_state == State::ParseProtocolVersion) {
|
||||
*m_version = val;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::String(const Ch *str, rapidjson::SizeType len, bool copy) {
|
||||
AMS_UNUSED(len, copy);
|
||||
|
||||
if (m_state == State::ParseServiceChannelsArray && *m_num_strings < m_max_strings) {
|
||||
m_strings[(*m_num_strings)++] = str;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::StartObject() {
|
||||
if (m_state == State::Begin) {
|
||||
m_state = State::ParseObject;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::EndObject(rapidjson::SizeType) {
|
||||
m_state = State::End;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::StartArray() {
|
||||
if (m_state == State::ParseServiceChannels) {
|
||||
m_state = State::ParseServiceChannelsArray;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::EndArray(rapidjson::SizeType len) {
|
||||
if (m_state == State::ParseServiceChannelsArray && len) {
|
||||
m_state = State::ParseObject;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 {
|
||||
|
||||
class JsonHandler : public rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, JsonHandler>{
|
||||
private:
|
||||
enum class State {
|
||||
Begin = 0,
|
||||
ParseObject = 1,
|
||||
ParseServiceChannels = 2,
|
||||
ParseServiceChannelsArray = 3,
|
||||
ParseProtocolVersion = 4,
|
||||
End = 5,
|
||||
};
|
||||
private:
|
||||
State m_state;
|
||||
s16 *m_version;
|
||||
const char **m_strings;
|
||||
int *m_num_strings;
|
||||
int m_max_strings;
|
||||
public:
|
||||
JsonHandler(s16 *vers, const char **str, int *ns, int max) : m_state(State::Begin), m_version(vers), m_strings(str), m_num_strings(ns), m_max_strings(max) { /* ... */ }
|
||||
|
||||
bool Key(const Ch *str, rapidjson::SizeType len, bool copy);
|
||||
bool Uint(unsigned);
|
||||
bool String(const Ch *, rapidjson::SizeType, bool);
|
||||
|
||||
bool StartObject();
|
||||
bool EndObject(rapidjson::SizeType);
|
||||
bool StartArray();
|
||||
bool EndArray(rapidjson::SizeType);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_json.hpp"
|
||||
#include "htclow_service_channel_parser.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto JsonParseFlags = rapidjson::kParseTrailingCommasFlag | rapidjson::kParseInsituFlag;
|
||||
|
||||
void ParseBody(s16 *out_version, const char **out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size) {
|
||||
AMS_UNUSED(str_size);
|
||||
|
||||
/* Create JSON handler. */
|
||||
JsonHandler json_handler(out_version, out_channels, out_num_channels, max_channels);
|
||||
|
||||
/* Create reader. */
|
||||
rapidjson::Reader json_reader;
|
||||
|
||||
/* Create stream. */
|
||||
rapidjson::InsituStringStream json_stream(static_cast<char *>(str));
|
||||
|
||||
/* Parse the json. */
|
||||
json_reader.Parse<JsonParseFlags>(json_stream, json_handler);
|
||||
}
|
||||
|
||||
constexpr bool IsNumericCharacter(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
constexpr bool IsValidCharacter(char c) {
|
||||
return IsNumericCharacter(c) || c == ':';
|
||||
}
|
||||
|
||||
bool IntegerToModuleId(ModuleId *out, int id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
case 4:
|
||||
*out = static_cast<ModuleId>(id);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool StringToChannel(impl::ChannelInternalType *out, char *str, size_t size) {
|
||||
enum class State {
|
||||
Begin,
|
||||
ModuleId,
|
||||
Sep1,
|
||||
Reserved,
|
||||
Sep2,
|
||||
ChannelId
|
||||
};
|
||||
|
||||
State state = State::Begin;
|
||||
|
||||
const char * cur = nullptr;
|
||||
|
||||
const char * const str_end = str + size;
|
||||
while (str < str_end && IsValidCharacter(*str)) {
|
||||
const char c = *str;
|
||||
|
||||
switch (state) {
|
||||
case State::Begin:
|
||||
if (IsNumericCharacter(c)) {
|
||||
cur = str;
|
||||
state = State::ModuleId;
|
||||
}
|
||||
break;
|
||||
case State::ModuleId:
|
||||
if (c == ':') {
|
||||
*str = 0;
|
||||
if (!IntegerToModuleId(std::addressof(out->module_id), atoi(cur))) {
|
||||
return false;
|
||||
}
|
||||
state = State::Sep1;
|
||||
} else if (!IsNumericCharacter(c)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case State::Sep1:
|
||||
if (IsNumericCharacter(c)) {
|
||||
cur = str;
|
||||
state = State::Reserved;
|
||||
}
|
||||
break;
|
||||
case State::Reserved:
|
||||
if (c == ':') {
|
||||
*str = 0;
|
||||
out->reserved = 0;
|
||||
state = State::Sep2;
|
||||
} else if (!IsNumericCharacter(c)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case State::Sep2:
|
||||
if (IsNumericCharacter(c)) {
|
||||
cur = str;
|
||||
state = State::ChannelId;
|
||||
}
|
||||
break;
|
||||
case State::ChannelId:
|
||||
if (!IsNumericCharacter(c)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
++str;
|
||||
}
|
||||
|
||||
if (str != str_end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out->channel_id = atoi(cur);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ParseServiceChannel(s16 *out_version, impl::ChannelInternalType *out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size) {
|
||||
/* Parse the JSON. */
|
||||
const char *channel_strs[0x20];
|
||||
int num_channels = 0;
|
||||
ParseBody(out_version, channel_strs, std::addressof(num_channels), util::size(channel_strs), str, str_size);
|
||||
|
||||
/* Parse the channel strings. */
|
||||
char * const str_end = static_cast<char *>(str) + str_size;
|
||||
int parsed_channels = 0;
|
||||
for (auto i = 0; i < num_channels && i < max_channels; ++i) {
|
||||
impl::ChannelInternalType channel;
|
||||
if (StringToChannel(std::addressof(channel), const_cast<char *>(channel_strs[i]), util::Strnlen(channel_strs[i], str_end - channel_strs[i]))) {
|
||||
out_channels[parsed_channels++] = channel;
|
||||
}
|
||||
}
|
||||
|
||||
*out_num_channels = parsed_channels;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 {
|
||||
|
||||
void ParseServiceChannel(s16 *out_version, impl::ChannelInternalType *out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user