htc: implement remaining worker thread send logic (for channel mux)

This commit is contained in:
Michael Scire
2021-02-09 03:21:45 -08:00
committed by SciresM
parent df3d62df84
commit 4ed665bcd3
14 changed files with 346 additions and 13 deletions

View File

@@ -15,6 +15,7 @@
*/
#include <stratosphere.hpp>
#include "htclow_mux.hpp"
#include "../htclow_packet_factory.hpp"
#include "../ctrl/htclow_ctrl_state_machine.hpp"
namespace ams::htclow::mux {
@@ -22,7 +23,7 @@ namespace ams::htclow::mux {
Mux::Mux(PacketFactory *pf, ctrl::HtcctrlStateMachine *sm)
: m_packet_factory(pf), m_state_machine(sm), m_task_manager(), m_event(os::EventClearMode_ManualClear),
m_channel_impl_map(pf, sm, std::addressof(m_task_manager), std::addressof(m_event)), m_global_send_buffer(pf),
m_mutex(), m_is_sleeping(false), m_version(ProtocolVersion)
m_mutex(), m_state(MuxState::Normal), m_version(ProtocolVersion)
{
/* ... */
}
@@ -78,6 +79,50 @@ namespace ams::htclow::mux {
}
}
bool Mux::QuerySendPacket(PacketHeader *header, PacketBody *body, int *out_body_size) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Get our map. */
auto &map = m_channel_impl_map.GetMap();
/* Iterate the map, checking for valid packet each time. */
for (auto &pair : map) {
/* Get the current channel impl. */
auto &channel_impl = m_channel_impl_map.GetChannelImpl(pair.second);
/* Check for an error packet. */
/* NOTE: it's unclear why Nintendo does this every iteration of the loop... */
if (auto *error_packet = m_global_send_buffer.GetNextPacket(); error_packet != nullptr) {
std::memcpy(header, error_packet->GetHeader(), sizeof(*header));
*out_body_size = 0;
return true;
}
/* See if the channel has something for us to send. */
if (channel_impl.QuerySendPacket(header, body, out_body_size)) {
return this->IsSendable(header->packet_type);
}
}
return false;
}
void Mux::RemovePacket(const PacketHeader &header) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Remove the packet from the appropriate source. */
if (header.packet_type == PacketType_Error) {
m_global_send_buffer.RemovePacket();
} else if (m_channel_impl_map.Exists(header.channel)) {
m_channel_impl_map[header.channel].RemovePacket(header);
}
/* Notify the task manager. */
m_task_manager.NotifySendReady();
}
void Mux::UpdateChannelState() {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
@@ -95,9 +140,9 @@ namespace ams::htclow::mux {
/* Update whether we're sleeping. */
if (m_state_machine->IsSleeping()) {
m_is_sleeping = true;
m_state = MuxState::Sleep;
} else {
m_is_sleeping = false;
m_state = MuxState::Normal;
m_event.Signal();
}
}
@@ -108,8 +153,23 @@ namespace ams::htclow::mux {
}
Result Mux::SendErrorPacket(impl::ChannelInternalType channel) {
/* TODO */
AMS_ABORT("Mux::SendErrorPacket");
/* Create and send the packet. */
R_TRY(m_global_send_buffer.AddPacket(m_packet_factory->MakeErrorPacket(channel)));
/* Signal our event. */
m_event.Signal();
return ResultSuccess();
}
bool Mux::IsSendable(PacketType packet_type) const {
switch (m_state) {
case MuxState::Normal:
return true;
case MuxState::Sleep:
return false;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
}