Skip to content
Permalink
Browse files

SI: Clarify length fields for manual commands

Fix up the calculation of the length fields and check that the returned
response is the expected length. This touches many files because it
converts a parameter name from the SI_Device interface from 'length' to
'request_length'. Prior, this field seemed to be used as request length
sometimes, as response length sometimes, and usually just totally ignored.
  • Loading branch information...
booto committed Jul 11, 2019
1 parent d01220e commit 62a2611925b3ffa8e3e36201a7ed46fd9ac6d843
@@ -8,7 +8,9 @@
#include <array>
#include <atomic>
#include <cstring>
#include <iomanip>
#include <memory>
#include <sstream>

#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
@@ -280,31 +282,51 @@ static void GenerateSIInterrupt(SIInterruptType type)
UpdateInterrupts();
}

constexpr u32 SI_XFER_LENGTH_MASK = 0x7f;

// Translate [0,1,2,...,126,127] to [128,1,2,...,126,127]
constexpr u32 ConvertSILengthField(u32 field)
{
return ((field - 1) & SI_XFER_LENGTH_MASK) + 1;
}

static void RunSIBuffer(u64 user_data, s64 cycles_late)
{
if (s_com_csr.TSTART)
{
// Math in_length
int in_length = s_com_csr.INLNGTH;
if (in_length == 0)
in_length = 128;
else
in_length++;

// Math out_length
int out_length = s_com_csr.OUTLNGTH;
if (out_length == 0)
out_length = 128;
else
out_length++;
u32 request_length = ConvertSILengthField(s_com_csr.OUTLNGTH);
u32 expected_response_length = ConvertSILengthField(s_com_csr.INLNGTH);
std::vector<u8> request_copy(s_si_buffer.data(), s_si_buffer.data() + request_length);

std::unique_ptr<ISIDevice>& device = s_channel[s_com_csr.CHANNEL].device;
int numOutput = device->RunBuffer(s_si_buffer.data(), in_length);
u32 actual_response_length = device->RunBuffer(s_si_buffer.data(), request_length);

DEBUG_LOG(SERIALINTERFACE, "RunSIBuffer chan: %d inLen: %i outLen: %i processed: %i",
s_com_csr.CHANNEL, in_length, out_length, numOutput);
DEBUG_LOG(SERIALINTERFACE,
"RunSIBuffer chan: %d request_length: %u expected_response_length: %u "
"actual_response_length: %u",
s_com_csr.CHANNEL, request_length, expected_response_length, actual_response_length);
if (expected_response_length != actual_response_length)
{
std::stringstream ss;
for (u8 b : request_copy)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)b << ' ';
}
ERROR_LOG(
SERIALINTERFACE,
"RunSIBuffer: expected_response_length(%u) != actual_response_length(%u): request: %s",
expected_response_length, actual_response_length, ss.str().c_str());
}

if (numOutput != 0)
// TODO:
// 1) Wait a reasonable amount of time for the result to be available:
// request is N bytes, ends with a stop bit
// response in M bytes, ends with a stop bit
// processing controller-side takes K us (investigate?)
// each bit takes 4us ([3us low/1us high] for a 0, [1us low/3us high] for a 1)
// time until response is available is at least: K + ((N*8 + 1) + (M*8 + 1)) * 4 us
// 2) Investigate the timeout period for NOREP0
if (actual_response_length != 0)
{
s_com_csr.TSTART = 0;
GenerateSIInterrupt(INT_TCINT);
@@ -37,15 +37,16 @@ SIDevices ISIDevice::GetDeviceType() const
return m_device_type;
}

int ISIDevice::RunBuffer(u8* buffer, int length)
int ISIDevice::RunBuffer(u8* buffer, int request_length)
{
#ifdef _DEBUG
DEBUG_LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", m_device_number, length);
DEBUG_LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", m_device_number,
request_length);

std::string temp;
int num = 0;

