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 ## JBus
This is a library for communicating with emulated GameBoy Advance instances 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) Currently, only [VBA-M](https://github.com/visualboyadvance-m/visualboyadvance-m)
is known to function. It uses the same networking method as the is known to function. It uses the same networking method as the
[Dolphin](https://github.com/dolphin-emu/dolphin) GameCube emulator. [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 s64 = int64_t;
using u64 = uint64_t; using u64 = uint64_t;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#undef bswap16 #undef bswap16
#undef bswap32 #undef bswap32
#undef bswap64 #undef bswap64
@ -139,6 +141,8 @@ static inline double SBig(double val) {return val;}
class Endpoint; class Endpoint;
class ThreadLocalEndpoint; class ThreadLocalEndpoint;
#endif
enum EJStatFlags enum EJStatFlags
{ {
GBA_JSTAT_MASK = 0x3a, GBA_JSTAT_MASK = 0x3a,
@ -159,11 +163,24 @@ enum EJoyReturn
GBA_JOYBOOT_ERR_INVALID = 4 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)>; 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(); 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); void WaitGCTicks(u64 ticks);
/** @brief Obtain CPU ticks per second of Dolphin hardware (clock speed).
* @return 486Mhz - always. */
static constexpr u64 GetGCTicksPerSec() { return 486000000ull; } static constexpr u64 GetGCTicksPerSec() { return 486000000ull; }
/** @brief Initialize platform specifics of JBus library */
void Initialize(); void Initialize();
} }

View File

@ -11,8 +11,16 @@
namespace jbus namespace jbus
{ {
/** 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. /** 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
* via jbus::Endpoint::GBAJoyBootAsync. The JoyBoot status may be obtained
* 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
@ -73,7 +81,7 @@ class KawasedoChallenge
s32 x0_pColor; s32 x0_pColor;
s32 x4_pSpeed; s32 x4_pSpeed;
u8* x8_progPtr; const u8* x8_progPtr;
u32 xc_progLen; u32 xc_progLen;
u8* x10_statusPtr; u8* x10_statusPtr;
FGBACallback x14_callback; FGBACallback x14_callback;
@ -91,17 +99,17 @@ class KawasedoChallenge
u32 x64_totalBytes; u32 x64_totalBytes;
bool m_started = true; bool m_started = true;
void F23(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _0Reset(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F25(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _1GetStatus(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F27(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _2ReadChallenge(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F29(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _3DSPCrypto(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void GBAX02(); void _DSPCryptoInit();
void GBAX01(ThreadLocalEndpoint& endpoint); void _DSPCryptoDone(ThreadLocalEndpoint& endpoint);
void F31(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _4TransmitProgram(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F33(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _5StartBootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F35(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _6BootPoll(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F37(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _7BootAcknowledge(ThreadLocalEndpoint& endpoint, EJoyReturn status);
void F39(ThreadLocalEndpoint& endpoint, EJoyReturn status); void _8BootDone(ThreadLocalEndpoint& endpoint, EJoyReturn status);
auto bindThis(void(KawasedoChallenge::*ptmf)(ThreadLocalEndpoint&, EJoyReturn)) auto bindThis(void(KawasedoChallenge::*ptmf)(ThreadLocalEndpoint&, EJoyReturn))
{ {
@ -110,7 +118,7 @@ class KawasedoChallenge
public: public:
KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed, KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status, FGBACallback&& callback); const u8* programp, s32 length, u8* status, FGBACallback&& callback);
bool started() const { return m_started; } bool started() const { return m_started; }
u8 percentComplete() const u8 percentComplete() const
{ {
@ -121,8 +129,6 @@ public:
bool isDone() const { return !x14_callback; } bool isDone() const { return !x14_callback; }
}; };
class Endpoint
{
friend class ThreadLocalEndpoint; friend class ThreadLocalEndpoint;
enum EJoybusCmds enum EJoybusCmds
@ -154,7 +160,6 @@ class Endpoint
bool m_cmdIssued = false; bool m_cmdIssued = false;
bool m_running = true; bool m_running = true;
static u64 getTransferTime(u8 cmd);
void clockSync(); void clockSync();
void send(const u8* buffer); void send(const u8* buffer);
size_t receive(u8* buffer); size_t receive(u8* buffer);
@ -170,34 +175,122 @@ class Endpoint
} }
public: 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(); 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); 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); 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); 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); 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); 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); 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); 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); 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, EJoyReturn GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed,
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.
* @return SI channel */
int GetChan() const { return m_chan; } int GetChan() const { return m_chan; }
Endpoint(u8 chan, net::Socket&& data, net::Socket&& clock); Endpoint(u8 chan, net::Socket&& data, net::Socket&& clock);
~Endpoint(); ~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 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) {}
public: 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); 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); 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); 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); 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(); } int GetChan() const { return m_ep.GetChan(); }
}; };

