htc: implement remainder of Mux/Tasks

This commit is contained in:
Michael Scire
2021-02-09 19:51:52 -08:00
committed by SciresM
parent 42cf3f50d7
commit b925344c3b
13 changed files with 291 additions and 24 deletions

View File

@@ -24,7 +24,7 @@ namespace ams::htclow::mux {
ChannelImpl::ChannelImpl(impl::ChannelInternalType channel, PacketFactory *pf, ctrl::HtcctrlStateMachine *sm, TaskManager *tm, os::Event *ev)
: m_channel(channel), m_packet_factory(pf), m_state_machine(sm), m_task_manager(tm), m_event(ev),
m_send_buffer(m_channel, pf), m_receive_buffer(), m_version(ProtocolVersion), m_config(DefaultChannelConfig),
m_offset(0), m_total_send_size(0), m_next_max_data(0), m_cur_max_data(0), m_share(),
m_offset(0), m_total_send_size(0), m_cur_max_data(0), m_prev_max_data(0), m_share(),
m_state_change_event(os::EventClearMode_ManualClear), m_state(ChannelState_Unconnectable)
{
@@ -146,10 +146,10 @@ namespace ams::htclow::mux {
bool ChannelImpl::QuerySendPacket(PacketHeader *header, PacketBody *body, int *out_body_size) {
/* Check our send buffer. */
if (m_send_buffer.QueryNextPacket(header, body, out_body_size, m_next_max_data, m_total_send_size, m_share.has_value(), m_share.value_or(0))) {
if (m_send_buffer.QueryNextPacket(header, body, out_body_size, m_cur_max_data, m_total_send_size, m_share.has_value(), m_share.value_or(0))) {
/* Update tracking variables. */
if (header->packet_type == PacketType_Data) {
m_cur_max_data = m_next_max_data;
m_prev_max_data = m_cur_max_data;
}
return true;
@@ -259,11 +259,11 @@ namespace ams::htclow::mux {
/* Perform handshake, if we should. */
if (m_config.handshake_enabled) {
/* Set our next max data. */
m_next_max_data = m_receive_buffer.GetBufferSize();
/* Set our current max data. */
m_cur_max_data = m_receive_buffer.GetBufferSize();
/* Make a max data packet. */
auto packet = m_packet_factory->MakeMaxDataPacket(m_channel, m_version, m_next_max_data);
auto packet = m_packet_factory->MakeMaxDataPacket(m_channel, m_version, m_cur_max_data);
R_UNLESS(packet, htclow::ResultOutOfMemory());
/* Send the packet. */
@@ -272,8 +272,8 @@ namespace ams::htclow::mux {
/* Signal that we have an packet to send. */
this->SignalSendPacketEvent();
/* Set our current max data. */
m_cur_max_data = m_next_max_data;
/* Set our prev max data. */
m_prev_max_data = m_cur_max_data;
} else {
/* Set our share. */
m_share = m_config.initial_counter_max_data;
@@ -290,6 +290,141 @@ namespace ams::htclow::mux {
return ResultSuccess();
}
Result ChannelImpl::DoFlush(u32 *out_task_id) {
/* Check our state. */
R_TRY(this->CheckState({ChannelState_Connected}));
/* Allocate a task. */
u32 task_id;
R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel));
/* Configure the task. */
m_task_manager->ConfigureFlushTask(task_id);
/* If we're already flushed, complete the task immediately. */
if (m_send_buffer.Empty()) {
m_task_manager->CompleteTask(task_id, EventTrigger_SendBufferEmpty);
}
/* Set the output task id. */
*out_task_id = task_id;
return ResultSuccess();
}
Result ChannelImpl::DoReceiveBegin(u32 *out_task_id, size_t size) {
/* Check our state. */
R_TRY(this->CheckState({ChannelState_Connected, ChannelState_Disconnected}));
/* Allocate a task. */
u32 task_id;
R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel));
/* Configure the task. */
m_task_manager->ConfigureReceiveTask(task_id, size);
/* Check if the task is already complete. */
if (m_receive_buffer.GetDataSize() >= size) {
m_task_manager->CompleteTask(task_id, EventTrigger_ReceiveData);
} else if (m_state == ChannelState_Disconnected) {
m_task_manager->CompleteTask(task_id, EventTrigger_Disconnect);
}
/* Set the output task id. */
*out_task_id = task_id;
return ResultSuccess();
}
Result ChannelImpl::DoReceiveEnd(size_t *out, void *dst, size_t dst_size) {
/* Check our state. */
R_TRY(this->CheckState({ChannelState_Connected, ChannelState_Disconnected}));
/* If we have nowhere to receive, we're done. */
if (dst_size == 0) {
*out = 0;
return ResultSuccess();
}
/* Get the amount of receivable data. */
const size_t receivable = m_receive_buffer.GetDataSize();
const size_t received = std::min(dst_size, receivable);
/* Read the data. */
R_ABORT_UNLESS(m_receive_buffer.Read(dst, received));
/* Handle flow control, if we should. */
if (m_config.flow_control_enabled) {
/* Read our fields. */
const auto prev_max_data = m_prev_max_data;
const auto next_max_data = m_cur_max_data + received;
const auto max_packet_size = m_config.max_packet_size;
const auto offset = m_offset;
/* Update our current max data. */
m_cur_max_data = next_max_data;
/* If we can, send a max data packet. */
if (prev_max_data - offset < max_packet_size + sizeof(PacketHeader)) {
/* Make a max data packet. */
auto packet = m_packet_factory->MakeMaxDataPacket(m_channel, m_version, next_max_data);
R_UNLESS(packet, htclow::ResultOutOfMemory());
/* Send the packet. */
m_send_buffer.AddPacket(std::move(packet));
/* Signal that we have an packet to send. */
this->SignalSendPacketEvent();
/* Set our prev max data. */
m_prev_max_data = m_cur_max_data;
}
}
/* Set the output size. */
*out = received;
return ResultSuccess();
}
Result ChannelImpl::DoSend(u32 *out_task_id, size_t *out, const void *src, size_t src_size) {
/* Check our state. */
R_TRY(this->CheckState({ChannelState_Connected}));
/* Allocate a task. */
u32 task_id;
R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel));
/* Send the data. */
const size_t sent = m_send_buffer.AddData(src, src_size);
/* Add the size to our total. */
m_total_send_size += sent;
/* Signal our event. */
this->SignalSendPacketEvent();
/* Configure the task. */
m_task_manager->ConfigureSendTask(task_id);
/* If we sent all the data, we're done. */
if (sent == src_size) {
m_task_manager->CompleteTask(task_id, EventTrigger_SendComplete);
}
/* Set the output. */
*out_task_id = task_id;
*out = sent;
return ResultSuccess();
}
Result ChannelImpl::DoShutdown() {
/* Check our state. */
R_TRY(this->CheckState({ChannelState_Connected}));
/* Set our state. */
this->SetState(ChannelState_Disconnected);
return ResultSuccess();
}
void ChannelImpl::SetSendBuffer(void *buf, size_t buf_size, size_t max_packet_size) {
/* Set buffer. */
m_send_buffer.SetBuffer(buf, buf_size);