while (num < length)
while (num < request_length)
{
temp += StringFromFormat("0x%02x ", buffer[num]);
num++;
@@ -73,7 +73,7 @@ class ISIDevice
SIDevices GetDeviceType() const;

// Run the SI Buffer
virtual int RunBuffer(u8* buffer, int length);
virtual int RunBuffer(u8* buffer, int request_length);
virtual int TransferInterval();

// Return true on new data
@@ -17,24 +17,19 @@ CSIDevice_DanceMat::CSIDevice_DanceMat(SIDevices device, int device_number)
{
}

int CSIDevice_DanceMat::RunBuffer(u8* buffer, int length)
int CSIDevice_DanceMat::RunBuffer(u8* buffer, int request_length)
{
// Read the command
EBufferCommands command = static_cast<EBufferCommands>(buffer[0]);

if (command == CMD_RESET)
{
ISIDevice::RunBuffer(buffer, length);
ISIDevice::RunBuffer(buffer, request_length);

u32 id = Common::swap32(SI_DANCEMAT);
std::memcpy(buffer, &id, sizeof(id));
return sizeof(id);
}
else
{
return CSIDevice_GCController::RunBuffer(buffer, length);
}

return length;
return CSIDevice_GCController::RunBuffer(buffer, request_length);
}

u32 CSIDevice_DanceMat::MapPadStatus(const GCPadStatus& pad_status)
@@ -16,7 +16,7 @@ class CSIDevice_DanceMat : public CSIDevice_GCController
public:
CSIDevice_DanceMat(SIDevices device, int device_number);

int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;
u32 MapPadStatus(const GCPadStatus& pad_status) override;
bool GetData(u32& hi, u32& low) override;
};
@@ -290,7 +290,7 @@ CSIDevice_GBA::CSIDevice_GBA(SIDevices device, int device_number) : ISIDevice(de
{
}

int CSIDevice_GBA::RunBuffer(u8* buffer, int length)
int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
{
switch (m_next_action)
{
@@ -45,7 +45,7 @@ class CSIDevice_GBA : public ISIDevice
public:
CSIDevice_GBA(SIDevices device, int device_number);

int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;
int TransferInterval() override;
bool GetData(u32& hi, u32& low) override;
void SendCommand(u32 command, u8 poll) override;
@@ -49,7 +49,7 @@ GCPadStatus CSIDevice_GCAdapter::GetPadStatus()
return pad_status;
}

int CSIDevice_GCAdapter::RunBuffer(u8* buffer, int length)
int CSIDevice_GCAdapter::RunBuffer(u8* buffer, int request_length)
{
if (!Core::WantsDeterminism())
{
@@ -66,7 +66,7 @@ int CSIDevice_GCAdapter::RunBuffer(u8* buffer, int length)
return 4;
}
}
return CSIDevice_GCController::RunBuffer(buffer, length);
return CSIDevice_GCController::RunBuffer(buffer, request_length);
}

bool CSIDevice_GCAdapter::GetData(u32& hi, u32& low)
@@ -16,7 +16,7 @@ class CSIDevice_GCAdapter : public CSIDevice_GCController
CSIDevice_GCAdapter(SIDevices device, int device_number);

GCPadStatus GetPadStatus() override;
int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;

bool GetData(u32& hi, u32& low) override;

@@ -36,17 +36,17 @@ CSIDevice_GCController::CSIDevice_GCController(SIDevices device, int device_numb
m_origin.substick_y = GCPadStatus::C_STICK_CENTER_Y;
}

int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
int CSIDevice_GCController::RunBuffer(u8* buffer, int request_length)
{
// For debug logging only
ISIDevice::RunBuffer(buffer, length);
ISIDevice::RunBuffer(buffer, request_length);

GCPadStatus pad_status = GetPadStatus();
if (!pad_status.isConnected)
{
u32 reply = Common::swap32(SI_ERROR_NO_RESPONSE);
std::memcpy(buffer, &reply, sizeof(reply));
return 4;
return sizeof(reply);
}

// Read the command
@@ -60,21 +60,21 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
{
u32 id = Common::swap32(SI_GC_CONTROLLER);
std::memcpy(buffer, &id, sizeof(id));
break;
return sizeof(id);
}

case CMD_DIRECT:
{
INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", length);
INFO_LOG(SERIALINTERFACE, "PAD - Direct (Request length: %d)", request_length);
u32 high, low;
GetData(high, low);
for (int i = 0; i < (length - 1) / 2; i++)
for (int i = 0; i < 4; i++)
{
buffer[i + 0] = (high >> (24 - (i * 8))) & 0xff;
buffer[i + 4] = (low >> (24 - (i * 8))) & 0xff;
}
return sizeof(high) + sizeof(low);
}
break;

case CMD_ORIGIN:
{
@@ -85,8 +85,8 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
{
buffer[i] = *calibration++;
}
return sizeof(SOrigin);
}
break;

// Recalibrate (FiRES: i am not 100 percent sure about this)
case CMD_RECALIBRATE:
@@ -98,8 +98,8 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
{
buffer[i] = *calibration++;
}
return sizeof(SOrigin);
}
break;

// DEFAULT
default:
@@ -110,7 +110,7 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
break;
}

return length;
return 0;
}

void CSIDevice_GCController::HandleMoviePadStatus(GCPadStatus* pad_status)
@@ -84,7 +84,7 @@ class CSIDevice_GCController : public ISIDevice
CSIDevice_GCController(SIDevices device, int device_number);

