mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-10-01 21:36:53 -05:00
Making SPI receive the DataSize so 8-bit and 32-bit packets can be used in the same project
This commit is contained in:
@@ -310,7 +310,7 @@ Name | Return type | Description
|
||||
|
||||
*(aka Normal Mode)*
|
||||
|
||||
This is the GBA's implementation of SPI. You can use this to interact with other GBAs or computers that know SPI. By default, it uses 32-bit packets, but you can switch to 8-bit by enabling the compile-time constant `LINK_SPI_8BIT_MODE`.
|
||||
This is the GBA's implementation of SPI. You can use this to interact with other GBAs or computers that know SPI.
|
||||
|
||||

|
||||
|
||||
@@ -319,7 +319,7 @@ This is the GBA's implementation of SPI. You can use this to interact with other
|
||||
Name | Return type | Description
|
||||
--- | --- | ---
|
||||
`isActive()` | **bool** | Returns whether the library is active or not.
|
||||
`activate(mode)` | - | Activates the library in a specific `mode` (one of `LinkSPI::Mode::SLAVE`, `LinkSPI::Mode::MASTER_256KBPS`, or `LinkSPI::Mode::MASTER_2MBPS`).
|
||||
`activate(mode, [dataSize])` | - | Activates the library in a specific `mode` (one of `LinkSPI::Mode::SLAVE`, `LinkSPI::Mode::MASTER_256KBPS`, or `LinkSPI::Mode::MASTER_2MBPS`). By default, the `dataSize` is 32-bit, but can be changed to `LinkSPI::DataSize::SIZE_8BIT`.
|
||||
`deactivate()` | - | Deactivates the library.
|
||||
`transfer(data)` | **u32** | Exchanges `data` with the other end. Returns the received data.
|
||||
`transfer(data, cancel)` | **u32** | Like `transfer(data)` but accepts a `cancel()` function. The library will continuously invoke it, and abort the transfer if it returns `true`.
|
||||
@@ -327,6 +327,7 @@ Name | Return type | Description
|
||||
`getAsyncState()` | **LinkSPI::AsyncState** | Returns the state of the last async transfer (one of `LinkSPI::AsyncState::IDLE`, `LinkSPI::AsyncState::WAITING`, or `LinkSPI::AsyncState::READY`).
|
||||
`getAsyncData()` | **u32** | If the async state is `READY`, returns the remote data and switches the state back to `IDLE`. If not, returns an empty response.
|
||||
`getMode()` | **LinkSPI::Mode** | Returns the current `mode`.
|
||||
`getDataSize()` | **LinkSPI::DataSize** | Returns the current `dataSize`.
|
||||
`setWaitModeActive(isActive)` | - | Enables or disables `waitMode` (*).
|
||||
`isWaitModeActive()` | **bool** | Returns whether `waitMode` (*) is active or not.
|
||||
|
||||
|
||||
@@ -42,14 +42,17 @@ int main() {
|
||||
output += "\n(stop: press L+R)\n";
|
||||
output += "(hold A on start for async)\n";
|
||||
output += "(hold B on start for waitMode)\n";
|
||||
output += "(hold UP for 8-bit mode)\n";
|
||||
output +=
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\n[!] to test this demo...\n "
|
||||
"\n\n\n\n\n\n\n\n\n[!] to test this demo...\n "
|
||||
"...use a GBC Link Cable!";
|
||||
|
||||
if ((keys & KEY_START) | (keys & KEY_SELECT)) {
|
||||
// (3) Initialize the library
|
||||
linkSPI->activate((keys & KEY_START) ? LinkSPI::Mode::MASTER_256KBPS
|
||||
: LinkSPI::Mode::SLAVE);
|
||||
: LinkSPI::Mode::SLAVE,
|
||||
(keys & KEY_UP) ? LinkSPI::DataSize::SIZE_8BIT
|
||||
: LinkSPI::DataSize::SIZE_32BIT);
|
||||
linkSPI->setWaitModeActive(keys &
|
||||
KEY_B); // see `waitMode` in README.md
|
||||
if (keys & KEY_A)
|
||||
|
||||
@@ -1014,7 +1014,7 @@ class LinkRawWireless {
|
||||
false, customAck);
|
||||
|
||||
if (customAck && !acknowledge())
|
||||
return LINK_SPI_NO_DATA;
|
||||
return LINK_SPI_NO_DATA_32;
|
||||
|
||||
return receivedData;
|
||||
}
|
||||
@@ -1032,7 +1032,7 @@ class LinkRawWireless {
|
||||
false, true);
|
||||
|
||||
if (!reverseAcknowledgeStart())
|
||||
return LINK_SPI_NO_DATA;
|
||||
return LINK_SPI_NO_DATA_32;
|
||||
|
||||
return receivedData;
|
||||
}
|
||||
|
||||
@@ -42,37 +42,14 @@
|
||||
|
||||
#include "_link_common.hpp"
|
||||
|
||||
/**
|
||||
* @brief 8-bit mode (uncomment to enable)
|
||||
*/
|
||||
// #define LINK_SPI_8BIT_MODE
|
||||
|
||||
static volatile char LINK_SPI_VERSION[] = "LinkSPI/v7.0.0";
|
||||
|
||||
#ifdef LINK_SPI_8BIT_MODE
|
||||
#define LINK_SPI_DATA_TYPE u8
|
||||
#endif
|
||||
#ifndef LINK_SPI_8BIT_MODE
|
||||
#define LINK_SPI_DATA_TYPE u32
|
||||
#endif
|
||||
|
||||
#ifdef LINK_SPI_8BIT_MODE
|
||||
#define LINK_SPI_DATA_REG Link::_REG_SIODATA8
|
||||
#endif
|
||||
#ifndef LINK_SPI_8BIT_MODE
|
||||
#define LINK_SPI_DATA_REG Link::_REG_SIODATA32
|
||||
#endif
|
||||
|
||||
#ifdef LINK_SPI_8BIT_MODE
|
||||
#define LINK_SPI_NO_DATA 0xff
|
||||
#endif
|
||||
#ifndef LINK_SPI_8BIT_MODE
|
||||
#define LINK_SPI_NO_DATA 0xffffffff
|
||||
#endif
|
||||
#define LINK_SPI_NO_DATA_32 0xffffffff
|
||||
#define LINK_SPI_NO_DATA_8 0xff
|
||||
#define LINK_SPI_NO_DATA LINK_SPI_NO_DATA_32
|
||||
|
||||
/**
|
||||
* @brief An SPI handler for the Link Port (Normal Mode, either 32 or 8 bits).
|
||||
* 32-bit transfers by default. Set `LINK_SPI_8BIT_MODE` for 8-bit transfers.
|
||||
*/
|
||||
class LinkSPI {
|
||||
private:
|
||||
@@ -92,6 +69,7 @@ class LinkSPI {
|
||||
|
||||
public:
|
||||
enum Mode { SLAVE, MASTER_256KBPS, MASTER_2MBPS };
|
||||
enum DataSize { SIZE_32BIT, SIZE_8BIT };
|
||||
enum AsyncState { IDLE, WAITING, READY };
|
||||
|
||||
/**
|
||||
@@ -102,9 +80,11 @@ class LinkSPI {
|
||||
/**
|
||||
* @brief Activates the library in a specific `mode`.
|
||||
* @param mode One of the enum values from `LinkSPI::Mode`.
|
||||
* @param dataSize One of the enum values from `LinkSPI::DataSize`.
|
||||
*/
|
||||
void activate(Mode mode) {
|
||||
void activate(Mode mode, DataSize dataSize = SIZE_32BIT) {
|
||||
this->mode = mode;
|
||||
this->dataSize = dataSize;
|
||||
this->waitMode = false;
|
||||
this->asyncState = IDLE;
|
||||
this->asyncData = 0;
|
||||
@@ -144,7 +124,7 @@ class LinkSPI {
|
||||
* @param data The value to be sent.
|
||||
* \warning Blocks the system until completion.
|
||||
*/
|
||||
LINK_SPI_DATA_TYPE transfer(LINK_SPI_DATA_TYPE data) {
|
||||
u32 transfer(u32 data) {
|
||||
return transfer(data, []() { return false; });
|
||||
}
|
||||
|
||||
@@ -156,12 +136,12 @@ class LinkSPI {
|
||||
* \warning Blocks the system until completion or cancellation.
|
||||
*/
|
||||
template <typename F>
|
||||
LINK_SPI_DATA_TYPE transfer(LINK_SPI_DATA_TYPE data,
|
||||
F cancel,
|
||||
bool _async = false,
|
||||
bool _customAck = false) {
|
||||
u32 transfer(u32 data,
|
||||
F cancel,
|
||||
bool _async = false,
|
||||
bool _customAck = false) {
|
||||
if (asyncState != IDLE)
|
||||
return LINK_SPI_NO_DATA;
|
||||
return noData();
|
||||
|
||||
setData(data);
|
||||
|
||||
@@ -177,20 +157,20 @@ class LinkSPI {
|
||||
disableTransfer();
|
||||
setInterruptsOff();
|
||||
asyncState = IDLE;
|
||||
return LINK_SPI_NO_DATA;
|
||||
return noData();
|
||||
}
|
||||
|
||||
enableTransfer();
|
||||
startTransfer();
|
||||
|
||||
if (_async)
|
||||
return LINK_SPI_NO_DATA;
|
||||
return noData();
|
||||
|
||||
while (!isReady())
|
||||
if (cancel()) {
|
||||
stopTransfer();
|
||||
disableTransfer();
|
||||
return LINK_SPI_NO_DATA;
|
||||
return noData();
|
||||
}
|
||||
|
||||
if (!_customAck)
|
||||
@@ -207,7 +187,7 @@ class LinkSPI {
|
||||
* \warning If `waitMode` (*) is active, blocks the system until completion.
|
||||
* See `setWaitModeActive(...)`.
|
||||
*/
|
||||
void transferAsync(LINK_SPI_DATA_TYPE data) {
|
||||
void transferAsync(u32 data) {
|
||||
transfer(data, []() { return false; }, true);
|
||||
}
|
||||
|
||||
@@ -222,7 +202,7 @@ class LinkSPI {
|
||||
* cancellation. See `setWaitModeActive(...)`.
|
||||
*/
|
||||
template <typename F>
|
||||
void transferAsync(LINK_SPI_DATA_TYPE data, F cancel) {
|
||||
void transferAsync(u32 data, F cancel) {
|
||||
transfer(data, cancel, true);
|
||||
}
|
||||
|
||||
@@ -236,11 +216,11 @@ class LinkSPI {
|
||||
* @brief If the async state is `READY`, returns the remote data and switches
|
||||
* the state back to `IDLE`. If not, returns an empty response.
|
||||
*/
|
||||
[[nodiscard]] LINK_SPI_DATA_TYPE getAsyncData() {
|
||||
[[nodiscard]] u32 getAsyncData() {
|
||||
if (asyncState != READY)
|
||||
return LINK_SPI_NO_DATA;
|
||||
return noData();
|
||||
|
||||
LINK_SPI_DATA_TYPE data = asyncData;
|
||||
u32 data = asyncData;
|
||||
asyncState = IDLE;
|
||||
return data;
|
||||
}
|
||||
@@ -250,6 +230,11 @@ class LinkSPI {
|
||||
*/
|
||||
[[nodiscard]] Mode getMode() { return mode; }
|
||||
|
||||
/**
|
||||
* @brief Returns the current `dataSize`.
|
||||
*/
|
||||
[[nodiscard]] DataSize getDataSize() { return dataSize; }
|
||||
|
||||
/**
|
||||
* @brief Enables or disables `waitMode`: The GBA adds an extra feature over
|
||||
* SPI. When working as master, it can check whether the other terminal is
|
||||
@@ -304,19 +289,19 @@ class LinkSPI {
|
||||
|
||||
private:
|
||||
Mode mode = Mode::SLAVE;
|
||||
DataSize dataSize = DataSize::SIZE_32BIT;
|
||||
bool waitMode = false;
|
||||
AsyncState asyncState = IDLE;
|
||||
LINK_SPI_DATA_TYPE asyncData = 0;
|
||||
u32 asyncData = 0;
|
||||
volatile bool isEnabled = false;
|
||||
|
||||
void setNormalMode() {
|
||||
Link::_REG_RCNT = Link::_REG_RCNT & ~(1 << BIT_GENERAL_PURPOSE_HIGH);
|
||||
#ifdef LINK_SPI_8BIT_MODE
|
||||
Link::_REG_SIOCNT = 0;
|
||||
#endif
|
||||
#ifndef LINK_SPI_8BIT_MODE
|
||||
Link::_REG_SIOCNT = 1 << BIT_LENGTH;
|
||||
#endif
|
||||
|
||||
if (dataSize == SIZE_32BIT)
|
||||
Link::_REG_SIOCNT = 1 << BIT_LENGTH;
|
||||
else
|
||||
Link::_REG_SIOCNT = 0;
|
||||
}
|
||||
|
||||
void setGeneralPurposeMode() {
|
||||
@@ -324,8 +309,21 @@ class LinkSPI {
|
||||
(1 << BIT_GENERAL_PURPOSE_HIGH);
|
||||
}
|
||||
|
||||
void setData(LINK_SPI_DATA_TYPE data) { LINK_SPI_DATA_REG = data; }
|
||||
LINK_SPI_DATA_TYPE getData() { return LINK_SPI_DATA_REG; }
|
||||
void setData(u32 data) {
|
||||
if (dataSize == SIZE_32BIT)
|
||||
Link::_REG_SIODATA32 = data;
|
||||
else
|
||||
Link::_REG_SIODATA8 = data & 0xff;
|
||||
}
|
||||
|
||||
u32 getData() {
|
||||
return dataSize == SIZE_32BIT ? Link::_REG_SIODATA32
|
||||
: Link::_REG_SIODATA8 & 0xff;
|
||||
}
|
||||
|
||||
u32 noData() {
|
||||
return dataSize == SIZE_32BIT ? LINK_SPI_NO_DATA_32 : LINK_SPI_NO_DATA_8;
|
||||
}
|
||||
|
||||
void enableTransfer() { _setSOLow(); }
|
||||
void disableTransfer() { _setSOHigh(); }
|
||||
|
||||
@@ -1792,7 +1792,7 @@ class LinkWireless {
|
||||
false, customAck);
|
||||
|
||||
if (customAck && !acknowledge())
|
||||
return LINK_SPI_NO_DATA;
|
||||
return LINK_SPI_NO_DATA_32;
|
||||
|
||||
return receivedData;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user