New code style refactor

This commit is contained in:
Jack Andersen 2018-12-07 19:20:55 -10:00
parent 500f88d7a7
commit e28b6551d0
10 changed files with 1821 additions and 2146 deletions

View File

@ -4,8 +4,7 @@
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
namespace jbus namespace jbus {
{
using s8 = int8_t; using s8 = int8_t;
using u8 = uint8_t; using u8 = uint8_t;
@ -24,8 +23,7 @@ using u64 = uint64_t;
/* Type-sensitive byte swappers */ /* Type-sensitive byte swappers */
template <typename T> template <typename T>
static inline T bswap16(T val) static inline T bswap16(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap16(val); return __builtin_bswap16(val);
#elif _WIN32 #elif _WIN32
@ -36,8 +34,7 @@ static inline T bswap16(T val)
} }
template <typename T> template <typename T>
static inline T bswap32(T val) static inline T bswap32(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap32(val); return __builtin_bswap32(val);
#elif _WIN32 #elif _WIN32
@ -50,88 +47,76 @@ static inline T bswap32(T val)
} }
template <typename T> template <typename T>
static inline T bswap64(T val) static inline T bswap64(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap64(val); return __builtin_bswap64(val);
#elif _WIN32 #elif _WIN32
return _byteswap_uint64(val); return _byteswap_uint64(val);
#else #else
return ((val & 0xFF00000000000000ULL) >> 56) | return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
((val & 0x00FF000000000000ULL) >> 40) | ((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000FF00000000ULL) >> 8) | ((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
((val & 0x00000000FF000000ULL) << 8) |
((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000000000FF00ULL) << 40) |
((val & 0x00000000000000FFULL) << 56);
#endif #endif
} }
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static inline int16_t SBig(int16_t val) {return bswap16(val);} static inline int16_t SBig(int16_t val) { return bswap16(val); }
static inline uint16_t SBig(uint16_t val) {return bswap16(val);} static inline uint16_t SBig(uint16_t val) { return bswap16(val); }
static inline int32_t SBig(int32_t val) {return bswap32(val);} static inline int32_t SBig(int32_t val) { return bswap32(val); }
static inline uint32_t SBig(uint32_t val) {return bswap32(val);} static inline uint32_t SBig(uint32_t val) { return bswap32(val); }
static inline int64_t SBig(int64_t val) {return bswap64(val);} static inline int64_t SBig(int64_t val) { return bswap64(val); }
static inline uint64_t SBig(uint64_t val) {return bswap64(val);} static inline uint64_t SBig(uint64_t val) { return bswap64(val); }
static inline float SBig(float val) static inline float SBig(float val) {
{
int32_t ival = bswap32(*((int32_t*)(&val))); int32_t ival = bswap32(*((int32_t*)(&val)));
return *((float*)(&ival)); return *((float*)(&ival));
} }
static inline double SBig(double val) static inline double SBig(double val) {
{
int64_t ival = bswap64(*((int64_t*)(&val))); int64_t ival = bswap64(*((int64_t*)(&val)));
return *((double*)(&ival)); return *((double*)(&ival));
} }
#ifndef SBIG #ifndef SBIG
#define SBIG(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \ #define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
#endif #endif
static inline int16_t SLittle(int16_t val) {return val;} static inline int16_t SLittle(int16_t val) { return val; }
static inline uint16_t SLittle(uint16_t val) {return val;} static inline uint16_t SLittle(uint16_t val) { return val; }
static inline int32_t SLittle(int32_t val) {return val;} static inline int32_t SLittle(int32_t val) { return val; }
static inline uint32_t SLittle(uint32_t val) {return val;} static inline uint32_t SLittle(uint32_t val) { return val; }
static inline int64_t SLittle(int64_t val) {return val;} static inline int64_t SLittle(int64_t val) { return val; }
static inline uint64_t SLittle(uint64_t val) {return val;} static inline uint64_t SLittle(uint64_t val) { return val; }
static inline float SLittle(float val) {return val;} static inline float SLittle(float val) { return val; }
static inline double SLittle(double val) {return val;} static inline double SLittle(double val) { return val; }
#ifndef SLITTLE #ifndef SLITTLE
#define SLITTLE(q) (q) #define SLITTLE(q) (q)
#endif #endif
#else #else
static inline int16_t SLittle(int16_t val) {return bswap16(val);} static inline int16_t SLittle(int16_t val) { return bswap16(val); }
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);} static inline uint16_t SLittle(uint16_t val) { return bswap16(val); }
static inline int32_t SLittle(int32_t val) {return bswap32(val);} static inline int32_t SLittle(int32_t val) { return bswap32(val); }
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);} static inline uint32_t SLittle(uint32_t val) { return bswap32(val); }
static inline int64_t SLittle(int64_t val) {return bswap64(val);} static inline int64_t SLittle(int64_t val) { return bswap64(val); }
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);} static inline uint64_t SLittle(uint64_t val) { return bswap64(val); }
static inline float SLittle(float val) static inline float SLittle(float val) {
{
int32_t ival = bswap32(*((int32_t*)(&val))); int32_t ival = bswap32(*((int32_t*)(&val)));
return *((float*)(&ival)); return *((float*)(&ival));
} }
static inline double SLittle(double val) static inline double SLittle(double val) {
{
int64_t ival = bswap64(*((int64_t*)(&val))); int64_t ival = bswap64(*((int64_t*)(&val)));
return *((double*)(&ival)); return *((double*)(&ival));
} }
#ifndef SLITTLE #ifndef SLITTLE
#define SLITTLE(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \ #define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
#endif #endif
static inline int16_t SBig(int16_t val) {return val;} static inline int16_t SBig(int16_t val) { return val; }
static inline uint16_t SBig(uint16_t val) {return val;} static inline uint16_t SBig(uint16_t val) { return val; }
static inline int32_t SBig(int32_t val) {return val;} static inline int32_t SBig(int32_t val) { return val; }
static inline uint32_t SBig(uint32_t val) {return val;} static inline uint32_t SBig(uint32_t val) { return val; }
static inline int64_t SBig(int64_t val) {return val;} static inline int64_t SBig(int64_t val) { return val; }
static inline uint64_t SBig(uint64_t val) {return val;} static inline uint64_t SBig(uint64_t val) { return val; }
static inline float SBig(float val) {return val;} static inline float SBig(float val) { return val; }
static inline double SBig(double val) {return val;} static inline double SBig(double val) { return val; }
#ifndef SBIG #ifndef SBIG
#define SBIG(q) (q) #define SBIG(q) (q)
#endif #endif
@ -142,8 +127,7 @@ class ThreadLocalEndpoint;
#endif #endif
enum EJStatFlags enum EJStatFlags {
{
GBA_JSTAT_MASK = 0x3a, GBA_JSTAT_MASK = 0x3a,
GBA_JSTAT_FLAGS_SHIFT = 4, GBA_JSTAT_FLAGS_SHIFT = 4,
GBA_JSTAT_FLAGS_MASK = 0x30, GBA_JSTAT_FLAGS_MASK = 0x30,
@ -153,8 +137,7 @@ enum EJStatFlags
GBA_JSTAT_RECV = 0x02 GBA_JSTAT_RECV = 0x02
}; };
enum EJoyReturn enum EJoyReturn {
{
GBA_READY = 0, GBA_READY = 0,
GBA_NOT_READY = 1, GBA_NOT_READY = 1,
GBA_BUSY = 2, GBA_BUSY = 2,
@ -182,5 +165,4 @@ static constexpr u64 GetGCTicksPerSec() { return 486000000ull; }
/** @brief Initialize platform specifics of JBus library */ /** @brief Initialize platform specifics of JBus library */
void Initialize(); void Initialize();
} } // namespace jbus

View File