View File

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

View File

@ -5,11 +5,11 @@
namespace jbus namespace jbus
{ {
void KawasedoChallenge::F23(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::F25))) != GBA_READY) bindThis(&KawasedoChallenge::_1GetStatus))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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 (status == GBA_READY)
if (*x10_statusPtr != GBA_JSTAT_SEND) if (*x10_statusPtr != GBA_JSTAT_SEND)
@ -28,7 +28,7 @@ void KawasedoChallenge::F25(ThreadLocalEndpoint& endpoint, EJoyReturn status)
if (status != GBA_READY || if (status != GBA_READY ||
(status = endpoint.GBAGetStatusAsync(x10_statusPtr, (status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F27))) != GBA_READY) bindThis(&KawasedoChallenge::_2ReadChallenge))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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 (status == GBA_READY)
if (*x10_statusPtr != (GBA_JSTAT_PSF0 | GBA_JSTAT_SEND)) if (*x10_statusPtr != (GBA_JSTAT_PSF0 | GBA_JSTAT_SEND))
@ -47,7 +47,7 @@ void KawasedoChallenge::F27(ThreadLocalEndpoint& endpoint, EJoyReturn status)
if (status != GBA_READY || if (status != GBA_READY ||
(status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, (status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F29))) != GBA_READY) bindThis(&KawasedoChallenge::_3DSPCrypto))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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) if (status != GBA_READY)
{ {
@ -71,12 +71,12 @@ void KawasedoChallenge::F29(ThreadLocalEndpoint& endpoint, EJoyReturn status)
} }
else else
{ {
GBAX02(); _DSPCryptoInit();
GBAX01(endpoint); _DSPCryptoDone(endpoint);
} }
} }
void KawasedoChallenge::GBAX02() 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;
@ -85,7 +85,7 @@ void KawasedoChallenge::GBAX02()
xf8_dspHmac.ProcessGBACrypto(); xf8_dspHmac.ProcessGBACrypto();
} }
void KawasedoChallenge::GBAX01(ThreadLocalEndpoint& endpoint) void Endpoint::KawasedoChallenge::_DSPCryptoDone(ThreadLocalEndpoint& endpoint)
{ {
x58_currentKey = xf8_dspHmac.x20_publicKey; x58_currentKey = xf8_dspHmac.x20_publicKey;
x5c_initMessage = xf8_dspHmac.x24_authInitCode; x5c_initMessage = xf8_dspHmac.x24_authInitCode;
@ -107,7 +107,7 @@ void KawasedoChallenge::GBAX01(ThreadLocalEndpoint& endpoint)
EJoyReturn status; EJoyReturn status;
if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr, if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F31))) != GBA_READY) bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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) if (status != GBA_READY)
{ {
@ -240,7 +240,7 @@ void KawasedoChallenge::F31(ThreadLocalEndpoint& endpoint, EJoyReturn status)
} }
if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr, if ((status = endpoint.GBAWriteAsync(x1c_writeBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F31))) != GBA_READY) bindThis(&KawasedoChallenge::_4TransmitProgram))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback)
@ -253,7 +253,7 @@ void KawasedoChallenge::F31(ThreadLocalEndpoint& endpoint, EJoyReturn status)
else // x34_bytesWritten > x64_totalBytes else // x34_bytesWritten > x64_totalBytes
{ {
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F33))) != GBA_READY) bindThis(&KawasedoChallenge::_5StartBootPoll))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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 || if (status != GBA_READY ||
(status = endpoint.GBAGetStatusAsync(x10_statusPtr, (status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F35))) != GBA_READY) bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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 (status == GBA_READY)
if (*x10_statusPtr & (GBA_JSTAT_FLAGS_MASK | GBA_JSTAT_RECV)) 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 (*x10_statusPtr != GBA_JSTAT_SEND)
{ {
if ((status = endpoint.GBAGetStatusAsync(x10_statusPtr, if ((status = endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F35))) != GBA_READY) bindThis(&KawasedoChallenge::_6BootPoll))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) if (x14_callback)
@ -313,7 +313,7 @@ void KawasedoChallenge::F35(ThreadLocalEndpoint& endpoint, EJoyReturn status)
} }
if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr, if ((status = endpoint.GBAReadAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F37))) != GBA_READY) bindThis(&KawasedoChallenge::_7BootAcknowledge))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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 || if (status != GBA_READY ||
(status = endpoint.GBAWriteAsync(x18_readBuf, x10_statusPtr, (status = endpoint.GBAWriteAsync(x18_readBuf, x10_statusPtr,
bindThis(&KawasedoChallenge::F39))) != GBA_READY) bindThis(&KawasedoChallenge::_8BootDone))) != GBA_READY)
{ {
x28_ticksAfterXf = 0; x28_ticksAfterXf = 0;
if (x14_callback) 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) if (status == GBA_READY)
*x10_statusPtr = 0; *x10_statusPtr = 0;
@ -353,50 +353,19 @@ void KawasedoChallenge::F39(ThreadLocalEndpoint& endpoint, EJoyReturn status)
} }
} }
KawasedoChallenge::KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed, Endpoint::KawasedoChallenge::KawasedoChallenge(Endpoint& endpoint, s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status, FGBACallback&& callback) const u8* programp, s32 length, u8* status, FGBACallback&& callback)
: x0_pColor(paletteColor), x4_pSpeed(paletteSpeed), x8_progPtr(programp), xc_progLen(length), : x0_pColor(paletteColor), x4_pSpeed(paletteSpeed), x8_progPtr(programp), xc_progLen(length),
x10_statusPtr(status), x14_callback(std::move(callback)), x34_bytesSent(0) x10_statusPtr(status), x14_callback(std::move(callback)), x34_bytesSent(0)
{ {
if (endpoint.GBAGetStatusAsync(x10_statusPtr, if (endpoint.GBAGetStatusAsync(x10_statusPtr,
bindThis(&KawasedoChallenge::F23)) != GBA_READY) bindThis(&KawasedoChallenge::_0Reset)) != GBA_READY)
{ {
x14_callback = {}; x14_callback = {};
m_started = false; 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() void Endpoint::clockSync()
{ {
if (!m_clockSocket) if (!m_clockSocket)
@ -598,12 +567,12 @@ void Endpoint::stop()
m_transferThread.join(); m_transferThread.join();
} }
EJoyReturn Endpoint::GBAGetProcessStatus(u8* percentp) EJoyReturn Endpoint::GBAGetProcessStatus(u8& percentOut)
{ {
std::unique_lock<std::mutex> lk(m_syncLock); std::unique_lock<std::mutex> lk(m_syncLock);
if (m_joyBoot) if (m_joyBoot)
{ {
*percentp = m_joyBoot->percentComplete(); percentOut = m_joyBoot->percentComplete();
if (!m_joyBoot->isDone()) if (!m_joyBoot->isDone())
return GBA_BUSY; return GBA_BUSY;
} }
@ -753,7 +722,7 @@ EJoyReturn Endpoint::GBAWrite(const u8* src, u8* status)
} }
EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed, EJoyReturn Endpoint::GBAJoyBootAsync(s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status, const u8* programp, s32 length, u8* status,
FGBACallback&& callback) FGBACallback&& callback)
{ {
if (m_chan > 3) if (m_chan > 3)

View File

@ -95,7 +95,7 @@ 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)
{ {