mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-05 09:13:43 -04:00
htc: implement htclow listener thread
This commit is contained in:
parent
c9c41e0e8d
commit
2341f18edd
21 changed files with 669 additions and 11 deletions
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "htclow_ctrl_service.hpp"
|
||||
#include "htclow_ctrl_state.hpp"
|
||||
#include "htclow_ctrl_state_machine.hpp"
|
||||
#include "../mux/htclow_mux.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
@ -81,4 +83,58 @@ namespace ams::htclow::ctrl {
|
|||
this->UpdateBeaconResponse(this->GetConnectionType(driver_type));
|
||||
}
|
||||
|
||||
Result HtcctrlService::NotifyDriverConnected() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
if (m_state_machine->GetHtcctrlState() == HtcctrlState_7) {
|
||||
R_TRY(this->SetState(HtcctrlState_8));
|
||||
} else {
|
||||
R_TRY(this->SetState(HtcctrlState_0));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HtcctrlService::NotifyDriverDisconnected() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
if (m_state_machine->GetHtcctrlState() == HtcctrlState_6) {
|
||||
R_TRY(this->SetState(HtcctrlState_7));
|
||||
} else {
|
||||
R_TRY(this->SetState(HtcctrlState_11));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <stratosphere.hpp>
|
||||
#include "htclow_ctrl_settings_holder.hpp"
|
||||
#include "htclow_ctrl_send_buffer.hpp"
|
||||
#include "htclow_ctrl_state.hpp"
|
||||
|
||||
namespace ams::htclow {
|
||||
|
||||
|
@ -55,10 +56,16 @@ namespace ams::htclow::ctrl {
|
|||
const char *GetConnectionType(impl::DriverType driver_type) const;
|
||||
|
||||
void UpdateBeaconResponse(const char *connection);
|
||||
|
||||
Result SetState(HtcctrlState state);
|
||||
void ReflectState();
|
||||
public:
|
||||
HtcctrlService(HtcctrlPacketFactory *pf, HtcctrlStateMachine *sm, mux::Mux *mux);
|
||||
|
||||
void SetDriverType(impl::DriverType driver_type);
|
||||
|
||||
Result NotifyDriverConnected();
|
||||
Result NotifyDriverDisconnected();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,115 @@
|
|||
namespace ams::htclow::ctrl {
|
||||
|
||||
enum HtcctrlState : u32 {
|
||||
HtcctrlState_Eleven = 11,
|
||||
HtcctrlState_0 = 0,
|
||||
HtcctrlState_1 = 1,
|
||||
HtcctrlState_2 = 2,
|
||||
HtcctrlState_3 = 3,
|
||||
HtcctrlState_4 = 4,
|
||||
HtcctrlState_5 = 5,
|
||||
HtcctrlState_6 = 6,
|
||||
HtcctrlState_7 = 7,
|
||||
HtcctrlState_8 = 8,
|
||||
HtcctrlState_9 = 9,
|
||||
HtcctrlState_10 = 10,
|
||||
HtcctrlState_11 = 11,
|
||||
HtcctrlState_12 = 12,
|
||||
};
|
||||
|
||||
constexpr bool IsStateTransitionAllowed(HtcctrlState from, HtcctrlState to) {
|
||||
switch (from) {
|
||||
case HtcctrlState_0:
|
||||
return to == HtcctrlState_1 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_1:
|
||||
return to == HtcctrlState_2 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_2:
|
||||
return to == HtcctrlState_3 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_3:
|
||||
return to == HtcctrlState_4 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_4:
|
||||
return to == HtcctrlState_5 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_5:
|
||||
return to == HtcctrlState_6 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_6:
|
||||
return to == HtcctrlState_7 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_7:
|
||||
return to == HtcctrlState_8;
|
||||
case HtcctrlState_8:
|
||||
return to == HtcctrlState_9 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_9:
|
||||
return to == HtcctrlState_4 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_10:
|
||||
return to == HtcctrlState_1 || to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
case HtcctrlState_11:
|
||||
return to == HtcctrlState_0;
|
||||
case HtcctrlState_12:
|
||||
return to == HtcctrlState_10 || to == HtcctrlState_11 || to == HtcctrlState_12;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsDisconnected(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_10:
|
||||
case HtcctrlState_11:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsConnecting(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_0:
|
||||
case HtcctrlState_1:
|
||||
case HtcctrlState_10:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsConnected(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_2:
|
||||
case HtcctrlState_3:
|
||||
case HtcctrlState_4:
|
||||
case HtcctrlState_5:
|
||||
case HtcctrlState_6:
|
||||
case HtcctrlState_7:
|
||||
case HtcctrlState_8:
|
||||
case HtcctrlState_9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsReadied(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_4:
|
||||
case HtcctrlState_5:
|
||||
case HtcctrlState_6:
|
||||
case HtcctrlState_7:
|
||||
case HtcctrlState_8:
|
||||
case HtcctrlState_9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsSleeping(HtcctrlState state) {
|
||||
switch (state) {
|
||||
case HtcctrlState_5:
|
||||
case HtcctrlState_6:
|
||||
case HtcctrlState_7:
|
||||
case HtcctrlState_8:
|
||||
case HtcctrlState_9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace ams::htclow::ctrl {
|
|||
|
||||
}
|
||||
|
||||
HtcctrlStateMachine::HtcctrlStateMachine() : m_map(), m_state(HtcctrlState_Eleven), m_prev_state(HtcctrlState_Eleven), m_mutex() {
|
||||
HtcctrlStateMachine::HtcctrlStateMachine() : m_map(), m_state(HtcctrlState_11), m_prev_state(HtcctrlState_11), m_mutex() {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
|
@ -55,4 +55,127 @@ namespace ams::htclow::ctrl {
|
|||
}
|
||||
}
|
||||
|
||||
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::ResultStateTransitionNotAllowed());
|
||||
|
||||
/* 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;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
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::IsUnsupportedServiceChannelToShutdown(const impl::ChannelInternalType &channel) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* TODO: What do these values mean? */
|
||||
auto it = m_map.find(channel);
|
||||
return it != m_map.end() && it->second._04 == 2 && it->second._00 == 2;
|
||||
}
|
||||
|
||||
bool HtcctrlStateMachine::IsConnectable(const impl::ChannelInternalType &channel) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* TODO: What do these values mean? */
|
||||
auto it = m_map.find(channel);
|
||||
return ctrl::IsConnected(m_state) && (!(it != m_map.end()) || it->second._04 != 2);
|
||||
}
|
||||
|
||||
void HtcctrlStateMachine::SetNotConnecting(const impl::ChannelInternalType &channel) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
/* TODO: What do these values mean? */
|
||||
auto it = m_map.find(channel);
|
||||
if (it != m_map.end() && it->second._04 != 2) {
|
||||
it->second._04 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,27 @@ namespace ams::htclow::ctrl {
|
|||
os::SdkMutex m_mutex;
|
||||
public:
|
||||
HtcctrlStateMachine();
|
||||
|
||||
HtcctrlState GetHtcctrlState();
|
||||
Result SetHtcctrlState(bool *out_transitioned, HtcctrlState state);
|
||||
|
||||
bool IsConnectedStatusChanged();
|
||||
bool IsSleepingStatusChanged();
|
||||
|
||||
bool IsConnected();
|
||||
bool IsReadied();
|
||||
bool IsUnconnectable();
|
||||
bool IsDisconnected();
|
||||
bool IsSleeping();
|
||||
|
||||
bool IsUnsupportedServiceChannelToShutdown(const impl::ChannelInternalType &channel);
|
||||
bool IsConnectable(const impl::ChannelInternalType &channel);
|
||||
|
||||
void SetNotConnecting(const impl::ChannelInternalType &channel);
|
||||
private:
|
||||
void SetStateWithoutCheckInternal(HtcctrlState state);
|
||||
|
||||
void ClearServiceChannelStates();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue