SI_DeviceGBA: clarify request-response state machine
Inspired by "#5147: GBASockServer: remove m_device_number (fixes warning)," trying to wrap my head around how this file works.
This commit is contained in:
parent
bacc35d99e
commit
72946a40f6
|
@ -239,31 +239,28 @@ void GBASockServer::Send(const u8* si_buffer)
|
||||||
if (!GetAvailableSock(m_client))
|
if (!GetAvailableSock(m_client))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < m_send_data.size(); i++)
|
std::array<u8, 5> send_data;
|
||||||
m_send_data[i] = si_buffer[i ^ 3];
|
for (size_t i = 0; i < send_data.size(); i++)
|
||||||
|
send_data[i] = si_buffer[i ^ 3];
|
||||||
m_cmd = (u8)m_send_data[0];
|
m_cmd = send_data[0];
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
NOTICE_LOG(SERIALINTERFACE, "%01d cmd %02x [> %02x%02x%02x%02x]", m_device_number,
|
NOTICE_LOG(SERIALINTERFACE, "%01d cmd %02x [> %02x%02x%02x%02x]", m_device_number, send_data[0],
|
||||||
(u8)m_send_data[0], (u8)m_send_data[1], (u8)m_send_data[2], (u8)m_send_data[3],
|
send_data[1], send_data[2], send_data[3], send_data[4]);
|
||||||
(u8)m_send_data[4]);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_client->setBlocking(false);
|
m_client->setBlocking(false);
|
||||||
sf::Socket::Status status;
|
sf::Socket::Status status;
|
||||||
if (m_cmd == CMD_WRITE)
|
if (m_cmd == CMD_WRITE)
|
||||||
status = m_client->send(m_send_data.data(), m_send_data.size());
|
status = m_client->send(send_data.data(), send_data.size());
|
||||||
else
|
else
|
||||||
status = m_client->send(m_send_data.data(), 1);
|
status = m_client->send(send_data.data(), 1);
|
||||||
|
|
||||||
if (m_cmd != CMD_STATUS)
|
if (m_cmd != CMD_STATUS)
|
||||||
m_booted = true;
|
m_booted = true;
|
||||||
|
|
||||||
if (status == sf::Socket::Disconnected)
|
if (status == sf::Socket::Disconnected)
|
||||||
Disconnect();
|
Disconnect();
|
||||||
|
|
||||||
m_time_cmd_sent = CoreTiming::GetTicks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int GBASockServer::Receive(u8* si_buffer)
|
int GBASockServer::Receive(u8* si_buffer)
|
||||||
|
@ -272,21 +269,17 @@ int GBASockServer::Receive(u8* si_buffer)
|
||||||
if (!GetAvailableSock(m_client))
|
if (!GetAvailableSock(m_client))
|
||||||
return 5;
|
return 5;
|
||||||
|
|
||||||
size_t num_received = 0;
|
if (m_booted)
|
||||||
u64 transfer_time = GetTransferTime((u8)m_send_data[0]);
|
|
||||||
bool block = (CoreTiming::GetTicks() - m_time_cmd_sent) > transfer_time;
|
|
||||||
if (m_cmd == CMD_STATUS && !m_booted)
|
|
||||||
block = false;
|
|
||||||
|
|
||||||
if (block)
|
|
||||||
{
|
{
|
||||||
sf::SocketSelector selector;
|
sf::SocketSelector selector;
|
||||||
selector.add(*m_client);
|
selector.add(*m_client);
|
||||||
selector.wait(sf::milliseconds(1000));
|
selector.wait(sf::milliseconds(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t num_received = 0;
|
||||||
|
std::array<u8, 5> recv_data;
|
||||||
sf::Socket::Status recv_stat =
|
sf::Socket::Status recv_stat =
|
||||||
m_client->receive(m_recv_data.data(), m_recv_data.size(), num_received);
|
m_client->receive(recv_data.data(), recv_data.size(), num_received);
|
||||||
if (recv_stat == sf::Socket::Disconnected)
|
if (recv_stat == sf::Socket::Disconnected)
|
||||||
{
|
{
|
||||||
Disconnect();
|
Disconnect();
|
||||||
|
@ -296,31 +289,33 @@ int GBASockServer::Receive(u8* si_buffer)
|
||||||
if (recv_stat == sf::Socket::NotReady)
|
if (recv_stat == sf::Socket::NotReady)
|
||||||
num_received = 0;
|
num_received = 0;
|
||||||
|
|
||||||
if (num_received > m_recv_data.size())
|
if (num_received > recv_data.size())
|
||||||
num_received = m_recv_data.size();
|
num_received = recv_data.size();
|
||||||
|
|
||||||
if (num_received > 0)
|
if (num_received > 0)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if ((u8)m_send_data[0] == 0x00 || (u8)m_send_data[0] == 0xff)
|
if (m_cmd == CMD_STATUS || m_cmd == CMD_RESET)
|
||||||
{
|
{
|
||||||
WARN_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%zu)",
|
WARN_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%zu)",
|
||||||
m_device_number, (u8)m_recv_data[0], (u8)m_recv_data[1], (u8)m_recv_data[2],
|
m_device_number, recv_data[0], recv_data[1], recv_data[2], recv_data[3],
|
||||||
(u8)m_recv_data[3], (u8)m_recv_data[4], num_received);
|
recv_data[4], num_received);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%zu)",
|
ERROR_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%zu)",
|
||||||
m_device_number, (u8)m_recv_data[0], (u8)m_recv_data[1], (u8)m_recv_data[2],
|
m_device_number, recv_data[0], recv_data[1], recv_data[2], recv_data[3],
|
||||||
(u8)m_recv_data[3], (u8)m_recv_data[4], num_received);
|
recv_data[4], num_received);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t i = 0; i < m_recv_data.size(); i++)
|
for (size_t i = 0; i < recv_data.size(); i++)
|
||||||
si_buffer[i ^ 3] = m_recv_data[i];
|
{
|
||||||
|
si_buffer[i ^ 3] = recv_data[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)num_received;
|
return static_cast<int>(num_received);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSIDevice_GBA::CSIDevice_GBA(SIDevices device, int device_number)
|
CSIDevice_GBA::CSIDevice_GBA(SIDevices device, int device_number)
|
||||||
|
@ -335,38 +330,45 @@ CSIDevice_GBA::~CSIDevice_GBA()
|
||||||
|
|
||||||
int CSIDevice_GBA::RunBuffer(u8* buffer, int length)
|
int CSIDevice_GBA::RunBuffer(u8* buffer, int length)
|
||||||
{
|
{
|
||||||
if (!m_waiting_for_response)
|
switch (m_next_action)
|
||||||
|
{
|
||||||
|
case NextAction::SendCommand:
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_send_data.size(); i++)
|
|
||||||
m_send_data[i] = buffer[i ^ 3];
|
|
||||||
|
|
||||||
m_num_data_received = 0;
|
|
||||||
ClockSync();
|
ClockSync();
|
||||||
Send(buffer);
|
Send(buffer);
|
||||||
|
m_last_cmd = buffer[3];
|
||||||
m_timestamp_sent = CoreTiming::GetTicks();
|
m_timestamp_sent = CoreTiming::GetTicks();
|
||||||
m_waiting_for_response = true;
|
m_next_action = NextAction::WaitTransferTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_waiting_for_response && m_num_data_received == 0)
|
// [[fallthrough]]
|
||||||
|
case NextAction::WaitTransferTime:
|
||||||
{
|
{
|
||||||
m_num_data_received = Receive(buffer);
|
int elapsed_time = static_cast<int>(CoreTiming::GetTicks() - m_timestamp_sent);
|
||||||
|
// Tell SI to ask again after TransferInterval() cycles
|
||||||
|
if (GetTransferTime(m_last_cmd) > elapsed_time)
|
||||||
|
return 0;
|
||||||
|
m_next_action = NextAction::ReceiveResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((GetTransferTime(m_send_data[0])) > (int)(CoreTiming::GetTicks() - m_timestamp_sent))
|
// [[fallthrough]]
|
||||||
|
case NextAction::ReceiveResponse:
|
||||||
{
|
{
|
||||||
return 0;
|
int num_data_received = Receive(buffer);
|
||||||
|
if (num_data_received > 0)
|
||||||
|
m_next_action = NextAction::SendCommand;
|
||||||
|
return num_data_received;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_num_data_received != 0)
|
|
||||||
m_waiting_for_response = false;
|
|
||||||
return m_num_data_received;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should never happen, but appease MSVC which thinks it might.
|
||||||
|
ERROR_LOG(SERIALINTERFACE, "Unknown state %i\n", static_cast<int>(m_next_action));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSIDevice_GBA::TransferInterval()
|
int CSIDevice_GBA::TransferInterval()
|
||||||
{
|
{
|
||||||
return GetTransferTime(m_send_data[0]);
|
return GetTransferTime(m_last_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSIDevice_GBA::GetData(u32& hi, u32& low)
|
bool CSIDevice_GBA::GetData(u32& hi, u32& low)
|
||||||
|
|
|
@ -36,10 +36,7 @@ public:
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sf::TcpSocket> m_client;
|
std::unique_ptr<sf::TcpSocket> m_client;
|
||||||
std::unique_ptr<sf::TcpSocket> m_clock_sync;
|
std::unique_ptr<sf::TcpSocket> m_clock_sync;
|
||||||
std::array<char, 5> m_send_data{};
|
|
||||||
std::array<char, 5> m_recv_data{};
|
|
||||||
|
|
||||||
u64 m_time_cmd_sent = 0;
|
|
||||||
u64 m_last_time_slice = 0;
|
u64 m_last_time_slice = 0;
|
||||||
int m_device_number;
|
int m_device_number;
|
||||||
u8 m_cmd = 0;
|
u8 m_cmd = 0;
|
||||||
|
@ -58,9 +55,15 @@ public:
|
||||||
void SendCommand(u32 command, u8 poll) override;
|
void SendCommand(u32 command, u8 poll) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<u8, 5> m_send_data{};
|
enum class NextAction
|
||||||
int m_num_data_received = 0;
|
{
|
||||||
|
SendCommand,
|
||||||
|
WaitTransferTime,
|
||||||
|
ReceiveResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
NextAction m_next_action = NextAction::SendCommand;
|
||||||
|
u8 m_last_cmd;
|
||||||
u64 m_timestamp_sent = 0;
|
u64 m_timestamp_sent = 0;
|
||||||
bool m_waiting_for_response = false;
|
|
||||||
};
|
};
|
||||||
} // namespace SerialInterface
|
} // namespace SerialInterface
|
||||||
|
|
Loading…
Reference in New Issue