// Run the SI Buffer
int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;

// Return true on new data
bool GetData(u32& hi, u32& low) override;
@@ -20,10 +20,10 @@ CSIDevice_GCSteeringWheel::CSIDevice_GCSteeringWheel(SIDevices device, int devic
{
}

int CSIDevice_GCSteeringWheel::RunBuffer(u8* buffer, int length)
int CSIDevice_GCSteeringWheel::RunBuffer(u8* buffer, int request_length)
{
// For debug logging only
ISIDevice::RunBuffer(buffer, length);
ISIDevice::RunBuffer(buffer, request_length);

// Read the command
EBufferCommands command = static_cast<EBufferCommands>(buffer[0]);
@@ -36,14 +36,11 @@ int CSIDevice_GCSteeringWheel::RunBuffer(u8* buffer, int length)
{
u32 id = Common::swap32(SI_GC_STEERING);
std::memcpy(buffer, &id, sizeof(id));
break;
return sizeof(id);
}

default:
return CSIDevice_GCController::RunBuffer(buffer, length);
}

return length;
return CSIDevice_GCController::RunBuffer(buffer, request_length);
}

bool CSIDevice_GCSteeringWheel::GetData(u32& hi, u32& low)
@@ -13,7 +13,7 @@ class CSIDevice_GCSteeringWheel : public CSIDevice_GCController
public:
CSIDevice_GCSteeringWheel(SIDevices device, int device_number);

int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;
bool GetData(u32& hi, u32& low) override;
void SendCommand(u32 command, u8 poll) override;

@@ -21,10 +21,10 @@ CSIDevice_Keyboard::CSIDevice_Keyboard(SIDevices device, int device_number)
{
}

int CSIDevice_Keyboard::RunBuffer(u8* buffer, int length)
int CSIDevice_Keyboard::RunBuffer(u8* buffer, int request_length)
{
// For debug logging only
ISIDevice::RunBuffer(buffer, length);
ISIDevice::RunBuffer(buffer, request_length);

// Read the command
EBufferCommands command = static_cast<EBufferCommands>(buffer[0]);
@@ -37,21 +37,21 @@ int CSIDevice_Keyboard::RunBuffer(u8* buffer, int length)
{
u32 id = Common::swap32(SI_GC_KEYBOARD);
std::memcpy(buffer, &id, sizeof(id));
break;
return sizeof(id);
}

case CMD_DIRECT:
{
INFO_LOG(SERIALINTERFACE, "Keyboard - Direct (Length: %d)", length);
INFO_LOG(SERIALINTERFACE, "Keyboard - Direct (Request Length: %d)", request_length);
u32 high, low;
GetData(high, low);
for (int i = 0; i < (length - 1) / 2; i++)
for (int i = 0; i < 4; i++)
{
buffer[i + 0] = (high >> (24 - (i * 8))) & 0xff;
buffer[i + 4] = (low >> (24 - (i * 8))) & 0xff;
}
return sizeof(high) + sizeof(low);
}
break;

default:
{
@@ -60,7 +60,7 @@ int CSIDevice_Keyboard::RunBuffer(u8* buffer, int length)
break;
}

return length;
return 0;
}

KeyboardStatus CSIDevice_Keyboard::GetKeyboardStatus() const
@@ -18,7 +18,7 @@ class CSIDevice_Keyboard : public ISIDevice
CSIDevice_Keyboard(SIDevices device, int device_number);

// Run the SI Buffer
int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;

// Return true on new data
bool GetData(u32& hi, u32& low) override;
@@ -14,11 +14,11 @@ CSIDevice_Null::CSIDevice_Null(SIDevices device, int device_number)
{
}

int CSIDevice_Null::RunBuffer(u8* buffer, int length)
int CSIDevice_Null::RunBuffer(u8* buffer, int request_length)
{
u32 reply = Common::swap32(SI_ERROR_NO_RESPONSE);
std::memcpy(buffer, &reply, sizeof(reply));
return 4;
return sizeof(reply);
}

bool CSIDevice_Null::GetData(u32& hi, u32& low)
@@ -15,7 +15,7 @@ class CSIDevice_Null final : public ISIDevice
public:
CSIDevice_Null(SIDevices device, int device_number);

int RunBuffer(u8* buffer, int length) override;
int RunBuffer(u8* buffer, int request_length) override;
bool GetData(u32& hi, u32& low) override;
void SendCommand(u32 command, u8 poll) override;
};

0 comments on commit 62a2611

Please sign in to comment.
You can’t perform that action at this time.