diff --git a/examples/LinkSPI_demo/src/main.cpp b/examples/LinkSPI_demo/src/main.cpp index a9423d7..cdab63a 100644 --- a/examples/LinkSPI_demo/src/main.cpp +++ b/examples/LinkSPI_demo/src/main.cpp @@ -1,10 +1,10 @@ +// (0) Include the header +#include "../../../lib/LinkSPI.hpp" + #include #include #include "../../_lib/interrupt.h" -// (0) Include the header -#include "../../../lib/LinkSPI.hpp" - void log(std::string text); void wait(u32 verticalLines); inline void VBLANK() {} diff --git a/lib/LinkPS2Keyboard.hpp b/lib/LinkPS2Keyboard.hpp index 5d80b0a..2c5f0b2 100644 --- a/lib/LinkPS2Keyboard.hpp +++ b/lib/LinkPS2Keyboard.hpp @@ -17,6 +17,10 @@ // linkPS2Keyboard->activate(); // - 4) Handle events in the callback sent to LinkPS2Keyboard's constructor! // -------------------------------------------------------------------------- +// (*) libtonc's interrupt handler sometimes ignores interrupts due to a bug. +// That causes packet loss. You REALLY want to use libugba's instead. +// (see examples) +// -------------------------------------------------------------------------- // ____________ // | Pinout | // |PS/2 --- GBA| diff --git a/lib/LinkPS2Mouse.hpp b/lib/LinkPS2Mouse.hpp index 9c98610..8d713c2 100644 --- a/lib/LinkPS2Mouse.hpp +++ b/lib/LinkPS2Mouse.hpp @@ -8,7 +8,7 @@ // Usage: // - 1) Include this header in your main.cpp file and add: // LinkPS2Mouse* linkPS2Mouse = new LinkPS2Mouse(); -// - 2) Add the required interrupt service routines: (*) +// - 2) Add the required interrupt service routines: // irq_init(NULL); // irq_add(II_TIMER2, NULL); // - 3) Initialize the library with: diff --git a/lib/LinkRawCable.hpp b/lib/LinkRawCable.hpp index e991c75..7cd1310 100644 --- a/lib/LinkRawCable.hpp +++ b/lib/LinkRawCable.hpp @@ -7,7 +7,7 @@ // Usage: // - 1) Include this header in your main.cpp file and add: // LinkRawCable* linkRawCable = new LinkRawCable(); -// - 2) (Optional) Add the interrupt service routines: +// - 2) (Optional) Add the interrupt service routines: (*) // irq_init(NULL); // irq_add(II_SERIAL, LINK_RAW_CABLE_ISR_SERIAL); // // (this is only required for `transferAsync`) @@ -17,7 +17,7 @@ // LinkRawCable::Response data = linkRawCable->transfer(0x1234); // // (this blocks the console indefinitely) // - 5) Exchange data with a cancellation callback: -// auto data = linkRawCable->transfer(0x1234, []() { +// LinkRawCable::Response data = linkRawCable->transfer(0x1234, []() { // auto keys = ~REG_KEYS & KEY_ANY; // return keys & KEY_START; // }); @@ -25,10 +25,14 @@ // linkRawCable->transferAsync(0x1234); // // ... // if (linkRawCable->getAsyncState() == LinkRawCable::AsyncState::READY) { -// auto data = linkRawCable->getAsyncData(); +// LinkRawCable::Response data = linkRawCable->getAsyncData(); // // ... // } // -------------------------------------------------------------------------- +// (*) libtonc's interrupt handler sometimes ignores interrupts due to a bug. +// That causes packet loss. You REALLY want to use libugba's instead. +// (see examples) +// -------------------------------------------------------------------------- // considerations: // - don't send 0xFFFF, it's a reserved value that means // - only transfer(...) if isReady() diff --git a/lib/LinkSPI.hpp b/lib/LinkSPI.hpp index 8d08566..ba5ca6d 100644 --- a/lib/LinkSPI.hpp +++ b/lib/LinkSPI.hpp @@ -2,7 +2,7 @@ #define LINK_SPI_H // -------------------------------------------------------------------------- -// An SPI handler for the Link Port (Normal Mode, 32bits). +// An SPI handler for the Link Port (Normal Mode, either 32 or 8 bits). // -------------------------------------------------------------------------- // Usage: // - 1) Include this header in your main.cpp file and add: @@ -15,18 +15,18 @@ // linkSPI->activate(LinkSPI::Mode::MASTER_256KBPS); // // (use LinkSPI::Mode::SLAVE on the other end) // - 4) Exchange 32-bit data with the other end: -// u32 data = linkSPI->transfer(0x12345678); +// auto data = linkSPI->transfer(0x12345678); // // (this blocks the console indefinitely) // - 5) Exchange data with a cancellation callback: -// u32 data = linkSPI->transfer(0x12345678, []() { -// u16 keys = ~REG_KEYS & KEY_ANY; +// auto data = linkSPI->transfer(0x12345678, []() { +// auto keys = ~REG_KEYS & KEY_ANY; // return keys & KEY_START; // }); // - 6) Exchange data asynchronously: // linkSPI->transferAsync(0x12345678); // // ... // if (linkSPI->getAsyncState() == LinkSPI::AsyncState::READY) { -// u32 data = linkSPI->getAsyncData(); +// auto data = linkSPI->getAsyncData(); // // ... // } // -------------------------------------------------------------------------- @@ -40,7 +40,7 @@ // - don't send 0xFFFFFFFF, it's reserved for errors! // -------------------------------------------------------------------------- -#include +#include "_link_common.h" // 8-bit mode (uncomment to enable) // #define LINK_SPI_8BIT_MODE @@ -53,10 +53,10 @@ #endif #ifdef LINK_SPI_8BIT_MODE -#define LINK_SPI_DATA_REG REG_SIODATA8 +#define LINK_SPI_DATA_REG Link::_REG_SIODATA8 #endif #ifndef LINK_SPI_8BIT_MODE -#define LINK_SPI_DATA_REG REG_SIODATA32 +#define LINK_SPI_DATA_REG Link::_REG_SIODATA32 #endif #ifdef LINK_SPI_8BIT_MODE @@ -66,27 +66,28 @@ #define LINK_SPI_NO_DATA 0xffffffff #endif -#define LINK_SPI_BIT_CLOCK 0 -#define LINK_SPI_BIT_CLOCK_SPEED 1 -#define LINK_SPI_BIT_SI 2 -#define LINK_SPI_BIT_SO 3 -#define LINK_SPI_BIT_START 7 -#define LINK_SPI_BIT_LENGTH 12 -#define LINK_SPI_BIT_IRQ 14 -#define LINK_SPI_BIT_GENERAL_PURPOSE_LOW 14 -#define LINK_SPI_BIT_GENERAL_PURPOSE_HIGH 15 - static volatile char LINK_SPI_VERSION[] = "LinkSPI/v7.0.0"; -const u32 LINK_SPI_MASK_CLEAR_SO_BIT = ~(1 << LINK_SPI_BIT_SO); -const u32 LINK_SPI_MASK_SET_START_BIT = (1 << LINK_SPI_BIT_START); - class LinkSPI { + private: + using u32 = unsigned int; + using u8 = unsigned char; + + static constexpr int BIT_CLOCK = 0; + static constexpr int BIT_CLOCK_SPEED = 1; + static constexpr int BIT_SI = 2; + static constexpr int BIT_SO = 3; + static constexpr int BIT_START = 7; + static constexpr int BIT_LENGTH = 12; + static constexpr int BIT_IRQ = 14; + static constexpr int BIT_GENERAL_PURPOSE_LOW = 14; + static constexpr int BIT_GENERAL_PURPOSE_HIGH = 15; + public: enum Mode { SLAVE, MASTER_256KBPS, MASTER_2MBPS }; enum AsyncState { IDLE, WAITING, READY }; - bool isActive() { return isEnabled; } + [[nodiscard]] bool isActive() { return isEnabled; } void activate(Mode mode) { this->mode = mode; @@ -178,7 +179,7 @@ class LinkSPI { transfer(data, cancel, true); } - LINK_SPI_DATA_TYPE getAsyncData() { + [[nodiscard]] LINK_SPI_DATA_TYPE getAsyncData() { if (asyncState != READY) return LINK_SPI_NO_DATA; @@ -187,10 +188,10 @@ class LinkSPI { return data; } - Mode getMode() { return mode; } + [[nodiscard]] Mode getMode() { return mode; } void setWaitModeActive(bool isActive) { waitMode = isActive; } - bool isWaitModeActive() { return waitMode; } - AsyncState getAsyncState() { return asyncState; } + [[nodiscard]] bool isWaitModeActive() { return waitMode; } + [[nodiscard]] AsyncState getAsyncState() { return asyncState; } void _onSerial(bool _customAck = false) { if (!isEnabled || asyncState != WAITING) @@ -204,9 +205,9 @@ class LinkSPI { asyncData = getData(); } - void _setSOHigh() { setBitHigh(LINK_SPI_BIT_SO); } - void _setSOLow() { setBitLow(LINK_SPI_BIT_SO); } - bool _isSIHigh() { return isBitHigh(LINK_SPI_BIT_SI); } + void _setSOHigh() { setBitHigh(BIT_SO); } + void _setSOLow() { setBitLow(BIT_SO); } + [[nodiscard]] bool _isSIHigh() { return isBitHigh(BIT_SI); } private: Mode mode = Mode::SLAVE; @@ -216,18 +217,18 @@ class LinkSPI { volatile bool isEnabled = false; void setNormalMode32Bit() { - REG_RCNT = REG_RCNT & ~(1 << LINK_SPI_BIT_GENERAL_PURPOSE_HIGH); + Link::_REG_RCNT = Link::_REG_RCNT & ~(1 << BIT_GENERAL_PURPOSE_HIGH); #ifdef LINK_SPI_8BIT_MODE - REG_SIOCNT = 0; + Link::_REG_SIOCNT = 0; #endif #ifndef LINK_SPI_8BIT_MODE - REG_SIOCNT = 1 << LINK_SPI_BIT_LENGTH; + Link::_REG_SIOCNT = 1 << BIT_LENGTH; #endif } void setGeneralPurposeMode() { - REG_RCNT = (REG_RCNT & ~(1 << LINK_SPI_BIT_GENERAL_PURPOSE_LOW)) | - (1 << LINK_SPI_BIT_GENERAL_PURPOSE_HIGH); + Link::_REG_RCNT = (Link::_REG_RCNT & ~(1 << BIT_GENERAL_PURPOSE_LOW)) | + (1 << BIT_GENERAL_PURPOSE_HIGH); } void setData(LINK_SPI_DATA_TYPE data) { LINK_SPI_DATA_REG = data; } @@ -235,22 +236,22 @@ class LinkSPI { void enableTransfer() { _setSOLow(); } void disableTransfer() { _setSOHigh(); } - void startTransfer() { setBitHigh(LINK_SPI_BIT_START); } - void stopTransfer() { setBitLow(LINK_SPI_BIT_START); } - bool isReady() { return !isBitHigh(LINK_SPI_BIT_START); } + void startTransfer() { setBitHigh(BIT_START); } + void stopTransfer() { setBitLow(BIT_START); } + bool isReady() { return !isBitHigh(BIT_START); } bool isSlaveReady() { return !_isSIHigh(); } - void setMasterMode() { setBitHigh(LINK_SPI_BIT_CLOCK); } - void setSlaveMode() { setBitLow(LINK_SPI_BIT_CLOCK); } - void set256KbpsSpeed() { setBitLow(LINK_SPI_BIT_CLOCK_SPEED); } - void set2MbpsSpeed() { setBitHigh(LINK_SPI_BIT_CLOCK_SPEED); } - void setInterruptsOn() { setBitHigh(LINK_SPI_BIT_IRQ); } - void setInterruptsOff() { setBitLow(LINK_SPI_BIT_IRQ); } + void setMasterMode() { setBitHigh(BIT_CLOCK); } + void setSlaveMode() { setBitLow(BIT_CLOCK); } + void set256KbpsSpeed() { setBitLow(BIT_CLOCK_SPEED); } + void set2MbpsSpeed() { setBitHigh(BIT_CLOCK_SPEED); } + void setInterruptsOn() { setBitHigh(BIT_IRQ); } + void setInterruptsOff() { setBitLow(BIT_IRQ); } bool isMaster() { return mode != SLAVE; } - bool isBitHigh(u8 bit) { return (REG_SIOCNT >> bit) & 1; } - void setBitHigh(u8 bit) { REG_SIOCNT |= 1 << bit; } - void setBitLow(u8 bit) { REG_SIOCNT &= ~(1 << bit); } + bool isBitHigh(u8 bit) { return (Link::_REG_SIOCNT >> bit) & 1; } + void setBitHigh(u8 bit) { Link::_REG_SIOCNT |= 1 << bit; } + void setBitLow(u8 bit) { Link::_REG_SIOCNT &= ~(1 << bit); } }; extern LinkSPI* linkSPI;