@ -6,25 +6,21 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
namespace jbus namespace jbus {
{
/** Main class for performing JoyBoot and subsequent JoyBus I/O operations. /** Main class for performing JoyBoot and subsequent JoyBus I/O operations.
* Instances should be obtained though the jbus::Listener::accept method. */ * Instances should be obtained though the jbus::Listener::accept method. */
class Endpoint class Endpoint {
{
/** Self-contained class for solving Kawasedo's GBA BootROM challenge. /** Self-contained class for solving Kawasedo's GBA BootROM challenge.
* GBA will boot client_pad.bin code on completion. * GBA will boot client_pad.bin code on completion.
* *
* This class shouldn't be used directly. JoyBoot operations are started * This class shouldn't be used directly. JoyBoot operations are started
* via jbus::Endpoint::GBAJoyBootAsync. The JoyBoot status may be obtained * via jbus::Endpoint::GBAJoyBootAsync. The JoyBoot status may be obtained
* via jbus::Endpoint::GBAGetProcessStatus. */ * via jbus::Endpoint::GBAGetProcessStatus. */
class KawasedoChallenge class KawasedoChallenge {
{
/** DSP-hosted public-key unwrap and initial message crypt /** DSP-hosted public-key unwrap and initial message crypt
* Reference: https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp */ * Reference: https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp */
struct DSPSecParms struct DSPSecParms {
{
/* Nonce challenge (first read from GBA, hence already little-endian) */ /* Nonce challenge (first read from GBA, hence already little-endian) */
u32 x0_gbaChallenge; u32 x0_gbaChallenge;
@ -79,19 +75,17 @@ class Endpoint
void _7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status);
auto bindThis(void(KawasedoChallenge::*ptmf)(ThreadLocalEndpoint&, EJoyReturn)) auto bindThis(void (KawasedoChallenge::*ptmf)(ThreadLocalEndpoint&, EJoyReturn)) {
{
return std::bind(ptmf, this, std::placeholders::_1, std::placeholders::_2); return std::bind(ptmf, this, std::placeholders::_1, std::placeholders::_2);
} }
public: public:
KawasedoChallenge() = default; KawasedoChallenge() = default;
KawasedoChallenge(s32 paletteColor, s32 paletteSpeed, KawasedoChallenge(s32 paletteColor, s32 paletteSpeed, const u8* programp, s32 length, u8* status,
const u8* programp, s32 length, u8* status, FGBACallback&& callback); FGBACallback&& callback);
void start(Endpoint& endpoint); void start(Endpoint& endpoint);
bool started() const { return m_started; } bool started() const { return m_started; }
u8 percentComplete() const u8 percentComplete() const {
{
if (!x64_totalBytes) if (!x64_totalBytes)
return 0; return 0;
return x34_bytesSent * 100 / x64_totalBytes; return x34_bytesSent * 100 / x64_totalBytes;
@ -102,13 +96,7 @@ class Endpoint
friend class ThreadLocalEndpoint; friend class ThreadLocalEndpoint;
enum EJoybusCmds enum EJoybusCmds { CMD_RESET = 0xff, CMD_STATUS = 0x00, CMD_READ = 0x14, CMD_WRITE = 0x15 };
{
CMD_RESET = 0xff,
CMD_STATUS = 0x00,
CMD_READ = 0x14,
CMD_WRITE = 0x15
};
static const u64 BITS_PER_SECOND = 115200; static const u64 BITS_PER_SECOND = 115200;
static const u64 BYTES_PER_SECOND = BITS_PER_SECOND / 8; static const u64 BYTES_PER_SECOND = BITS_PER_SECOND / 8;
@ -139,11 +127,7 @@ class Endpoint
void transferProc(); void transferProc();
void transferWakeup(ThreadLocalEndpoint& endpoint, u8 status); void transferWakeup(ThreadLocalEndpoint& endpoint, u8 status);
auto bindSync() auto bindSync() { return std::bind(&Endpoint::transferWakeup, this, std::placeholders::_1, std::placeholders::_2); }
{
return std::bind(&Endpoint::transferWakeup, this,
std::placeholders::_1, std::placeholders::_2);
}
public: public:
/** @brief Request stop of I/O thread and block until joined. /** @brief Request stop of I/O thread and block until joined.
@ -212,8 +196,7 @@ public:
* @param status Destination pointer for EJStatFlags. * @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes. * @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */ * @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed, EJoyReturn GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed, const u8* programp, s32 length, u8* status,
const u8* programp, s32 length, u8* status,
FGBACallback&& callback); FGBACallback&& callback);
/** @brief Get virtual SI channel assigned to this endpoint. /** @brief Get virtual SI channel assigned to this endpoint.
@ -222,8 +205,7 @@ public:
/** @brief Set virtual SI channel assigned to this endpoint. /** @brief Set virtual SI channel assigned to this endpoint.
* @param chan SI channel [0,3] */ * @param chan SI channel [0,3] */
void setChan(unsigned chan) void setChan(unsigned chan) {
{
if (chan > 3) if (chan > 3)
chan = 3; chan = 3;
m_chan = chan; m_chan = chan;
@ -240,8 +222,7 @@ public:
/** Lockless wrapper interface for jbus::Endpoint. /** Lockless wrapper interface for jbus::Endpoint.
* This class is constructed internally and supplied as a callback argument. * This class is constructed internally and supplied as a callback argument.
* It should not be constructed directly. */ * It should not be constructed directly. */
class ThreadLocalEndpoint class ThreadLocalEndpoint {
{
friend class Endpoint; friend class Endpoint;
Endpoint& m_ep; Endpoint& m_ep;
ThreadLocalEndpoint(Endpoint& ep) : m_ep(ep) {} ThreadLocalEndpoint(Endpoint& ep) : m_ep(ep) {}
@ -278,5 +259,4 @@ public:
int getChan() const { return m_ep.getChan(); } int getChan() const { return m_ep.getChan(); }
}; };
} } // namespace jbus

View File

@ -6,12 +6,10 @@
#include <queue> #include <queue>
#include <mutex> #include <mutex>
namespace jbus namespace jbus {
{
/** Server interface for accepting incoming connections from GBA emulator instances. */ /** Server interface for accepting incoming connections from GBA emulator instances. */
class Listener class Listener {
{
net::Socket m_dataServer = {false}; net::Socket m_dataServer = {false};
net::Socket m_clockServer = {false}; net::Socket m_clockServer = {false};
std::thread m_listenerThread; std::thread m_listenerThread;
@ -38,5 +36,4 @@ public:
~Listener(); ~Listener();
}; };
} } // namespace jbus

View File

@ -14,30 +14,24 @@ typedef UINT_PTR SOCKET;
struct sockaddr_in; struct sockaddr_in;
namespace jbus::net namespace jbus::net {
{
/** IP address class derived from SFML */ /** IP address class derived from SFML */
class IPAddress class IPAddress {
{
uint32_t m_address = 0; uint32_t m_address = 0;
bool m_valid = false; bool m_valid = false;
void resolve(const std::string& address); void resolve(const std::string& address);
public: public:
IPAddress(const std::string& address) IPAddress(const std::string& address) { resolve(address); }
{
resolve(address);
}
uint32_t toInteger() const; uint32_t toInteger() const;
operator bool() const { return m_valid; } operator bool() const { return m_valid; }
}; };
/** Server-oriented TCP socket class derived from SFML */ /** Server-oriented TCP socket class derived from SFML */
class Socket class Socket {
{
#ifndef _WIN32 #ifndef _WIN32
using SocketTp = int; using SocketTp = int;
#else #else
@ -50,30 +44,19 @@ class Socket
void setRemoteSocket(int remSocket); void setRemoteSocket(int remSocket);
public: public:
enum class EResult enum class EResult { OK, Error, Busy };
{
OK,
Error,
Busy
};
#ifdef _WIN32 #ifdef _WIN32
static EResult LastWSAError(); static EResult LastWSAError();
#endif #endif
Socket(bool blocking) Socket(bool blocking) : m_isBlocking(blocking) {}
: m_isBlocking(blocking) {}
~Socket() { close(); } ~Socket() { close(); }
Socket(const Socket& other) = delete; Socket(const Socket& other) = delete;
Socket& operator=(const Socket& other) = delete; Socket& operator=(const Socket& other) = delete;
Socket(Socket&& other) Socket(Socket&& other) : m_socket(other.m_socket), m_isBlocking(other.m_isBlocking) { other.m_socket = -1; }
: m_socket(other.m_socket), m_isBlocking(other.m_isBlocking) Socket& operator=(Socket&& other) {
{
other.m_socket = -1;
}
Socket& operator=(Socket&& other)
{
close(); close();
m_socket = other.m_socket; m_socket = other.m_socket;
other.m_socket = -1; other.m_socket = -1;
@ -98,5 +81,4 @@ public:
SocketTp GetInternalSocket() const { return m_socket; } SocketTp GetInternalSocket() const { return m_socket; }
}; };
} } // namespace jbus::net

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,7 @@
#include "jbus/Common.hpp" #include "jbus/Common.hpp"
namespace jbus namespace jbus {
{
#if __APPLE__ #if __APPLE__
static u64 MachToDolphinNum; static u64 MachToDolphinNum;
@ -24,8 +23,7 @@ static u64 MachToDolphinDenom;
static LARGE_INTEGER PerfFrequency; static LARGE_INTEGER PerfFrequency;
#endif #endif
u64 GetGCTicks() u64 GetGCTicks() {
{
#if __APPLE__ #if __APPLE__
return mach_absolute_time() * MachToDolphinNum / MachToDolphinDenom; return mach_absolute_time() * MachToDolphinNum / MachToDolphinDenom;
#elif __linux__ || __FreeBSD__ #elif __linux__ || __FreeBSD__
@ -44,31 +42,27 @@ u64 GetGCTicks()
#endif #endif
} }
void WaitGCTicks(u64 ticks) void WaitGCTicks(u64 ticks) {
{
#ifndef _WIN32 #ifndef _WIN32
struct timeval tv = {}; struct timeval tv = {};
tv.tv_sec = ticks / GetGCTicksPerSec(); tv.tv_sec = ticks / GetGCTicksPerSec();
tv.tv_usec = (ticks % GetGCTicksPerSec()) * 1000000 / GetGCTicksPerSec(); tv.tv_usec = (ticks % GetGCTicksPerSec()) * 1000000 / GetGCTicksPerSec();
select(0, NULL, NULL, NULL, &tv); select(0, NULL, NULL, NULL, &tv);
#else #else
if (ticks < GetGCTicksPerSec() / 60) if (ticks < GetGCTicksPerSec() / 60) {
{
/* NT is useless for scheduling sub-millisecond intervals */ /* NT is useless for scheduling sub-millisecond intervals */
u64 start = GetGCTicks(); u64 start = GetGCTicks();
do { Sleep(0); } while (GetGCTicks() - start < ticks); do {
} Sleep(0);
else } while (GetGCTicks() - start < ticks);
{ } else {
/* Use normal Sleep() for durations longer than ~16ms */ /* Use normal Sleep() for durations longer than ~16ms */
Sleep(ticks * 1000 / GetGCTicksPerSec() + Sleep(ticks * 1000 / GetGCTicksPerSec() + (ticks % GetGCTicksPerSec()) * 1000 / GetGCTicksPerSec());
(ticks % GetGCTicksPerSec()) * 1000 / GetGCTicksPerSec());
} }
#endif #endif
} }
void Initialize() void Initialize() {
{
#if __APPLE__ #if __APPLE__
mach_timebase_info_data_t timebase; mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase); mach_timebase_info(&timebase);
@ -81,4 +75,4 @@ void Initialize()
#endif #endif
} }
} } // namespace jbus

View File

@ -2,13 +2,11 @@
#define LOG_TRANSFER 0 #define LOG_TRANSFER 0
namespace jbus namespace jbus {
{
#define ROUND_UP_8(val) (((val) + 7) & ~7) #define ROUND_UP_8(val) (((val) + 7) & ~7)
void Endpoint::KawasedoChallenge::DSPSecParms::ProcessGBACrypto() void Endpoint::KawasedoChallenge::DSPSecParms::ProcessGBACrypto() {
{
/* Unwrap key from challenge using 'sedo' magic number (to encrypt JoyBoot program) */ /* Unwrap key from challenge using 'sedo' magic number (to encrypt JoyBoot program) */
x20_key = x0_gbaChallenge ^ 0x6f646573; x20_key = x0_gbaChallenge ^ 0x6f646573;
@ -40,79 +38,61 @@ void Endpoint::KawasedoChallenge::DSPSecParms::ProcessGBACrypto()
x24_authInitCode = t3 ^ ((t3 & 0x200) != 0 ? 0x6f646573 : 0x6177614b); x24_authInitCode = t3 ^ ((t3 & 0x200) != 0 ? 0x6f646573 : 0x6177614b);
} }
void Endpoint::KawasedoChallenge::_0Reset(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_0Reset(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{
if (status != GBA_READY || if (status != GBA_READY ||
(status = endpoint.GBAResetAsync(x10_statusPtr, (status = endpoint.GBAResetAsync(x10_statusPtr, bindThis(&KawasedoChallenge::_1GetStatus))) != GBA_READY) {
bindThis(&KawasedoChallenge::_1GetStatus))) != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_1GetStatus(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_1GetStatus(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{
if (status == GBA_READY) if (status == GBA_READY)
if (*x10_statusPtr != GBA_JSTAT_SEND) if (*x10_statusPtr != GBA_JSTAT_SEND)
status = GBA_JOYBOOT_UNKNOWN_STATE; status = GBA_JOYBOOT_UNKNOWN_STATE;
if (status != GBA_READY || if (status != GBA_READY || (status = endpoint.GBAGetStatusAsync(
(status = endpoint.GBAGetStatusAsync(x10_statusPtr, x10_statusPtr, bindThis(&KawasedoChallenge::_2ReadChallenge))) != GBA_READY) {
bindThis(&KawasedoChallenge::_2ReadChallenge))) != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_2ReadChallenge(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_2ReadChallenge(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{
if (status == GBA_READY) if (status == GBA_READY)
if (*x10_statusPtr != (GBA_JSTAT_PSF0 | GBA_JSTAT_SEND)) if (*x10_statusPtr != (GBA_JSTAT_PSF0 | GBA_JSTAT_SEND))
status = GBA_JOYBOOT_UNKNOWN_STATE; status = GBA_JOYBOOT_UNKNOWN_STATE;
if (status != GBA_READY || if (status != GBA_READY || (status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
(status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, bindThis(&KawasedoChallenge::_3DSPCrypto))) != GBA_READY) {
bindThis(&KawasedoChallenge::_3DSPCrypto))) != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_3DSPCrypto(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_3DSPCrypto(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{ if (status != GBA_READY) {
if (status != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} } else {
else
{
_DSPCryptoInit(); _DSPCryptoInit();
_DSPCryptoDone(endpoint); _DSPCryptoDone(endpoint);
} }
} }
void Endpoint::KawasedoChallenge::_DSPCryptoInit() void Endpoint::KawasedoChallenge::_DSPCryptoInit() {
{
xf8_dspHmac.x0_gbaChallenge = reinterpret_cast<u32&>(x18_readBuf); xf8_dspHmac.x0_gbaChallenge = reinterpret_cast<u32&>(x18_readBuf);
xf8_dspHmac.x4_logoPalette = x0_pColor; xf8_dspHmac.x4_logoPalette = x0_pColor;
xf8_dspHmac.x8_logoSpeed = x4_pSpeed; xf8_dspHmac.x8_logoSpeed = x4_pSpeed;
@ -120,8 +100,7 @@ void Endpoint::KawasedoChallenge::_DSPCryptoInit()
xf8_dspHmac.ProcessGBACrypto(); xf8_dspHmac.ProcessGBACrypto();
} }
void Endpoint::KawasedoChallenge::_DSPCryptoDone(ThreadLocalEndpoint& endpoint) void Endpoint::KawasedoChallenge::_DSPCryptoDone(ThreadLocalEndpoint& endpoint) {
{
x58_currentKey = xf8_dspHmac.x20_key; x58_currentKey = xf8_dspHmac.x20_key;
x5c_initMessage = xf8_dspHmac.x24_authInitCode; x5c_initMessage = xf8_dspHmac.x24_authInitCode;
@ -141,25 +120,20 @@ void Endpoint::KawasedoChallenge::_DSPCryptoDone(ThreadLocalEndpoint& endpoint)
x30_justStarted = 1; x30_justStarted = 1;
EJoyReturn status; EJoyReturn status;
if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr, if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr, bindThis(&KawasedoChallenge::_4TransmitProgram))) !=
bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY) GBA_READY) {
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{ if (status != GBA_READY) {
if (status != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
@ -169,18 +143,12 @@ void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoin
#if LOG_TRANSFER #if LOG_TRANSFER
printf("PROG [%d/%d]\n", x34_bytesSent, x64_totalBytes); printf("PROG [%d/%d]\n", x34_bytesSent, x64_totalBytes);
#endif #endif
if (x30_justStarted) if (x30_justStarted) {
{
x30_justStarted = 0; x30_justStarted = 0;
} } else {
else if (!(*x10_statusPtr & GBA_JSTAT_PSF1) || (*x10_statusPtr & GBA_JSTAT_PSF0) >> 4 != (x34_bytesSent & 4) >> 2) {
{
if (!(*x10_statusPtr & GBA_JSTAT_PSF1) ||
(*x10_statusPtr & GBA_JSTAT_PSF0) >> 4 != (x34_bytesSent & 4) >> 2)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, GBA_JOYBOOT_UNKNOWN_STATE); x14_callback(endpoint, GBA_JOYBOOT_UNKNOWN_STATE);
x14_callback = {}; x14_callback = {};
} }
@ -189,38 +157,29 @@ void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoin
x34_bytesSent += 4; x34_bytesSent += 4;
} }
if (x34_bytesSent <= x64_totalBytes) if (x34_bytesSent <= x64_totalBytes) {
{
u32 cryptWindow; u32 cryptWindow;
if (x34_bytesSent != x64_totalBytes) if (x34_bytesSent != x64_totalBytes) {
{
x20_byteInWindow = 0; x20_byteInWindow = 0;
cryptWindow = 0; cryptWindow = 0;
while (x20_byteInWindow < 4) while (x20_byteInWindow < 4) {
{ if (xc_progLen) {
if (xc_progLen)
{
cryptWindow |= *x8_progPtr++ << (x20_byteInWindow * 8); cryptWindow |= *x8_progPtr++ << (x20_byteInWindow * 8);
--xc_progLen; --xc_progLen;
} }
++x20_byteInWindow; ++x20_byteInWindow;
} }
if (x34_bytesSent == 0xac) if (x34_bytesSent == 0xac) {
{
x60_gameId = cryptWindow; x60_gameId = cryptWindow;
} } else if (x34_bytesSent == 0xc4) {
else if (x34_bytesSent == 0xc4)
{
cryptWindow = endpoint.getChan() << 0x8; cryptWindow = endpoint.getChan() << 0x8;
} }
if (x34_bytesSent >= 0xc0) if (x34_bytesSent >= 0xc0) {
{
u32 shiftWindow = cryptWindow; u32 shiftWindow = cryptWindow;
u32 shiftCrc = x38_crc; u32 shiftCrc = x38_crc;
for (int i=0 ; i<32 ; ++i) for (int i = 0; i < 32; ++i) {
{
if ((shiftWindow ^ shiftCrc) & 0x1) if ((shiftWindow ^ shiftCrc) & 0x1)
shiftCrc = (shiftCrc >> 1) ^ 0xa1c1; shiftCrc = (shiftCrc >> 1) ^ 0xa1c1;
else else
@ -231,23 +190,17 @@ void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoin
x38_crc = shiftCrc; x38_crc = shiftCrc;
} }
if (x34_bytesSent == 0x1f8) if (x34_bytesSent == 0x1f8) {
{
x3c_checkStore[0] = cryptWindow; x3c_checkStore[0] = cryptWindow;
} } else if (x34_bytesSent == 0x1fc) {
else if (x34_bytesSent == 0x1fc)
{
x20_byteInWindow = 1; x20_byteInWindow = 1;
x3c_checkStore[x20_byteInWindow] = cryptWindow; x3c_checkStore[x20_byteInWindow] = cryptWindow;
} }
} } else {
else
{
cryptWindow = x38_crc | x34_bytesSent << 16; cryptWindow = x38_crc | x34_bytesSent << 16;
} }
if (x34_bytesSent > 0xbf) if (x34_bytesSent > 0xbf) {
{
x58_currentKey = 0x6177614b * x58_currentKey + 1; x58_currentKey = 0x6177614b * x58_currentKey + 1;
cryptWindow ^= x58_currentKey; cryptWindow ^= x58_currentKey;
@ -263,8 +216,7 @@ void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoin
if (x34_bytesSent == 0x1f8) if (x34_bytesSent == 0x1f8)
x3c_checkStore[2] = cryptWindow; x3c_checkStore[2] = cryptWindow;
if (x20_byteInWindow < 4) if (x20_byteInWindow < 4) {
{
x3c_checkStore[2 + x20_byteInWindow] = cryptWindow; x3c_checkStore[2 + x20_byteInWindow] = cryptWindow;
x3c_checkStore[5 - x20_byteInWindow] = x3c_checkStore[5 - x20_byteInWindow] =
x3c_checkStore[1 + x20_byteInWindow] * x3c_checkStore[4 - x20_byteInWindow]; x3c_checkStore[1 + x20_byteInWindow] * x3c_checkStore[4 - x20_byteInWindow];
@ -275,24 +227,19 @@ void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoin
} }
if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr, if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY) bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY) {
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} } else // x34_bytesWritten > x64_totalBytes
else // x34_bytesWritten > x64_totalBytes
{
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::_5StartBootPoll))) != GBA_READY)
{ {
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, bindThis(&KawasedoChallenge::_5StartBootPoll))) !=
GBA_READY) {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
@ -300,46 +247,35 @@ void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoin
} }
} }
void Endpoint::KawasedoChallenge::_5StartBootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_5StartBootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{
if (status != GBA_READY || if (status != GBA_READY ||
(status = endpoint.GBAGetStatusAsync(x10_statusPtr, (status = endpoint.GBAGetStatusAsync(x10_statusPtr, bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY) {
bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_6BootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_6BootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{
if (status == GBA_READY) if (status == GBA_READY)
if (*x10_statusPtr & (GBA_JSTAT_FLAGS_MASK | GBA_JSTAT_RECV)) if (*x10_statusPtr & (GBA_JSTAT_FLAGS_MASK | GBA_JSTAT_RECV))
status = GBA_JOYBOOT_UNKNOWN_STATE; status = GBA_JOYBOOT_UNKNOWN_STATE;
if (status != GBA_READY) if (status != GBA_READY) {
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
return; return;
} }
if (*x10_statusPtr != GBA_JSTAT_SEND) if (*x10_statusPtr != GBA_JSTAT_SEND) {
{ if ((status = endpoint.GBAGetStatusAsync(x10_statusPtr, bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY) {
if ((status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
@ -347,78 +283,68 @@ void Endpoint::KawasedoChallenge::_6BootPoll(ThreadLocalEndpoint& endpoint, EJoy
return; return;
} }
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, bindThis(&KawasedoChallenge::_7BootAcknowledge))) !=
bindThis(&KawasedoChallenge::_7BootAcknowledge))) != GBA_READY) GBA_READY) {
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{ if (status != GBA_READY || (status = endpoint.GBAWriteAsync(x18_readBuf, x10_statusPtr,
if (status != GBA_READY || bindThis(&KawasedoChallenge::_8BootDone))) != GBA_READY) {
(status = endpoint.GBAWriteAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::_8BootDone))) != GBA_READY)
{
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
} }
void Endpoint::KawasedoChallenge::_8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status) void Endpoint::KawasedoChallenge::_8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status) {
{
if (status == GBA_READY) if (status == GBA_READY)
*x10_statusPtr = 0; *x10_statusPtr = 0;
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback) {
{
x14_callback(endpoint, status); x14_callback(endpoint, status);
x14_callback = {}; x14_callback = {};
} }
} }
Endpoint::KawasedoChallenge::KawasedoChallenge(s32 paletteColor, s32 paletteSpeed, Endpoint::KawasedoChallenge::KawasedoChallenge(s32 paletteColor, s32 paletteSpeed, const u8* programp, s32 length,
const u8* programp, s32 length, u8* status, FGBACallback&& callback) u8* status, FGBACallback&& callback)
: x0_pColor(paletteColor), x4_pSpeed(paletteSpeed), x8_progPtr(programp), xc_progLen(length), : x0_pColor(paletteColor)
x10_statusPtr(status), x14_callback(std::move(callback)), x34_bytesSent(0), m_initialized(true) , x4_pSpeed(paletteSpeed)
{} , x8_progPtr(programp)
, xc_progLen(length)
, x10_statusPtr(status)
, x14_callback(std::move(callback))
, x34_bytesSent(0)
, m_initialized(true) {}
void Endpoint::KawasedoChallenge::start(Endpoint& endpoint) void Endpoint::KawasedoChallenge::start(Endpoint& endpoint) {
{ if (endpoint.GBAGetStatusAsync(x10_statusPtr, bindThis(&KawasedoChallenge::_0Reset)) != GBA_READY) {
if (endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::_0Reset)) != GBA_READY)
{
x14_callback = {}; x14_callback = {};
m_started = false; m_started = false;
} }
} }
void Endpoint::clockSync() void Endpoint::clockSync() {
{ if (!m_clockSocket) {
if (!m_clockSocket)
{
m_running = false; m_running = false;
return; return;
} }
u32 TickDelta = 0; u32 TickDelta = 0;
if (!m_lastGCTick) if (!m_lastGCTick) {
{
m_lastGCTick = GetGCTicks(); m_lastGCTick = GetGCTicks();
TickDelta = GetGCTicksPerSec() / 60; TickDelta = GetGCTicksPerSec() / 60;
} } else
else
TickDelta = GetGCTicks() - m_lastGCTick; TickDelta = GetGCTicks() - m_lastGCTick;
/* Scale GameCube clock into GBA clock */ /* Scale GameCube clock into GBA clock */
@ -429,8 +355,7 @@ void Endpoint::clockSync()
m_running = false; m_running = false;
} }
void Endpoint::send(const u8* buffer) void Endpoint::send(const u8* buffer) {
{
m_lastCmd = buffer[0]; m_lastCmd = buffer[0];
net::Socket::EResult result; net::Socket::EResult result;
@ -443,31 +368,25 @@ void Endpoint::send(const u8* buffer)
if (m_lastCmd != CMD_STATUS) if (m_lastCmd != CMD_STATUS)
m_booted = true; m_booted = true;
if (result != net::Socket::EResult::OK) if (result != net::Socket::EResult::OK) {
{
m_running = false; m_running = false;
} }
#if LOG_TRANSFER #if LOG_TRANSFER
else else {
{ printf("Send %02x [> %02x%02x%02x%02x] (%lu)\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], sentBytes);
printf("Send %02x [> %02x%02x%02x%02x] (%lu)\n", buffer[0],
buffer[1], buffer[2], buffer[3], buffer[4], sentBytes);
} }
#endif #endif
} }
size_t Endpoint::receive(u8* buffer) size_t Endpoint::receive(u8* buffer) {
{ if (!m_dataSocket) {
if (!m_dataSocket)
{
m_running = false; m_running = false;
return 5; return 5;
} }
size_t recvBytes = 0; size_t recvBytes = 0;
net::Socket::EResult result = m_dataSocket.recv(buffer, 5, recvBytes); net::Socket::EResult result = m_dataSocket.recv(buffer, 5, recvBytes);
if (result == net::Socket::EResult::Error) if (result == net::Socket::EResult::Error) {
{
m_running = false; m_running = false;
return 5; return 5;
} }
@ -476,19 +395,13 @@ size_t Endpoint::receive(u8* buffer)
recvBytes = 5; recvBytes = 5;
#if LOG_TRANSFER #if LOG_TRANSFER
if (recvBytes > 0) if (recvBytes > 0) {
{ if (m_lastCmd == CMD_STATUS || m_lastCmd == CMD_RESET) {
if (m_lastCmd == CMD_STATUS || m_lastCmd == CMD_RESET) printf("Stat/Reset [< %02x%02x%02x%02x%02x] (%lu)\n", (u8)buffer[0], (u8)buffer[1], (u8)buffer[2], (u8)buffer[3],
{ (u8)buffer[4], recvBytes);
printf("Stat/Reset [< %02x%02x%02x%02x%02x] (%lu)\n", } else {
(u8)buffer[0], (u8)buffer[1], (u8)buffer[2], printf("Receive [< %02x%02x%02x%02x%02x] (%lu)\n", (u8)buffer[0], (u8)buffer[1], (u8)buffer[2], (u8)buffer[3],
(u8)buffer[3], (u8)buffer[4], recvBytes); (u8)buffer[4], recvBytes);
}
else
{
printf("Receive [< %02x%02x%02x%02x%02x] (%lu)\n",
(u8)buffer[0], (u8)buffer[1], (u8)buffer[2],
(u8)buffer[3], (u8)buffer[4], recvBytes);
} }
} }
#endif #endif
@ -496,8 +409,7 @@ size_t Endpoint::receive(u8* buffer)
return recvBytes; return recvBytes;
} }
size_t Endpoint::runBuffer(u8* buffer, std::unique_lock<std::mutex>& lk) size_t Endpoint::runBuffer(u8* buffer, std::unique_lock<std::mutex>& lk) {
{
u8 tmpBuffer[5]; u8 tmpBuffer[5];
memmove(tmpBuffer, buffer, 5); memmove(tmpBuffer, buffer, 5);
@ -511,24 +423,20 @@ size_t Endpoint::runBuffer(u8* buffer, std::unique_lock<std::mutex>& lk)
return receivedBytes; return receivedBytes;
} }
bool Endpoint::idleGetStatus(std::unique_lock<std::mutex>& lk) bool Endpoint::idleGetStatus(std::unique_lock<std::mutex>& lk) {
{ u8 buffer[] = {CMD_STATUS, 0, 0, 0, 0};
u8 buffer[] = { CMD_STATUS, 0, 0, 0, 0 };
return runBuffer(buffer, lk); return runBuffer(buffer, lk);
} }
void Endpoint::transferProc() void Endpoint::transferProc() {
{
#if LOG_TRANSFER #if LOG_TRANSFER
printf("Starting JoyBus transfer thread for channel %d\n", m_chan); printf("Starting JoyBus transfer thread for channel %d\n", m_chan);
#endif #endif
/* This lock is relinquished on I/O cycles or when waiting for next request */ /* This lock is relinquished on I/O cycles or when waiting for next request */
std::unique_lock<std::mutex> lk(m_syncLock); std::unique_lock<std::mutex> lk(m_syncLock);
while (m_running) while (m_running) {
{ if (m_cmdIssued) {
if (m_cmdIssued)
{
/* Synchronous command write/read cycle */ /* Synchronous command write/read cycle */
runBuffer(m_buffer, lk); runBuffer(m_buffer, lk);
m_cmdIssued = false; m_cmdIssued = false;
@ -558,26 +466,20 @@ void Endpoint::transferProc()
m_statusPtr = nullptr; m_statusPtr = nullptr;
m_readDstPtr = nullptr; m_readDstPtr = nullptr;
if (m_callback) if (m_callback) {
{
FGBACallback cb = std::move(m_callback); FGBACallback cb = std::move(m_callback);
m_callback = {}; m_callback = {};
ThreadLocalEndpoint ep(*this); ThreadLocalEndpoint ep(*this);
cb(ep, xferStatus); cb(ep, xferStatus);
} }
} } else if (!m_booted) {
else if (!m_booted)
{
/* Poll bus with status messages when inactive */ /* Poll bus with status messages when inactive */
if (idleGetStatus(lk)) if (idleGetStatus(lk)) {
{
lk.unlock(); lk.unlock();
WaitGCTicks(GetGCTicksPerSec() * 4 / 60); WaitGCTicks(GetGCTicksPerSec() * 4 / 60);
lk.lock(); lk.lock();
} }
} } else {
else
{
/* Wait for next user request */ /* Wait for next user request */
m_issueCv.wait(lk); m_issueCv.wait(lk);
} }
@ -592,27 +494,21 @@ void Endpoint::transferProc()
#endif #endif
} }
void Endpoint::transferWakeup(ThreadLocalEndpoint& endpoint, u8 status) void Endpoint::transferWakeup(ThreadLocalEndpoint& endpoint, u8 status) { m_syncCv.notify_all(); }
{
m_syncCv.notify_all();
}
void Endpoint::stop() void Endpoint::stop() {
{
m_running = false; m_running = false;
m_issueCv.notify_one(); m_issueCv.notify_one();
if (m_transferThread.joinable()) if (m_transferThread.joinable())
m_transferThread.join(); m_transferThread.join();
} }
EJoyReturn Endpoint::GBAGetProcessStatus(u8& percentOut) EJoyReturn Endpoint::GBAGetProcessStatus(u8& percentOut) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
std::unique_lock<std::mutex> lk(m_syncLock); std::unique_lock<std::mutex> lk(m_syncLock);
if (m_joyBoot) if (m_joyBoot) {
{
percentOut = m_joyBoot.percentComplete(); percentOut = m_joyBoot.percentComplete();
if (!m_joyBoot.isDone()) if (!m_joyBoot.isDone())
return GBA_BUSY; return GBA_BUSY;
@ -624,8 +520,7 @@ EJoyReturn Endpoint::GBAGetProcessStatus(u8& percentOut)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAGetStatusAsync(u8* status, FGBACallback&& callback) EJoyReturn Endpoint::GBAGetStatusAsync(u8* status, FGBACallback&& callback) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -643,8 +538,7 @@ EJoyReturn Endpoint::GBAGetStatusAsync(u8* status, FGBACallback&& callback)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAGetStatus(u8* status) EJoyReturn Endpoint::GBAGetStatus(u8* status) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -663,8 +557,7 @@ EJoyReturn Endpoint::GBAGetStatus(u8* status)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAResetAsync(u8* status, FGBACallback&& callback) EJoyReturn Endpoint::GBAResetAsync(u8* status, FGBACallback&& callback) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -682,8 +575,7 @@ EJoyReturn Endpoint::GBAResetAsync(u8* status, FGBACallback&& callback)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAReset(u8* status) EJoyReturn Endpoint::GBAReset(u8* status) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -702,8 +594,7 @@ EJoyReturn Endpoint::GBAReset(u8* status)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback) EJoyReturn Endpoint::GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -722,8 +613,7 @@ EJoyReturn Endpoint::GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBARead(u8* dst, u8* status) EJoyReturn Endpoint::GBARead(u8* dst, u8* status) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -743,8 +633,7 @@ EJoyReturn Endpoint::GBARead(u8* dst, u8* status)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAWriteAsync(const u8* src, u8* status, FGBACallback&& callback) EJoyReturn Endpoint::GBAWriteAsync(const u8* src, u8* status, FGBACallback&& callback) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -755,8 +644,8 @@ EJoyReturn Endpoint::GBAWriteAsync(const u8* src, u8* status, FGBACallback&& cal
m_cmdIssued = true; m_cmdIssued = true;
m_statusPtr = status; m_statusPtr = status;
m_buffer[0] = CMD_WRITE; m_buffer[0] = CMD_WRITE;
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
m_buffer[i+1] = src[i]; m_buffer[i + 1] = src[i];
m_callback = std::move(callback); m_callback = std::move(callback);
m_issueCv.notify_one(); m_issueCv.notify_one();
@ -764,8 +653,7 @@ EJoyReturn Endpoint::GBAWriteAsync(const u8* src, u8* status, FGBACallback&& cal
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAWrite(const u8* src, u8* status) EJoyReturn Endpoint::GBAWrite(const u8* src, u8* status) {
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -776,8 +664,8 @@ EJoyReturn Endpoint::GBAWrite(const u8* src, u8* status)
m_cmdIssued = true; m_cmdIssued = true;
m_statusPtr = status; m_statusPtr = status;
m_buffer[0] = CMD_WRITE; m_buffer[0] = CMD_WRITE;
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
m_buffer[i+1] = src[i]; m_buffer[i + 1] = src[i];
m_callback = bindSync(); m_callback = bindSync();
m_issueCv.notify_one(); m_issueCv.notify_one();
@ -786,10 +674,8 @@ EJoyReturn Endpoint::GBAWrite(const u8* src, u8* status)
return GBA_READY; return GBA_READY;
} }
EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed, EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed, const u8* programp, s32 length, u8* status,
const u8* programp, s32 length, u8* status, FGBACallback&& callback) {
FGBACallback&& callback)
{
if (!m_running) if (!m_running)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -808,8 +694,7 @@ EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed,
if (programp[0xac] * programp[0xac] * programp[0xac] * programp[0xac] == 0) if (programp[0xac] * programp[0xac] * programp[0xac] * programp[0xac] == 0)
return GBA_JOYBOOT_ERR_INVALID; return GBA_JOYBOOT_ERR_INVALID;
m_joyBoot = KawasedoChallenge(paletteColor, paletteSpeed, programp, length, status, m_joyBoot = KawasedoChallenge(paletteColor, paletteSpeed, programp, length, status, std::move(callback));
std::move(callback));
m_joyBoot.start(*this); m_joyBoot.start(*this);
if (!m_joyBoot.started()) if (!m_joyBoot.started())
return GBA_NOT_READY; return GBA_NOT_READY;
@ -818,15 +703,13 @@ EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed,
} }
Endpoint::Endpoint(u8 chan, net::Socket&& data, net::Socket&& clock) Endpoint::Endpoint(u8 chan, net::Socket&& data, net::Socket&& clock)
: m_dataSocket(std::move(data)), m_clockSocket(std::move(clock)), m_chan(chan) : m_dataSocket(std::move(data)), m_clockSocket(std::move(clock)), m_chan(chan) {
{
m_transferThread = std::thread(std::bind(&Endpoint::transferProc, this)); m_transferThread = std::thread(std::bind(&Endpoint::transferProc, this));
} }
Endpoint::~Endpoint() { stop(); } Endpoint::~Endpoint() { stop(); }
EJoyReturn ThreadLocalEndpoint::GBAGetStatusAsync(u8* status, FGBACallback&& callback) EJoyReturn ThreadLocalEndpoint::GBAGetStatusAsync(u8* status, FGBACallback&& callback) {
{
if (!m_ep.m_running || m_ep.m_cmdIssued) if (!m_ep.m_running || m_ep.m_cmdIssued)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -838,8 +721,7 @@ EJoyReturn ThreadLocalEndpoint::GBAGetStatusAsync(u8* status, FGBACallback&& cal
return GBA_READY; return GBA_READY;
} }
EJoyReturn ThreadLocalEndpoint::GBAResetAsync(u8* status, FGBACallback&& callback) EJoyReturn ThreadLocalEndpoint::GBAResetAsync(u8* status, FGBACallback&& callback) {
{
if (!m_ep.m_running || m_ep.m_cmdIssued) if (!m_ep.m_running || m_ep.m_cmdIssued)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -851,8 +733,7 @@ EJoyReturn ThreadLocalEndpoint::GBAResetAsync(u8* status, FGBACallback&& callbac
return GBA_READY; return GBA_READY;
} }
EJoyReturn ThreadLocalEndpoint::GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback) EJoyReturn ThreadLocalEndpoint::GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback) {
{
if (!m_ep.m_running || m_ep.m_cmdIssued) if (!m_ep.m_running || m_ep.m_cmdIssued)
return GBA_NOT_READY; return GBA_NOT_READY;
@ -865,19 +746,18 @@ EJoyReturn ThreadLocalEndpoint::GBAReadAsync(u8* dst, u8* status, FGBACallback&&
return GBA_READY; return GBA_READY;
} }
EJoyReturn ThreadLocalEndpoint::GBAWriteAsync(const u8* src, u8* status, FGBACallback&& callback) EJoyReturn ThreadLocalEndpoint::GBAWriteAsync(const u8* src, u8* status, FGBACallback&& callback) {
{
if (!m_ep.m_running || m_ep.m_cmdIssued) if (!m_ep.m_running || m_ep.m_cmdIssued)
return GBA_NOT_READY; return GBA_NOT_READY;
m_ep.m_cmdIssued = true; m_ep.m_cmdIssued = true;
m_ep.m_statusPtr = status; m_ep.m_statusPtr = status;
m_ep.m_buffer[0] = Endpoint::CMD_WRITE; m_ep.m_buffer[0] = Endpoint::CMD_WRITE;
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
m_ep.m_buffer[i+1] = src[i]; m_ep.m_buffer[i + 1] = src[i];
m_ep.m_callback = std::move(callback); m_ep.m_callback = std::move(callback);
return GBA_READY; return GBA_READY;
} }
} } // namespace jbus

View File

@ -3,11 +3,9 @@
#define LOG_LISTENER 0 #define LOG_LISTENER 0
namespace jbus namespace jbus {
{
void Listener::listenerProc() void Listener::listenerProc() {
{
#if LOG_LISTENER #if LOG_LISTENER
printf("JoyBus listener started\n"); printf("JoyBus listener started\n");
#endif #endif
@ -15,37 +13,28 @@ void Listener::listenerProc()
net::IPAddress localhost("127.0.0.1"); net::IPAddress localhost("127.0.0.1");
bool dataBound = false; bool dataBound = false;
bool clockBound = false; bool clockBound = false;
while (m_running && (!dataBound || !clockBound)) while (m_running && (!dataBound || !clockBound)) {
{ if (!dataBound) {
if (!dataBound) if (!(dataBound = m_dataServer.openAndListen(localhost, DataPort))) {
{
if (!(dataBound = m_dataServer.openAndListen(localhost, DataPort)))
{
m_dataServer = net::Socket(false); m_dataServer = net::Socket(false);
#if LOG_LISTENER #if LOG_LISTENER
printf("data open failed %s; will retry\n", strerror(errno)); printf("data open failed %s; will retry\n", strerror(errno));
#endif #endif
WaitGCTicks(GetGCTicksPerSec()); WaitGCTicks(GetGCTicksPerSec());
} } else {
else
{
#if LOG_LISTENER #if LOG_LISTENER
printf("data listening on port %d\n", DataPort); printf("data listening on port %d\n", DataPort);
#endif #endif
} }
} }
if (!clockBound) if (!clockBound) {
{ if (!(clockBound = m_clockServer.openAndListen(localhost, ClockPort))) {
if (!(clockBound = m_clockServer.openAndListen(localhost, ClockPort)))
{
m_clockServer = net::Socket(false); m_clockServer = net::Socket(false);
#if LOG_LISTENER #if LOG_LISTENER
printf("clock open failed %s; will retry\n", strerror(errno)); printf("clock open failed %s; will retry\n", strerror(errno));
#endif #endif
WaitGCTicks(GetGCTicksPerSec()); WaitGCTicks(GetGCTicksPerSec());
} } else {
else
{
#if LOG_LISTENER #if LOG_LISTENER
printf("clock listening on port %d\n", ClockPort); printf("clock listening on port %d\n", ClockPort);
#endif #endif
@ -57,25 +46,20 @@ void Listener::listenerProc()
net::Socket acceptData = {true}; net::Socket acceptData = {true};
net::Socket acceptClock = {true}; net::Socket acceptClock = {true};
std::string hostname; std::string hostname;
while (m_running) while (m_running) {
{ if (m_dataServer.accept(acceptData, hostname) == net::Socket::EResult::OK) {
if (m_dataServer.accept(acceptData, hostname) == net::Socket::EResult::OK)
{
#if LOG_LISTENER #if LOG_LISTENER
printf("accepted data connection from %s\n", hostname.c_str()); printf("accepted data connection from %s\n", hostname.c_str());
#endif #endif
} }
if (m_clockServer.accept(acceptClock, hostname) == net::Socket::EResult::OK) if (m_clockServer.accept(acceptClock, hostname) == net::Socket::EResult::OK) {
{
#if LOG_LISTENER #if LOG_LISTENER
printf("accepted clock connection from %s\n", hostname.c_str()); printf("accepted clock connection from %s\n", hostname.c_str());
#endif #endif
} }
if (acceptData && acceptClock) if (acceptData && acceptClock) {
{
std::unique_lock<std::mutex> lk(m_queueLock); std::unique_lock<std::mutex> lk(m_queueLock);
m_endpointQueue.push(std::make_unique<Endpoint>( m_endpointQueue.push(std::make_unique<Endpoint>(0, std::move(acceptData), std::move(acceptClock)));
0, std::move(acceptData), std::move(acceptClock)));
} }
WaitGCTicks(GetGCTicksPerSec()); WaitGCTicks(GetGCTicksPerSec());
} }
@ -87,25 +71,21 @@ void Listener::listenerProc()
#endif #endif
} }
void Listener::start() void Listener::start() {
{
stop(); stop();
m_running = true; m_running = true;
m_listenerThread = std::thread(std::bind(&Listener::listenerProc, this)); m_listenerThread = std::thread(std::bind(&Listener::listenerProc, this));
} }
void Listener::stop() void Listener::stop() {
{
m_running = false; m_running = false;
if (m_listenerThread.joinable()) if (m_listenerThread.joinable())
m_listenerThread.join(); m_listenerThread.join();
} }
std::unique_ptr<Endpoint> Listener::accept() std::unique_ptr<Endpoint> Listener::accept() {
{
std::unique_lock<std::mutex> lk(m_queueLock); std::unique_lock<std::mutex> lk(m_queueLock);
if (m_endpointQueue.size()) if (m_endpointQueue.size()) {
{
std::unique_ptr<Endpoint> ret; std::unique_ptr<Endpoint> ret;
ret = std::move(m_endpointQueue.front()); ret = std::move(m_endpointQueue.front());
m_endpointQueue.pop(); m_endpointQueue.pop();
@ -116,4 +96,4 @@ std::unique_ptr<Endpoint> Listener::accept()
Listener::~Listener() { stop(); } Listener::~Listener() { stop(); }
} } // namespace jbus

View File

@ -13,8 +13,7 @@
#include <Ws2tcpip.h> #include <Ws2tcpip.h>
#endif #endif
namespace jbus::net namespace jbus::net {
{
/* Define the low-level send/receive flags, which depend on the OS */ /* Define the low-level send/receive flags, which depend on the OS */
#ifdef __linux__ #ifdef __linux__
@ -23,43 +22,32 @@ static const int _flags = MSG_NOSIGNAL;
static const int _flags = 0; static const int _flags = 0;
#endif #endif
void IPAddress::resolve(const std::string& address) void IPAddress::resolve(const std::string& address) {
{
m_address = 0; m_address = 0;
m_valid = false; m_valid = false;
if (address == "255.255.255.255") if (address == "255.255.255.255") {
{
/* The broadcast address needs to be handled explicitly, /* The broadcast address needs to be handled explicitly,
* because it is also the value returned by inet_addr on error */ * because it is also the value returned by inet_addr on error */
m_address = INADDR_BROADCAST; m_address = INADDR_BROADCAST;
m_valid = true; m_valid = true;
} } else if (address == "0.0.0.0") {
else if (address == "0.0.0.0")
{
m_address = INADDR_ANY; m_address = INADDR_ANY;
m_valid = true; m_valid = true;
} } else {
else
{
/* Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") */ /* Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") */
struct in_addr addr; struct in_addr addr;
if (inet_pton(AF_INET, address.c_str(), &addr) == 1) if (inet_pton(AF_INET, address.c_str(), &addr) == 1) {
{
m_address = addr.s_addr; m_address = addr.s_addr;
m_valid = true; m_valid = true;
} } else {
else
{
/* Not a valid address, try to convert it as a host name */ /* Not a valid address, try to convert it as a host name */
addrinfo hints; addrinfo hints;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
addrinfo* result = NULL; addrinfo* result = NULL;
if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0) if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0) {
{ if (result) {
if (result)
{
addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr; addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;
freeaddrinfo(result); freeaddrinfo(result);
m_address = addr.s_addr; m_address = addr.s_addr;
@ -70,13 +58,9 @@ void IPAddress::resolve(const std::string& address)
} }
} }
uint32_t IPAddress::toInteger() const uint32_t IPAddress::toInteger() const { return ntohl(m_address); }
{
return ntohl(m_address);
}
static sockaddr_in createAddress(uint32_t address, unsigned short port) static sockaddr_in createAddress(uint32_t address, unsigned short port) {
{
sockaddr_in addr; sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(address); addr.sin_addr.s_addr = htonl(address);
@ -90,14 +74,12 @@ static sockaddr_in createAddress(uint32_t address, unsigned short port)
return addr; return addr;
} }
bool Socket::openSocket() bool Socket::openSocket() {
{
if (isOpen()) if (isOpen())
return false; return false;
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == -1) if (m_socket == -1) {
{
fprintf(stderr, "Can't allocate socket\n"); fprintf(stderr, "Can't allocate socket\n");
return false; return false;
} }
@ -113,18 +95,15 @@ bool Socket::openSocket()
return true; return true;
} }
void Socket::setRemoteSocket(int remSocket) void Socket::setRemoteSocket(int remSocket) {
{
close(); close();
m_socket = remSocket; m_socket = remSocket;
setBlocking(m_isBlocking); setBlocking(m_isBlocking);
} }
#ifdef _WIN32 #ifdef _WIN32
Socket::EResult Socket::LastWSAError() Socket::EResult Socket::LastWSAError() {
{ switch (WSAGetLastError()) {
switch (WSAGetLastError())
{
case WSAEWOULDBLOCK: case WSAEWOULDBLOCK:
case WSAEALREADY: case WSAEALREADY:
return EResult::Busy; return EResult::Busy;
@ -134,8 +113,7 @@ Socket::EResult Socket::LastWSAError()
} }
#endif #endif
void Socket::setBlocking(bool blocking) void Socket::setBlocking(bool blocking) {
{
m_isBlocking = blocking; m_isBlocking = blocking;
#ifndef _WIN32 #ifndef _WIN32
int status = fcntl(m_socket, F_GETFL); int status = fcntl(m_socket, F_GETFL);
@ -149,31 +127,27 @@ void Socket::setBlocking(bool blocking)
#endif #endif
} }
bool Socket::openAndListen(const IPAddress& address, uint32_t port) bool Socket::openAndListen(const IPAddress& address, uint32_t port) {
{
if (!openSocket()) if (!openSocket())
return false; return false;
sockaddr_in addr = createAddress(address.toInteger(), port); sockaddr_in addr = createAddress(address.toInteger(), port);
if (bind(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) if (bind(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
{
/* Not likely to happen, but... */ /* Not likely to happen, but... */
//fprintf(stderr, "Failed to bind listener socket to port %d\n", port); // fprintf(stderr, "Failed to bind listener socket to port %d\n", port);
return false; return false;
} }
if (::listen(m_socket, 0) == -1) if (::listen(m_socket, 0) == -1) {
{
/* Oops, socket is deaf */ /* Oops, socket is deaf */
//fprintf(stderr, "Failed to listen to port %d\n", port); // fprintf(stderr, "Failed to listen to port %d\n", port);
return false; return false;
} }
return true; return true;
} }
Socket::EResult Socket::accept(Socket& remoteSocketOut, sockaddr_in& fromAddress) Socket::EResult Socket::accept(Socket& remoteSocketOut, sockaddr_in& fromAddress) {
{
if (!isOpen()) if (!isOpen())
return EResult::Error; return EResult::Error;
@ -182,8 +156,7 @@ Socket::EResult Socket::accept(Socket& remoteSocketOut, sockaddr_in& fromAddress
int remoteSocket = ::accept(m_socket, reinterpret_cast<sockaddr*>(&fromAddress), &length); int remoteSocket = ::accept(m_socket, reinterpret_cast<sockaddr*>(&fromAddress), &length);
/* Check for errors */ /* Check for errors */
if (remoteSocket == -1) if (remoteSocket == -1) {
{
#ifndef _WIN32 #ifndef _WIN32
EResult res = (errno == EAGAIN) ? EResult::Busy : EResult::Error; EResult res = (errno == EAGAIN) ? EResult::Busy : EResult::Error;
if (res == EResult::Error) if (res == EResult::Error)
@ -202,14 +175,12 @@ Socket::EResult Socket::accept(Socket& remoteSocketOut, sockaddr_in& fromAddress
return EResult::OK; return EResult::OK;
} }
Socket::EResult Socket::accept(Socket& remoteSocketOut) Socket::EResult Socket::accept(Socket& remoteSocketOut) {
{
sockaddr_in fromAddress; sockaddr_in fromAddress;
return accept(remoteSocketOut, fromAddress); return accept(remoteSocketOut, fromAddress);
} }
Socket::EResult Socket::accept(Socket& remoteSocketOut, std::string& fromHostname) Socket::EResult Socket::accept(Socket& remoteSocketOut, std::string& fromHostname) {
{
sockaddr_in fromAddress; sockaddr_in fromAddress;
socklen_t len = sizeof(fromAddress); socklen_t len = sizeof(fromAddress);
char name[NI_MAXHOST]; char name[NI_MAXHOST];
@ -220,8 +191,7 @@ Socket::EResult Socket::accept(Socket& remoteSocketOut, std::string& fromHostnam
return res; return res;
} }
void Socket::close() void Socket::close() {
{
if (!isOpen()) if (!isOpen())
return; return;
#ifndef _WIN32 #ifndef _WIN32
@ -232,8 +202,7 @@ void Socket::close()
m_socket = -1; m_socket = -1;
} }
Socket::EResult Socket::send(const void* buf, size_t len, size_t& transferred) Socket::EResult Socket::send(const void* buf, size_t len, size_t& transferred) {
{
transferred = 0; transferred = 0;
if (!isOpen()) if (!isOpen())
return EResult::Error; return EResult::Error;
@ -243,8 +212,7 @@ Socket::EResult Socket::send(const void* buf, size_t len, size_t& transferred)
/* Loop until every byte has been sent */ /* Loop until every byte has been sent */
int result = 0; int result = 0;
for (size_t sent = 0; sent < len; sent += result) for (size_t sent = 0; sent < len; sent += result) {
{
/* Send a chunk of data */ /* Send a chunk of data */
result = ::send(m_socket, static_cast<const char*>(buf) + sent, len - sent, _flags); result = ::send(m_socket, static_cast<const char*>(buf) + sent, len - sent, _flags);
@ -261,14 +229,12 @@ Socket::EResult Socket::send(const void* buf, size_t len, size_t& transferred)
return EResult::OK; return EResult::OK;
} }
Socket::EResult Socket::send(const void* buf, size_t len) Socket::EResult Socket::send(const void* buf, size_t len) {
{
size_t transferred; size_t transferred;
return send(buf, len, transferred); return send(buf, len, transferred);
} }
Socket::EResult Socket::recv(void* buf, size_t len, size_t& transferred) Socket::EResult Socket::recv(void* buf, size_t len, size_t& transferred) {
{
transferred = 0; transferred = 0;
if (!isOpen()) if (!isOpen())
return EResult::Error; return EResult::Error;
@ -295,10 +261,9 @@ Socket::EResult Socket::recv(void* buf, size_t len, size_t& transferred)
return EResult::OK; return EResult::OK;
} }
Socket::EResult Socket::recv(void* buf, size_t len) Socket::EResult Socket::recv(void* buf, size_t len) {
{
size_t transferred; size_t transferred;
return recv(buf, len, transferred); return recv(buf, len, transferred);
} }
} } // namespace jbus::net

View File

@ -3,22 +3,17 @@
#include "jbus/Endpoint.hpp" #include "jbus/Endpoint.hpp"
#include <functional> #include <functional>
static void clientPadComplimentCheck(jbus::u8* buffer) static void clientPadComplimentCheck(jbus::u8* buffer) {
{
jbus::u8 check = 0x19; jbus::u8 check = 0x19;
for (int i=0xa0 ; i<0xbd ; ++i) for (int i = 0xa0; i < 0xbd; ++i)
check += buffer[i]; check += buffer[i];
buffer[0xbd] = -check; buffer[0xbd] = -check;
} }
static jbus::EJoyReturn BootStatus = jbus::GBA_JOYBOOT_ERR_INVALID; static jbus::EJoyReturn BootStatus = jbus::GBA_JOYBOOT_ERR_INVALID;
static void JoyBootDone(jbus::ThreadLocalEndpoint& endpoint, jbus::EJoyReturn status) static void JoyBootDone(jbus::ThreadLocalEndpoint& endpoint, jbus::EJoyReturn status) { BootStatus = status; }
{
BootStatus = status;
}
static bool DonePoll(jbus::Endpoint& endpoint) static bool DonePoll(jbus::Endpoint& endpoint) {
{
jbus::u8 status; jbus::u8 status;
if (endpoint.GBAReset(&status) == jbus::GBA_NOT_READY) if (endpoint.GBAReset(&status) == jbus::GBA_NOT_READY)
if (endpoint.GBAReset(&status) == jbus::GBA_NOT_READY) if (endpoint.GBAReset(&status) == jbus::GBA_NOT_READY)
@ -32,17 +27,14 @@ static bool DonePoll(jbus::Endpoint& endpoint)
return true; return true;
} }
int main(int argc, char** argv) int main(int argc, char** argv) {
{ if (argc < 2) {
if (argc < 2)
{
printf("Usage: joyboot <client_pad.bin>\n"); printf("Usage: joyboot <client_pad.bin>\n");
return 1; return 1;
} }
FILE* fp = fopen(argv[1], "rb"); FILE* fp = fopen(argv[1], "rb");
if (!fp) if (!fp) {
{
fprintf(stderr, "Unable to open %s\n", argv[1]); fprintf(stderr, "Unable to open %s\n", argv[1]);
return 1; return 1;
} }
@ -53,8 +45,7 @@ int main(int argc, char** argv)
std::unique_ptr<jbus::u8[]> data(new jbus::u8[fsize]); std::unique_ptr<jbus::u8[]> data(new jbus::u8[fsize]);
fread(data.get(), 1, fsize, fp); fread(data.get(), 1, fsize, fp);
fclose(fp); fclose(fp);
if (fsize < 512) if (fsize < 512) {
{
fprintf(stderr, "%s must be at least 512 bytes\n", argv[1]); fprintf(stderr, "%s must be at least 512 bytes\n", argv[1]);
return 1; return 1;
} }
@ -66,8 +57,7 @@ int main(int argc, char** argv)
jbus::Listener listener; jbus::Listener listener;
listener.start(); listener.start();
std::unique_ptr<jbus::Endpoint> endpoint; std::unique_ptr<jbus::Endpoint> endpoint;
while (true) while (true) {
{
jbus::s64 frameStart = jbus::GetGCTicks(); jbus::s64 frameStart = jbus::GetGCTicks();
endpoint = listener.accept(); endpoint = listener.accept();
if (endpoint) if (endpoint)
@ -83,11 +73,9 @@ int main(int argc, char** argv)
jbus::WaitGCTicks(jbus::GetGCTicksPerSec() * 4); jbus::WaitGCTicks(jbus::GetGCTicksPerSec() * 4);
jbus::u8 status; jbus::u8 status;
if (endpoint->GBAJoyBootAsync(2, 2, data.get(), fsize, if (endpoint->GBAJoyBootAsync(2, 2, data.get(), fsize, &status,
&status, std::bind(JoyBootDone, std::bind(JoyBootDone, std::placeholders::_1, std::placeholders::_2)) !=
std::placeholders::_1, jbus::GBA_READY) {
std::placeholders::_2)) != jbus::GBA_READY)
{
fprintf(stderr, "Unable to start JoyBoot\n"); fprintf(stderr, "Unable to start JoyBoot\n");
return 1; return 1;
} }
@ -95,18 +83,15 @@ int main(int argc, char** argv)
jbus::s64 start = jbus::GetGCTicks(); jbus::s64 start = jbus::GetGCTicks();
jbus::u8 percent = 0; jbus::u8 percent = 0;
jbus::u8 lastpercent = 0; jbus::u8 lastpercent = 0;
while (endpoint->GBAGetProcessStatus(percent) == jbus::GBA_BUSY) while (endpoint->GBAGetProcessStatus(percent) == jbus::GBA_BUSY) {
{ if (percent != lastpercent) {
if (percent != lastpercent)
{
lastpercent = percent; lastpercent = percent;
printf("\rUpload %d%%", percent); printf("\rUpload %d%%", percent);
fflush(stdout); fflush(stdout);
} }
jbus::s64 curTime = jbus::GetGCTicks(); jbus::s64 curTime = jbus::GetGCTicks();
jbus::s64 passedTicks = curTime - start; jbus::s64 passedTicks = curTime - start;
if (passedTicks > jbus::GetGCTicksPerSec() * 10) if (passedTicks > jbus::GetGCTicksPerSec() * 10) {
{
fprintf(stderr, "JoyBoot timeout\n"); fprintf(stderr, "JoyBoot timeout\n");
return 1; return 1;
} }
@ -114,12 +99,10 @@ int main(int argc, char** argv)
} }
printf("\nJoy Boot finished with %d status\n", status); printf("\nJoy Boot finished with %d status\n", status);
while (!DonePoll(*endpoint)) while (!DonePoll(*endpoint)) {
{
jbus::s64 curTime = jbus::GetGCTicks(); jbus::s64 curTime = jbus::GetGCTicks();
jbus::s64 passedTicks = curTime - start; jbus::s64 passedTicks = curTime - start;
if (passedTicks > jbus::GetGCTicksPerSec() * 15) if (passedTicks > jbus::GetGCTicksPerSec() * 15) {
{
fprintf(stderr, "JoyBoot timeout\n"); fprintf(stderr, "JoyBoot timeout\n");
return 1; return 1;
} }