Add Doxygen comments

This commit is contained in:
Jack Andersen 2017-01-07 13:55:41 -10:00
parent a3fe0a3a25
commit 4699542f93
9 changed files with 2708 additions and 175 deletions

9
DocMain.md Normal file
View File

@ -0,0 +1,9 @@
JBus Documentation {#mainpage}
==============================
JBus functions as a server for acceping connections from GBA emulator clients.
The jbus::Listener class may be constructed and [started](@ref jbus::Listener::start)
to enque incoming jbus::Endpoint instances.
Once an Endpoint has been [accepted](@ref jbus::Listener::accept), it's ready to use.
Refer to the jbus::Endpoint class for the main interface.

2406
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2016-2017 JBus Contributors
Original Authors: Jack Andersen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,8 +1,17 @@
## JBus
This is a library for communicating with emulated GameBoy Advance instances
using the JoyBus protocol, linked over TCP.
using the JoyBus protocol linked over TCP.
Currently, only [VBA-M](https://github.com/visualboyadvance-m/visualboyadvance-m)
is known to function. It uses the same networking method as the
[Dolphin](https://github.com/dolphin-emu/dolphin) GameCube emulator.
### Documentation
[Doxygen docs are available!](http://axiodl.github.io/jbus)
### Example
[Refer to the `joyboot.cpp`](https://github.com/AxioDL/jbus/blob/master/tools/joyboot.cpp)
implementation for a good usage example.

View File

@ -17,6 +17,8 @@ using u32 = uint32_t;
using s64 = int64_t;
using u64 = uint64_t;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#undef bswap16
#undef bswap32
#undef bswap64
@ -139,6 +141,8 @@ static inline double SBig(double val) {return val;}
class Endpoint;
class ThreadLocalEndpoint;
#endif
enum EJStatFlags
{
GBA_JSTAT_MASK = 0x3a,
@ -159,11 +163,24 @@ enum EJoyReturn
GBA_JOYBOOT_ERR_INVALID = 4
};
/** @brief Standard callback for asynchronous jbus::Endpoint APIs.
* @param endpoint Thread-local Endpoint interface for optionally issuing next command in sequence.
* @param status GBA_READY if connection is still open, GBA_NOT_READY if connection lost. */
using FGBACallback = std::function<void(ThreadLocalEndpoint& endpoint, EJoyReturn status)>;
/** @brief Get host system's timebase scaled into Dolphin ticks.
* @return Scaled ticks from host timebase. */
u64 GetGCTicks();
/** @brief Wait an approximate Dolphin tick duration (avoid using, it's rather inaccurate).
* @param ticks CPU ticks to wait. */
void WaitGCTicks(u64 ticks);
/** @brief Obtain CPU ticks per second of Dolphin hardware (clock speed).
* @return 486Mhz - always. */
static constexpr u64 GetGCTicksPerSec() { return 486000000ull; }
/** @brief Initialize platform specifics of JBus library */
void Initialize();
}

View File

@ -11,118 +11,124 @@
namespace jbus
{
/** Self-contained class for solving Kawasedo's GBA BootROM challenge.
* GBA will boot client_pad.bin code on completion. */
class KawasedoChallenge
{
/** 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 */
struct DSPSecParms
{
/* Nonce challenge (first read from GBA, hence already little-endian) */
u32 x0_gbaChallenge;
/* Palette of pulsing logo on GBA during transmission [0,6] */
u32 x4_logoPalette;
/* Speed and direction of palette interpolation [-4,4] */
u32 x8_logoSpeed;
/* Length of JoyBoot program to upload */
u32 xc_progLength;
/* Unwrapped public key */
u32 x20_publicKey;
/* Message authentication code */
u32 x24_authInitCode;
void ProcessGBACrypto()
{
/* Unwrap key from challenge using 'sedo' magic number (to encrypt JoyBoot program) */
x20_publicKey = x0_gbaChallenge ^ 0x6f646573;
/* Pack palette parameters */
u16 paletteSpeedCoded;
s16 logoSpeed = static_cast<s8>(x8_logoSpeed);
if (logoSpeed < 0)
paletteSpeedCoded = ((-logoSpeed + 2) * 2) | (x4_logoPalette << 4);
else if (logoSpeed == 0)
paletteSpeedCoded = (x4_logoPalette * 2) | 0x70;
else /* logo_speed > 0 */
paletteSpeedCoded = ((logoSpeed - 1) * 2) | (x4_logoPalette << 4);
/* JoyBoot ROMs start with a padded header; this is the length beyond that header */
s32 lengthNoHeader = ROUND_UP_8(xc_progLength) - 0x200;
/* The JoyBus protocol transmits in 4-byte packets while flipping a state flag;
* so the GBA BIOS counts the program length in 8-byte packet-pairs */
u16 packetPairCount = (lengthNoHeader < 0) ? 0 : lengthNoHeader / 8;
paletteSpeedCoded |= (packetPairCount & 0x4000) >> 14;
/* Pack together encoded transmission parameters */
u32 t1 = (((packetPairCount << 16) | 0x3f80) & 0x3f80ffff) * 2;
t1 += (static_cast<s16>(static_cast<s8>(t1 >> 8)) & packetPairCount) << 16;
u32 t2 = ((paletteSpeedCoded & 0xff) << 16) + (t1 & 0xff0000) + ((t1 >> 8) & 0xffff00);
u32 t3 = paletteSpeedCoded << 16 | ((t2 << 8) & 0xff000000) | (t1 >> 16) | 0x80808080;
/* Wrap with 'Kawa' or 'sedo' (Kawasedo is the author of the BIOS cipher) */
x24_authInitCode = t3 ^ ((t3 & 0x200) != 0 ? 0x6f646573 : 0x6177614b);
}
} xf8_dspHmac;
s32 x0_pColor;
s32 x4_pSpeed;
u8* x8_progPtr;
u32 xc_progLen;
u8* x10_statusPtr;
FGBACallback x14_callback;
u8 x18_readBuf[4];
u8 x1c_writeBuf[4];
s32 x20_byteInWindow;
u64 x28_ticksAfterXf;
u32 x30_justStarted;
u32 x34_bytesSent;
u32 x38_crc;
u32 x3c_checkStore[7];
s32 x58_currentKey;
s32 x5c_initMessage;
s32 x60_gameId;
u32 x64_totalBytes;
bool m_started = true;
void F23(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F25(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F27(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F29(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void GBAX02();
void GBAX01(ThreadLocalEndpoint& endpoint);
void F31(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F33(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F35(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F37(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F39(ThreadLocalEndpoint& endpoint, EJoyReturn status);
auto bindThis(void(KawasedoChallenge::*ptmf)(ThreadLocalEndpoint&, EJoyReturn))
{
return std::bind(ptmf, this, std::placeholders::_1, std::placeholders::_2);
}
public:
KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status, FGBACallback&& callback);
bool started() const { return m_started; }
u8 percentComplete() const
{
if (!x64_totalBytes)
return 0;
return x34_bytesSent * 100 / x64_totalBytes;
}
bool isDone() const { return !x14_callback; }
};
/** Main class for performing JoyBoot and subsequent JoyBus I/O operations.
* Instances should be obtained though the jbus::Listener::accept method. */
class Endpoint
{
/** Self-contained class for solving Kawasedo's GBA BootROM challenge.
* GBA will boot client_pad.bin code on completion.
*
* This class shouldn't be used directly. JoyBoot operations are started
* via jbus::Endpoint::GBAJoyBootAsync. The JoyBoot status may be obtained
* via jbus::Endpoint::GBAGetProcessStatus. */
class KawasedoChallenge
{
/** 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 */
struct DSPSecParms
{
/* Nonce challenge (first read from GBA, hence already little-endian) */
u32 x0_gbaChallenge;
/* Palette of pulsing logo on GBA during transmission [0,6] */
u32 x4_logoPalette;
/* Speed and direction of palette interpolation [-4,4] */
u32 x8_logoSpeed;
/* Length of JoyBoot program to upload */
u32 xc_progLength;
/* Unwrapped public key */
u32 x20_publicKey;
/* Message authentication code */
u32 x24_authInitCode;
void ProcessGBACrypto()
{
/* Unwrap key from challenge using 'sedo' magic number (to encrypt JoyBoot program) */
x20_publicKey = x0_gbaChallenge ^ 0x6f646573;
/* Pack palette parameters */
u16 paletteSpeedCoded;
s16 logoSpeed = static_cast<s8>(x8_logoSpeed);
if (logoSpeed < 0)
paletteSpeedCoded = ((-logoSpeed + 2) * 2) | (x4_logoPalette << 4);
else if (logoSpeed == 0)
paletteSpeedCoded = (x4_logoPalette * 2) | 0x70;
else /* logo_speed > 0 */
paletteSpeedCoded = ((logoSpeed - 1) * 2) | (x4_logoPalette << 4);
/* JoyBoot ROMs start with a padded header; this is the length beyond that header */
s32 lengthNoHeader = ROUND_UP_8(xc_progLength) - 0x200;
/* The JoyBus protocol transmits in 4-byte packets while flipping a state flag;
* so the GBA BIOS counts the program length in 8-byte packet-pairs */
u16 packetPairCount = (lengthNoHeader < 0) ? 0 : lengthNoHeader / 8;
paletteSpeedCoded |= (packetPairCount & 0x4000) >> 14;
/* Pack together encoded transmission parameters */
u32 t1 = (((packetPairCount << 16) | 0x3f80) & 0x3f80ffff) * 2;
t1 += (static_cast<s16>(static_cast<s8>(t1 >> 8)) & packetPairCount) << 16;
u32 t2 = ((paletteSpeedCoded & 0xff) << 16) + (t1 & 0xff0000) + ((t1 >> 8) & 0xffff00);
u32 t3 = paletteSpeedCoded << 16 | ((t2 << 8) & 0xff000000) | (t1 >> 16) | 0x80808080;
/* Wrap with 'Kawa' or 'sedo' (Kawasedo is the author of the BIOS cipher) */
x24_authInitCode = t3 ^ ((t3 & 0x200) != 0 ? 0x6f646573 : 0x6177614b);
}
} xf8_dspHmac;
s32 x0_pColor;
s32 x4_pSpeed;
const u8* x8_progPtr;
u32 xc_progLen;
u8* x10_statusPtr;
FGBACallback x14_callback;
u8 x18_readBuf[4];
u8 x1c_writeBuf[4];
s32 x20_byteInWindow;
u64 x28_ticksAfterXf;
u32 x30_justStarted;
u32 x34_bytesSent;
u32 x38_crc;
u32 x3c_checkStore[7];
s32 x58_currentKey;
s32 x5c_initMessage;
s32 x60_gameId;
u32 x64_totalBytes;
bool m_started = true;
void _0Reset(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _1GetStatus(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _2ReadChallenge(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _3DSPCrypto(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _DSPCryptoInit();
void _DSPCryptoDone(ThreadLocalEndpoint& endpoint);
void _4TransmitProgram(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _5StartBootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _6BootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void _8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status);
auto bindThis(void(KawasedoChallenge::*ptmf)(ThreadLocalEndpoint&, EJoyReturn))
{
return std::bind(ptmf, this, std::placeholders::_1, std::placeholders::_2);
}
public:
KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed,
const u8* programp, s32 length, u8* status, FGBACallback&& callback);
bool started() const { return m_started; }
u8 percentComplete() const
{
if (!x64_totalBytes)
return 0;
return x34_bytesSent * 100 / x64_totalBytes;
}
bool isDone() const { return !x14_callback; }
};
friend class ThreadLocalEndpoint;
enum EJoybusCmds
@ -154,7 +160,6 @@ class Endpoint
bool m_cmdIssued = false;
bool m_running = true;
static u64 getTransferTime(u8 cmd);
void clockSync();
void send(const u8* buffer);
size_t receive(u8* buffer);
@ -170,34 +175,122 @@ class Endpoint
}
public:
/** @brief Request stop of I/O thread and block until joined.
* Further use of this Endpoint is undefined behavior.
* The destructor calls this implicitly. */
void stop();
EJoyReturn GBAGetProcessStatus(u8* percentp);
/** @brief Get status of last asynchronous operation.
* @param percentOut Reference to output transfer percent of GBAJoyBootAsync.
* @return GBA_READY when idle, or GBA_BUSY when operation in progress. */
EJoyReturn GBAGetProcessStatus(u8& percentOut);
/** @brief Get JOYSTAT register from GBA asynchronously.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAGetStatusAsync(u8* status, FGBACallback&& callback);
/** @brief Get JOYSTAT register from GBA synchronously.
* @param status Destination pointer for EJStatFlags.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAGetStatus(u8* status);
/** @brief Send RESET command to GBA asynchronously.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAResetAsync(u8* status, FGBACallback&& callback);
/** @brief Send RESET command to GBA synchronously.
* @param status Destination pointer for EJStatFlags.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAReset(u8* status);
/** @brief Send READ command to GBA asynchronously.
* @param dst Destination pointer for 4-byte packet of data.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback);
/** @brief Send READ command to GBA synchronously.
* @param dst Destination pointer for 4-byte packet of data.
* @param status Destination pointer for EJStatFlags.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBARead(u8* dst, u8* status);
/** @brief Send WRITE command to GBA asynchronously.
* @param src Source pointer for 4-byte packet of data. It is not required to keep resident.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAWriteAsync(const u8* src, u8* status, FGBACallback&& callback);
/** @brief Send WRITE command to GBA synchronously.
* @param src Source pointer for 4-byte packet of data. It is not required to keep resident.
* @param status Destination pointer for EJStatFlags.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAWrite(const u8* src, u8* status);
/** @brief Initiate JoyBoot sequence on this endpoint.
* @param paletteColor Palette for displaying logo in ROM header [0,6].
* @param paletteSpeed Palette interpolation speed for displaying logo in ROM header [-4,4].
* @param programp Pointer to program ROM data.
* @param length Length of program ROM data.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status,
const u8* programp, s32 length, u8* status,
FGBACallback&& callback);
/** @brief Get virtual SI channel assigned to this endpoint.
* @return SI channel */
int GetChan() const { return m_chan; }
Endpoint(u8 chan, net::Socket&& data, net::Socket&& clock);
~Endpoint();
};
/** Lockless wrapper interface for jbus::Endpoint.
* This class is constructed internally and supplied as a callback argument.
* It should not be constructed directly. */
class ThreadLocalEndpoint
{
friend class Endpoint;
Endpoint& m_ep;
ThreadLocalEndpoint(Endpoint& ep) : m_ep(ep) {}
public:
/** @brief Get JOYSTAT register from GBA asynchronously.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAGetStatusAsync(u8* status, FGBACallback&& callback);
/** @brief Send RESET command to GBA asynchronously.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAResetAsync(u8* status, FGBACallback&& callback);
/** @brief Send READ command to GBA asynchronously.
* @param dst Destination pointer for 4-byte packet of data.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAReadAsync(u8* dst, u8* status, FGBACallback&& callback);
/** @brief Send WRITE command to GBA asynchronously.
* @param src Source pointer for 4-byte packet of data. It is not required to keep resident.
* @param status Destination pointer for EJStatFlags.
* @param callback Functor to execute when operation completes.
* @return GBA_READY if submitted, or GBA_NOT_READY if another operation in progress. */
EJoyReturn GBAWriteAsync(const u8* src, u8* status, FGBACallback&& callback);
/** @brief Get virtual SI channel assigned to this endpoint.
* @return SI channel */
int GetChan() const { return m_ep.GetChan(); }
};

View File

@ -10,6 +10,7 @@
namespace jbus
{
/** Server interface for accepting incoming connections from GBA emulator instances. */
class Listener
{
net::Socket m_dataServer = {false};
@ -25,9 +26,16 @@ class Listener
void listenerProc();
public:
/** @brief Start listener thread. */
void start();
/** @brief Request stop of listener thread and block until joined. */
void stop();
/** @brief Pop jbus::Endpoint off Listener's queue.
* @return Endpoint instance, ready to issue commands. */
std::unique_ptr<Endpoint> accept();
~Listener();
};

View File

@ -5,11 +5,11 @@
namespace jbus
{
void KawasedoChallenge::F23(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_0Reset(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status != GBA_READY ||
(status = endpoint.GBAResetAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F25))) != GBA_READY)
bindThis(&KawasedoChallenge::_1GetStatus))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -20,7 +20,7 @@ void KawasedoChallenge::F23(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F25(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_1GetStatus(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status == GBA_READY)
if (*x10_statusPtr != GBA_JSTAT_SEND)
@ -28,7 +28,7 @@ void KawasedoChallenge::F25(ThreadLocalEndpoint& endpoint, EJoyReturn status)
if (status != GBA_READY ||
(status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F27))) != GBA_READY)
bindThis(&KawasedoChallenge::_2ReadChallenge))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -39,7 +39,7 @@ void KawasedoChallenge::F25(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F27(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_2ReadChallenge(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status == GBA_READY)
if (*x10_statusPtr != (GBA_JSTAT_PSF0 | GBA_JSTAT_SEND))
@ -47,7 +47,7 @@ void KawasedoChallenge::F27(ThreadLocalEndpoint& endpoint, EJoyReturn status)
if (status != GBA_READY ||
(status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F29))) != GBA_READY)
bindThis(&KawasedoChallenge::_3DSPCrypto))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -58,7 +58,7 @@ void KawasedoChallenge::F27(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F29(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_3DSPCrypto(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status != GBA_READY)
{
@ -71,12 +71,12 @@ void KawasedoChallenge::F29(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
else
{
GBAX02();
GBAX01(endpoint);
_DSPCryptoInit();
_DSPCryptoDone(endpoint);
}
}
void KawasedoChallenge::GBAX02()
void Endpoint::KawasedoChallenge::_DSPCryptoInit()
{
xf8_dspHmac.x0_gbaChallenge = reinterpret_cast<u32&>(x18_readBuf);
xf8_dspHmac.x4_logoPalette = x0_pColor;
@ -85,7 +85,7 @@ void KawasedoChallenge::GBAX02()
xf8_dspHmac.ProcessGBACrypto();
}
void KawasedoChallenge::GBAX01(ThreadLocalEndpoint& endpoint)
void Endpoint::KawasedoChallenge::_DSPCryptoDone(ThreadLocalEndpoint& endpoint)
{
x58_currentKey = xf8_dspHmac.x20_publicKey;
x5c_initMessage = xf8_dspHmac.x24_authInitCode;
@ -107,7 +107,7 @@ void KawasedoChallenge::GBAX01(ThreadLocalEndpoint& endpoint)
EJoyReturn status;
if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F31))) != GBA_READY)
bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -118,7 +118,7 @@ void KawasedoChallenge::GBAX01(ThreadLocalEndpoint& endpoint)
}
}
void KawasedoChallenge::F31(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_4TransmitProgram(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status != GBA_READY)
{
@ -240,7 +240,7 @@ void KawasedoChallenge::F31(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F31))) != GBA_READY)
bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -253,7 +253,7 @@ void KawasedoChallenge::F31(ThreadLocalEndpoint& endpoint, EJoyReturn status)
else // x34_bytesWritten > x64_totalBytes
{
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F33))) != GBA_READY)
bindThis(&KawasedoChallenge::_5StartBootPoll))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -265,11 +265,11 @@ void KawasedoChallenge::F31(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F33(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_5StartBootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status != GBA_READY ||
(status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F35))) != GBA_READY)
bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -280,7 +280,7 @@ void KawasedoChallenge::F33(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F35(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_6BootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status == GBA_READY)
if (*x10_statusPtr & (GBA_JSTAT_FLAGS_MASK | GBA_JSTAT_RECV))
@ -300,7 +300,7 @@ void KawasedoChallenge::F35(ThreadLocalEndpoint& endpoint, EJoyReturn status)
if (*x10_statusPtr != GBA_JSTAT_SEND)
{
if ((status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F35))) != GBA_READY)
bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -313,7 +313,7 @@ void KawasedoChallenge::F35(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F37))) != GBA_READY)
bindThis(&KawasedoChallenge::_7BootAcknowledge))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -324,11 +324,11 @@ void KawasedoChallenge::F35(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F37(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status != GBA_READY ||
(status = endpoint.GBAWriteAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F39))) != GBA_READY)
bindThis(&KawasedoChallenge::_8BootDone))) != GBA_READY)
{
x28_ticksAfterXf = 0;
if (x14_callback)
@ -339,7 +339,7 @@ void KawasedoChallenge::F37(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
void KawasedoChallenge::F39(ThreadLocalEndpoint& endpoint, EJoyReturn status)
void Endpoint::KawasedoChallenge::_8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status)
{
if (status == GBA_READY)
*x10_statusPtr = 0;
@ -353,50 +353,19 @@ void KawasedoChallenge::F39(ThreadLocalEndpoint& endpoint, EJoyReturn status)
}
}
KawasedoChallenge::KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status, FGBACallback&& callback)
Endpoint::KawasedoChallenge::KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed,
const u8* programp, s32 length, u8* status, FGBACallback&& callback)
: x0_pColor(paletteColor), x4_pSpeed(paletteSpeed), x8_progPtr(programp), xc_progLen(length),
x10_statusPtr(status), x14_callback(std::move(callback)), x34_bytesSent(0)
{
if (endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F23)) != GBA_READY)
bindThis(&KawasedoChallenge::_0Reset)) != GBA_READY)
{
x14_callback = {};
m_started = false;
}
}
u64 Endpoint::getTransferTime(u8 cmd)
{
u64 bytes = 0;
switch (cmd)
{
case CMD_RESET:
case CMD_STATUS:
{
bytes = 4;
break;
}
case CMD_READ:
{
bytes = 6;
break;
}
case CMD_WRITE:
{
bytes = 1;
break;
}
default:
{
bytes = 1;
break;
}
}
return bytes * GetGCTicksPerSec() / BYTES_PER_SECOND;
}
void Endpoint::clockSync()
{
if (!m_clockSocket)
@ -598,12 +567,12 @@ void Endpoint::stop()
m_transferThread.join();
}
EJoyReturn Endpoint::GBAGetProcessStatus(u8* percentp)
EJoyReturn Endpoint::GBAGetProcessStatus(u8& percentOut)
{
std::unique_lock<std::mutex> lk(m_syncLock);
if (m_joyBoot)
{
*percentp = m_joyBoot->percentComplete();
percentOut = m_joyBoot->percentComplete();
if (!m_joyBoot->isDone())
return GBA_BUSY;
}
@ -753,7 +722,7 @@ EJoyReturn Endpoint::GBAWrite(const u8* src, u8* status)
}
EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status,
const u8* programp, s32 length, u8* status,
FGBACallback&& callback)
{
if (m_chan > 3)

View File

@ -95,7 +95,7 @@ int main(int argc, char** argv)
jbus::s64 start = jbus::GetGCTicks();
jbus::u8 percent = 0;
jbus::u8 lastpercent = 0;
while (endpoint->GBAGetProcessStatus(&percent) == jbus::GBA_BUSY)
while (endpoint->GBAGetProcessStatus(percent) == jbus::GBA_BUSY)
{
if (percent != lastpercent)
{