mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-09-12 19:07:20 -05:00
Using prefixes and moving structs/enums inside classes
This commit is contained in:
@@ -74,7 +74,7 @@ Name | Return type | Description
|
||||
--- | --- | ---
|
||||
`reset()` | - | Resets communication mode to General Purpose. **Required to initialize the library!**
|
||||
`setMode(pin, direction)` | - | Configures a `pin` to use a `direction` (input or output).
|
||||
`getMode(pin)` | **LinkPin** | Returns the direction set at `pin`.
|
||||
`getMode(pin)` | **LinkGPIO::Direction** | Returns the direction set at `pin`.
|
||||
`readPin(pin)` | **bool** | Returns whether a `pin` is *HIGH* or not (when set as an input).
|
||||
`writePin(pin, isHigh)` | - | Sets a `pin` to be high or not (when set as an output).
|
||||
`setSIInterrupts(isEnabled)` | - | If it `isEnabled`, a IRQ will be generated when `SI` changes from *HIGH* to *LOW*.
|
||||
@@ -19,11 +19,11 @@ void init() {
|
||||
|
||||
// (2) Add the interrupt service routines
|
||||
interrupt_init();
|
||||
interrupt_set_handler(INTR_VBLANK, LINK_ISR_VBLANK);
|
||||
interrupt_set_handler(INTR_VBLANK, LINK_CABLE_ISR_VBLANK);
|
||||
interrupt_enable(INTR_VBLANK);
|
||||
interrupt_set_handler(INTR_SERIAL, LINK_ISR_SERIAL);
|
||||
interrupt_set_handler(INTR_SERIAL, LINK_CABLE_ISR_SERIAL);
|
||||
interrupt_enable(INTR_SERIAL);
|
||||
interrupt_set_handler(INTR_TIMER3, LINK_ISR_TIMER);
|
||||
interrupt_set_handler(INTR_TIMER3, LINK_CABLE_ISR_TIMER);
|
||||
interrupt_enable(INTR_TIMER3);
|
||||
|
||||
// (3) Initialize the library
|
||||
@@ -33,8 +33,8 @@ void init() {
|
||||
int main() {
|
||||
init();
|
||||
|
||||
u16 data[LINK_MAX_PLAYERS];
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++) {
|
||||
u16 data[LINK_CABLE_MAX_PLAYERS];
|
||||
for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++) {
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ int main() {
|
||||
TextStream::instance().setText(
|
||||
"P" + asStr(linkCable->currentPlayerId()) + "/" +
|
||||
asStr(linkCable->playerCount()) + "-R" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_BIT_READY)) + "-S" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_BIT_START)) + "-E" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_BIT_ERROR)),
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_CABLE_BIT_READY)) + "-S" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_CABLE_BIT_START)) + "-E" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_CABLE_BIT_ERROR)),
|
||||
0, 14);
|
||||
|
||||
engine->update();
|
||||
@@ -60,11 +60,11 @@ inline void setUpInterrupts() {
|
||||
interrupt_init();
|
||||
|
||||
// LinkCable
|
||||
interrupt_set_handler(INTR_VBLANK, LINK_ISR_VBLANK);
|
||||
interrupt_set_handler(INTR_VBLANK, LINK_CABLE_ISR_VBLANK);
|
||||
interrupt_enable(INTR_VBLANK);
|
||||
interrupt_set_handler(INTR_SERIAL, LINK_ISR_SERIAL);
|
||||
interrupt_set_handler(INTR_SERIAL, LINK_CABLE_ISR_SERIAL);
|
||||
interrupt_enable(INTR_SERIAL);
|
||||
interrupt_set_handler(INTR_TIMER3, LINK_ISR_TIMER);
|
||||
interrupt_set_handler(INTR_TIMER3, LINK_CABLE_ISR_TIMER);
|
||||
interrupt_enable(INTR_TIMER3);
|
||||
|
||||
// A+B+START+SELECT
|
||||
|
||||
@@ -67,7 +67,7 @@ void TestScene::tick(u16 keys) {
|
||||
}
|
||||
|
||||
// determine which value should be sent
|
||||
u16 value = LINK_NO_DATA;
|
||||
u16 value = LINK_CABLE_NO_DATA;
|
||||
if (!initialized && linkCable->currentPlayerId() == 1) {
|
||||
initialized = true;
|
||||
value = 999;
|
||||
@@ -83,7 +83,7 @@ void TestScene::tick(u16 keys) {
|
||||
send(counter);
|
||||
counter++;
|
||||
send(counter);
|
||||
} else if (value != LINK_NO_DATA) {
|
||||
} else if (value != LINK_CABLE_NO_DATA) {
|
||||
send(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ void init() {
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
|
||||
interrupt_init();
|
||||
interrupt_set_handler(INTR_VBLANK, LINK_ISR_VBLANK);
|
||||
interrupt_set_handler(INTR_VBLANK, LINK_CABLE_ISR_VBLANK);
|
||||
interrupt_enable(INTR_VBLANK);
|
||||
interrupt_set_handler(INTR_SERIAL, LINK_ISR_SERIAL);
|
||||
interrupt_set_handler(INTR_SERIAL, LINK_CABLE_ISR_SERIAL);
|
||||
interrupt_enable(INTR_SERIAL);
|
||||
interrupt_set_handler(INTR_TIMER3, LINK_ISR_TIMER);
|
||||
interrupt_set_handler(INTR_TIMER3, LINK_CABLE_ISR_TIMER);
|
||||
interrupt_enable(INTR_TIMER3);
|
||||
|
||||
linkCable->activate();
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "../../_lib/LinkGPIO.h"
|
||||
|
||||
void log(std::string text);
|
||||
std::string mode(std::string name, LinkGPIO::Pin pin);
|
||||
std::string value(std::string name, LinkGPIO::Pin pin, bool isHigh);
|
||||
|
||||
LinkGPIO* linkGPIO = new LinkGPIO();
|
||||
|
||||
@@ -33,62 +35,44 @@ int main() {
|
||||
bool sendSCHigh = keys & KEY_A;
|
||||
|
||||
// Modes
|
||||
output += "SI: INPUT\n";
|
||||
output +=
|
||||
std::string("SO: ") +
|
||||
(linkGPIO->getMode(LinkPin::SO) == LinkDirection::OUTPUT ? "OUTPUT\n"
|
||||
: "INPUT\n");
|
||||
output +=
|
||||
std::string("SD: ") +
|
||||
(linkGPIO->getMode(LinkPin::SD) == LinkDirection::OUTPUT ? "OUTPUT\n"
|
||||
: "INPUT\n");
|
||||
output +=
|
||||
std::string("SC: ") +
|
||||
(linkGPIO->getMode(LinkPin::SC) == LinkDirection::OUTPUT ? "OUTPUT\n"
|
||||
: "INPUT\n");
|
||||
output += mode("SI", LinkGPIO::Pin::SI);
|
||||
output += mode("SO", LinkGPIO::Pin::SO);
|
||||
output += mode("SD", LinkGPIO::Pin::SD);
|
||||
output += mode("SC", LinkGPIO::Pin::SC);
|
||||
|
||||
// Separator
|
||||
output += "\n---\n\n";
|
||||
|
||||
// Values
|
||||
output += "< SI: " + std::to_string(linkGPIO->readPin(LinkPin::SI)) + "\n";
|
||||
output +=
|
||||
linkGPIO->getMode(LinkPin::SO) == LinkDirection::INPUT
|
||||
? "< SO: " + std::to_string(linkGPIO->readPin(LinkPin::SO)) + "\n"
|
||||
: "> SO: " + std::to_string(sendSOHigh) + "\n";
|
||||
output +=
|
||||
linkGPIO->getMode(LinkPin::SD) == LinkDirection::INPUT
|
||||
? "< SD: " + std::to_string(linkGPIO->readPin(LinkPin::SD)) + "\n"
|
||||
: "> SD: " + std::to_string(sendSDHigh) + "\n";
|
||||
output +=
|
||||
linkGPIO->getMode(LinkPin::SC) == LinkDirection::INPUT
|
||||
? "< SC: " + std::to_string(linkGPIO->readPin(LinkPin::SC)) + "\n"
|
||||
: "> SC: " + std::to_string(sendSCHigh) + "\n";
|
||||
output += value("SI", LinkGPIO::Pin::SI, false);
|
||||
output += value("SO", LinkGPIO::Pin::SO, sendSOHigh);
|
||||
output += value("SD", LinkGPIO::Pin::SD, sendSDHigh);
|
||||
output += value("SC", LinkGPIO::Pin::SC, sendSCHigh);
|
||||
|
||||
// Print
|
||||
log(output);
|
||||
|
||||
// Set modes
|
||||
if (setSOOutput)
|
||||
linkGPIO->setMode(LinkPin::SO, LinkDirection::OUTPUT);
|
||||
linkGPIO->setMode(LinkGPIO::Pin::SO, LinkGPIO::Direction::OUTPUT);
|
||||
if (setSDOutput)
|
||||
linkGPIO->setMode(LinkPin::SD, LinkDirection::OUTPUT);
|
||||
linkGPIO->setMode(LinkGPIO::Pin::SD, LinkGPIO::Direction::OUTPUT);
|
||||
if (setSCOutput)
|
||||
linkGPIO->setMode(LinkPin::SC, LinkDirection::OUTPUT);
|
||||
linkGPIO->setMode(LinkGPIO::Pin::SC, LinkGPIO::Direction::OUTPUT);
|
||||
if (setSOInput)
|
||||
linkGPIO->setMode(LinkPin::SO, LinkDirection::INPUT);
|
||||
linkGPIO->setMode(LinkGPIO::Pin::SO, LinkGPIO::Direction::INPUT);
|
||||
if (setSDInput)
|
||||
linkGPIO->setMode(LinkPin::SD, LinkDirection::INPUT);
|
||||
linkGPIO->setMode(LinkGPIO::Pin::SD, LinkGPIO::Direction::INPUT);
|
||||
if (setSCInput)
|
||||
linkGPIO->setMode(LinkPin::SC, LinkDirection::INPUT);
|
||||
linkGPIO->setMode(LinkGPIO::Pin::SC, LinkGPIO::Direction::INPUT);
|
||||
|
||||
// Set values
|
||||
if (linkGPIO->getMode(LinkPin::SO) == LinkDirection::OUTPUT)
|
||||
linkGPIO->writePin(LinkPin::SO, sendSOHigh);
|
||||
if (linkGPIO->getMode(LinkPin::SD) == LinkDirection::OUTPUT)
|
||||
linkGPIO->writePin(LinkPin::SD, sendSDHigh);
|
||||
if (linkGPIO->getMode(LinkPin::SC) == LinkDirection::OUTPUT)
|
||||
linkGPIO->writePin(LinkPin::SC, sendSCHigh);
|
||||
if (linkGPIO->getMode(LinkGPIO::Pin::SO) == LinkGPIO::Direction::OUTPUT)
|
||||
linkGPIO->writePin(LinkGPIO::Pin::SO, sendSOHigh);
|
||||
if (linkGPIO->getMode(LinkGPIO::Pin::SD) == LinkGPIO::Direction::OUTPUT)
|
||||
linkGPIO->writePin(LinkGPIO::Pin::SD, sendSDHigh);
|
||||
if (linkGPIO->getMode(LinkGPIO::Pin::SC) == LinkGPIO::Direction::OUTPUT)
|
||||
linkGPIO->writePin(LinkGPIO::Pin::SC, sendSCHigh);
|
||||
|
||||
while (REG_VCOUNT >= 160)
|
||||
; // wait till VDraw
|
||||
@@ -103,4 +87,18 @@ void log(std::string text) {
|
||||
tte_erase_screen();
|
||||
tte_write("#{P:0,0}");
|
||||
tte_write(text.c_str());
|
||||
}
|
||||
|
||||
std::string mode(std::string name, LinkGPIO::Pin pin) {
|
||||
return name + ": " +
|
||||
(linkGPIO->getMode(pin) == LinkGPIO::Direction::OUTPUT ? "OUTPUT\n"
|
||||
: "INPUT\n");
|
||||
}
|
||||
|
||||
std::string value(std::string name, LinkGPIO::Pin pin, bool isHigh) {
|
||||
auto title = name + ": ";
|
||||
|
||||
return linkGPIO->getMode(pin) == LinkGPIO::Direction::INPUT
|
||||
? "< " + title + std::to_string(linkGPIO->readPin(pin)) + "\n"
|
||||
: "> " + title + std::to_string(isHigh) + "\n";
|
||||
}
|
||||
188
lib/LinkCable.h
188
lib/LinkCable.h
@@ -9,9 +9,9 @@
|
||||
// LinkCable* linkCable = new LinkCable();
|
||||
// - 2) Add the required interrupt service routines: (*)
|
||||
// irq_init(NULL);
|
||||
// irq_add(II_VBLANK, LINK_ISR_VBLANK);
|
||||
// irq_add(II_SERIAL, LINK_ISR_SERIAL);
|
||||
// irq_add(II_TIMER3, LINK_ISR_TIMER);
|
||||
// irq_add(II_VBLANK, LINK_CABLE_ISR_VBLANK);
|
||||
// irq_add(II_SERIAL, LINK_CABLE_ISR_SERIAL);
|
||||
// irq_add(II_TIMER3, LINK_CABLE_ISR_TIMER);
|
||||
// - 3) Initialize the library with:
|
||||
// linkCable->activate();
|
||||
// - 4) Send/read messages by using:
|
||||
@@ -38,66 +38,67 @@
|
||||
#include <tonc_core.h>
|
||||
#include <queue>
|
||||
|
||||
#define LINK_MAX_PLAYERS 4
|
||||
#define LINK_DISCONNECTED 0xFFFF
|
||||
#define LINK_NO_DATA 0x0
|
||||
#define LINK_DEFAULT_TIMEOUT 3
|
||||
#define LINK_DEFAULT_REMOTE_TIMEOUT 5
|
||||
#define LINK_DEFAULT_BUFFER_SIZE 30
|
||||
#define LINK_DEFAULT_INTERVAL 50
|
||||
#define LINK_DEFAULT_SEND_TIMER_ID 3
|
||||
#define LINK_BASE_FREQUENCY TM_FREQ_1024
|
||||
#define LINK_REMOTE_TIMEOUT_OFFLINE -1
|
||||
#define LINK_BIT_SLAVE 2
|
||||
#define LINK_BIT_READY 3
|
||||
#define LINK_BITS_PLAYER_ID 4
|
||||
#define LINK_BIT_ERROR 6
|
||||
#define LINK_BIT_START 7
|
||||
#define LINK_BIT_MULTIPLAYER 13
|
||||
#define LINK_BIT_IRQ 14
|
||||
#define LINK_BIT_GENERAL_PURPOSE_LOW 14
|
||||
#define LINK_BIT_GENERAL_PURPOSE_HIGH 15
|
||||
#define LINK_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
#define LINK_CABLE_MAX_PLAYERS 4
|
||||
#define LINK_CABLE_DISCONNECTED 0xFFFF
|
||||
#define LINK_CABLE_NO_DATA 0x0
|
||||
#define LINK_CABLE_DEFAULT_TIMEOUT 3
|
||||
#define LINK_CABLE_DEFAULT_REMOTE_TIMEOUT 5
|
||||
#define LINK_CABLE_DEFAULT_BUFFER_SIZE 30
|
||||
#define LINK_CABLE_DEFAULT_INTERVAL 50
|
||||
#define LINK_CABLE_DEFAULT_SEND_TIMER_ID 3
|
||||
#define LINK_CABLE_BASE_FREQUENCY TM_FREQ_1024
|
||||
#define LINK_CABLE_REMOTE_TIMEOUT_OFFLINE -1
|
||||
#define LINK_CABLE_BIT_SLAVE 2
|
||||
#define LINK_CABLE_BIT_READY 3
|
||||
#define LINK_CABLE_BITS_PLAYER_ID 4
|
||||
#define LINK_CABLE_BIT_ERROR 6
|
||||
#define LINK_CABLE_BIT_START 7
|
||||
#define LINK_CABLE_BIT_MULTIPLAYER 13
|
||||
#define LINK_CABLE_BIT_IRQ 14
|
||||
#define LINK_CABLE_BIT_GENERAL_PURPOSE_LOW 14
|
||||
#define LINK_CABLE_BIT_GENERAL_PURPOSE_HIGH 15
|
||||
#define LINK_CABLE_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_CABLE_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
|
||||
void LINK_ISR_VBLANK();
|
||||
void LINK_ISR_TIMER();
|
||||
void LINK_ISR_SERIAL();
|
||||
u16 LINK_QUEUE_POP(std::queue<u16>& q);
|
||||
void LINK_QUEUE_CLEAR(std::queue<u16>& q);
|
||||
const u16 LINK_TIMER_IRQ_IDS[] = {IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2,
|
||||
IRQ_TIMER3};
|
||||
|
||||
struct LinkPublicState {
|
||||
std::queue<u16> incomingMessages[LINK_MAX_PLAYERS];
|
||||
u8 playerCount;
|
||||
u8 currentPlayerId;
|
||||
bool isReady = false;
|
||||
bool isConsumed = false;
|
||||
};
|
||||
|
||||
struct LinkInternalState {
|
||||
std::queue<u16> outgoingMessages;
|
||||
int timeouts[LINK_MAX_PLAYERS];
|
||||
bool IRQFlag;
|
||||
u32 IRQTimeout;
|
||||
bool isAddingMessage = false;
|
||||
};
|
||||
void LINK_CABLE_ISR_VBLANK();
|
||||
void LINK_CABLE_ISR_TIMER();
|
||||
void LINK_CABLE_ISR_SERIAL();
|
||||
u16 LINK_CABLE_QUEUE_POP(std::queue<u16>& q);
|
||||
void LINK_CABLE_QUEUE_CLEAR(std::queue<u16>& q);
|
||||
const u16 LINK_CABLE_TIMER_IRQ_IDS[] = {IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2,
|
||||
IRQ_TIMER3};
|
||||
|
||||
class LinkCable {
|
||||
public:
|
||||
struct PublicState {
|
||||
std::queue<u16> incomingMessages[LINK_CABLE_MAX_PLAYERS];
|
||||
u8 playerCount;
|
||||
u8 currentPlayerId;
|
||||
bool isReady = false;
|
||||
bool isConsumed = false;
|
||||
};
|
||||
|
||||
struct InternalState {
|
||||
std::queue<u16> outgoingMessages;
|
||||
int timeouts[LINK_CABLE_MAX_PLAYERS];
|
||||
bool IRQFlag;
|
||||
u32 IRQTimeout;
|
||||
bool isAddingMessage = false;
|
||||
};
|
||||
|
||||
enum BaudRate {
|
||||
BAUD_RATE_0, // 9600 bps
|
||||
BAUD_RATE_1, // 38400 bps
|
||||
BAUD_RATE_2, // 57600 bps
|
||||
BAUD_RATE_3 // 115200 bps
|
||||
};
|
||||
|
||||
explicit LinkCable(BaudRate baudRate = BAUD_RATE_1,
|
||||
u32 timeout = LINK_DEFAULT_TIMEOUT,
|
||||
u32 remoteTimeout = LINK_DEFAULT_REMOTE_TIMEOUT,
|
||||
u32 bufferSize = LINK_DEFAULT_BUFFER_SIZE,
|
||||
u16 interval = LINK_DEFAULT_INTERVAL,
|
||||
u8 sendTimerId = LINK_DEFAULT_SEND_TIMER_ID) {
|
||||
u32 timeout = LINK_CABLE_DEFAULT_TIMEOUT,
|
||||
u32 remoteTimeout = LINK_CABLE_DEFAULT_REMOTE_TIMEOUT,
|
||||
u32 bufferSize = LINK_CABLE_DEFAULT_BUFFER_SIZE,
|
||||
u16 interval = LINK_CABLE_DEFAULT_INTERVAL,
|
||||
u8 sendTimerId = LINK_CABLE_DEFAULT_SEND_TIMER_ID) {
|
||||
this->baudRate = baudRate;
|
||||
this->timeout = timeout;
|
||||
this->remoteTimeout = remoteTimeout;
|
||||
@@ -138,15 +139,15 @@ class LinkCable {
|
||||
|
||||
u16 read(u8 playerId) {
|
||||
if (!$state.isReady)
|
||||
return LINK_NO_DATA;
|
||||
return LINK_CABLE_NO_DATA;
|
||||
|
||||
return LINK_QUEUE_POP($state.incomingMessages[playerId]);
|
||||
return LINK_CABLE_QUEUE_POP($state.incomingMessages[playerId]);
|
||||
}
|
||||
|
||||
void consume() { $state.isConsumed = true; }
|
||||
|
||||
void send(u16 data) {
|
||||
if (data == LINK_DISCONNECTED || data == LINK_NO_DATA)
|
||||
if (data == LINK_CABLE_DISCONNECTED || data == LINK_CABLE_NO_DATA)
|
||||
return;
|
||||
|
||||
_state.isAddingMessage = true;
|
||||
@@ -195,20 +196,20 @@ class LinkCable {
|
||||
_state.IRQTimeout = 0;
|
||||
|
||||
u8 newPlayerCount = 0;
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++) {
|
||||
for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++) {
|
||||
u16 data = REG_SIOMULTI[i];
|
||||
|
||||
if (data != LINK_DISCONNECTED) {
|
||||
if (data != LINK_NO_DATA && i != state.currentPlayerId)
|
||||
if (data != LINK_CABLE_DISCONNECTED) {
|
||||
if (data != LINK_CABLE_NO_DATA && i != state.currentPlayerId)
|
||||
push(state.incomingMessages[i], data);
|
||||
newPlayerCount++;
|
||||
_state.timeouts[i] = 0;
|
||||
} else if (_state.timeouts[i] > LINK_REMOTE_TIMEOUT_OFFLINE) {
|
||||
} else if (_state.timeouts[i] > LINK_CABLE_REMOTE_TIMEOUT_OFFLINE) {
|
||||
_state.timeouts[i]++;
|
||||
|
||||
if (_state.timeouts[i] >= (int)remoteTimeout) {
|
||||
LINK_QUEUE_CLEAR(state.incomingMessages[i]);
|
||||
_state.timeouts[i] = LINK_REMOTE_TIMEOUT_OFFLINE;
|
||||
LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]);
|
||||
_state.timeouts[i] = LINK_CABLE_REMOTE_TIMEOUT_OFFLINE;
|
||||
} else
|
||||
newPlayerCount++;
|
||||
}
|
||||
@@ -216,7 +217,8 @@ class LinkCable {
|
||||
|
||||
state.playerCount = newPlayerCount;
|
||||
state.currentPlayerId =
|
||||
(REG_SIOCNT & (0b11 << LINK_BITS_PLAYER_ID)) >> LINK_BITS_PLAYER_ID;
|
||||
(REG_SIOCNT & (0b11 << LINK_CABLE_BITS_PLAYER_ID)) >>
|
||||
LINK_CABLE_BITS_PLAYER_ID;
|
||||
|
||||
if (!isMaster())
|
||||
sendPendingData();
|
||||
@@ -225,9 +227,9 @@ class LinkCable {
|
||||
}
|
||||
|
||||
private:
|
||||
LinkPublicState state; // (updated state / back buffer)
|
||||
LinkPublicState $state; // (visible state / front buffer)
|
||||
LinkInternalState _state; // (internal state)
|
||||
PublicState state; // (updated state / back buffer)
|
||||
PublicState $state; // (visible state / front buffer)
|
||||
InternalState _state; // (internal state)
|
||||
BaudRate baudRate;
|
||||
u32 timeout;
|
||||
u32 remoteTimeout;
|
||||
@@ -236,24 +238,24 @@ class LinkCable {
|
||||
u8 sendTimerId;
|
||||
bool isEnabled = false;
|
||||
|
||||
bool isReady() { return isBitHigh(LINK_BIT_READY); }
|
||||
bool hasError() { return isBitHigh(LINK_BIT_ERROR); }
|
||||
bool isMaster() { return !isBitHigh(LINK_BIT_SLAVE); }
|
||||
bool isSending() { return isBitHigh(LINK_BIT_START); }
|
||||
bool isReady() { return isBitHigh(LINK_CABLE_BIT_READY); }
|
||||
bool hasError() { return isBitHigh(LINK_CABLE_BIT_ERROR); }
|
||||
bool isMaster() { return !isBitHigh(LINK_CABLE_BIT_SLAVE); }
|
||||
bool isSending() { return isBitHigh(LINK_CABLE_BIT_START); }
|
||||
bool didTimeout() { return _state.IRQTimeout >= timeout; }
|
||||
|
||||
void sendPendingData() {
|
||||
if (_state.isAddingMessage)
|
||||
return;
|
||||
|
||||
transfer(LINK_QUEUE_POP(_state.outgoingMessages));
|
||||
transfer(LINK_CABLE_QUEUE_POP(_state.outgoingMessages));
|
||||
}
|
||||
|
||||
void transfer(u16 data) {
|
||||
REG_SIOMLT_SEND = data;
|
||||
|
||||
if (isMaster())
|
||||
setBitHigh(LINK_BIT_START);
|
||||
setBitHigh(LINK_CABLE_BIT_START);
|
||||
}
|
||||
|
||||
bool resetIfNeeded() {
|
||||
@@ -274,11 +276,11 @@ class LinkCable {
|
||||
void resetState() {
|
||||
state.playerCount = 0;
|
||||
state.currentPlayerId = 0;
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++) {
|
||||
LINK_QUEUE_CLEAR(state.incomingMessages[i]);
|
||||
_state.timeouts[i] = LINK_REMOTE_TIMEOUT_OFFLINE;
|
||||
for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++) {
|
||||
LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]);
|
||||
_state.timeouts[i] = LINK_CABLE_REMOTE_TIMEOUT_OFFLINE;
|
||||
}
|
||||
LINK_QUEUE_CLEAR(_state.outgoingMessages);
|
||||
LINK_CABLE_QUEUE_CLEAR(_state.outgoingMessages);
|
||||
_state.IRQFlag = false;
|
||||
_state.IRQTimeout = 0;
|
||||
}
|
||||
@@ -286,18 +288,18 @@ class LinkCable {
|
||||
void stop() {
|
||||
stopTimer();
|
||||
|
||||
LINK_SET_LOW(REG_RCNT, LINK_BIT_GENERAL_PURPOSE_LOW);
|
||||
LINK_SET_HIGH(REG_RCNT, LINK_BIT_GENERAL_PURPOSE_HIGH);
|
||||
LINK_CABLE_SET_LOW(REG_RCNT, LINK_CABLE_BIT_GENERAL_PURPOSE_LOW);
|
||||
LINK_CABLE_SET_HIGH(REG_RCNT, LINK_CABLE_BIT_GENERAL_PURPOSE_HIGH);
|
||||
}
|
||||
|
||||
void start() {
|
||||
startTimer();
|
||||
|
||||
LINK_SET_LOW(REG_RCNT, LINK_BIT_GENERAL_PURPOSE_HIGH);
|
||||
LINK_CABLE_SET_LOW(REG_RCNT, LINK_CABLE_BIT_GENERAL_PURPOSE_HIGH);
|
||||
REG_SIOCNT = baudRate;
|
||||
REG_SIOMLT_SEND = 0;
|
||||
setBitHigh(LINK_BIT_MULTIPLAYER);
|
||||
setBitHigh(LINK_BIT_IRQ);
|
||||
setBitHigh(LINK_CABLE_BIT_MULTIPLAYER);
|
||||
setBitHigh(LINK_CABLE_BIT_IRQ);
|
||||
}
|
||||
|
||||
void stopTimer() {
|
||||
@@ -306,7 +308,7 @@ class LinkCable {
|
||||
|
||||
void startTimer() {
|
||||
REG_TM[sendTimerId].start = -interval;
|
||||
REG_TM[sendTimerId].cnt = TM_ENABLE | TM_IRQ | LINK_BASE_FREQUENCY;
|
||||
REG_TM[sendTimerId].cnt = TM_ENABLE | TM_IRQ | LINK_CABLE_BASE_FREQUENCY;
|
||||
}
|
||||
|
||||
void copyState() {
|
||||
@@ -317,48 +319,48 @@ class LinkCable {
|
||||
state.isConsumed = false;
|
||||
$state = state;
|
||||
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++)
|
||||
LINK_QUEUE_CLEAR(state.incomingMessages[i]);
|
||||
for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++)
|
||||
LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]);
|
||||
}
|
||||
|
||||
void push(std::queue<u16>& q, u16 value) {
|
||||
if (q.size() >= bufferSize)
|
||||
LINK_QUEUE_POP(q);
|
||||
LINK_CABLE_QUEUE_POP(q);
|
||||
|
||||
q.push(value);
|
||||
}
|
||||
|
||||
bool isBitHigh(u8 bit) { return (REG_SIOCNT >> bit) & 1; }
|
||||
void setBitHigh(u8 bit) { LINK_SET_HIGH(REG_SIOCNT, bit); }
|
||||
void setBitLow(u8 bit) { LINK_SET_LOW(REG_SIOCNT, bit); }
|
||||
void setBitHigh(u8 bit) { LINK_CABLE_SET_HIGH(REG_SIOCNT, bit); }
|
||||
void setBitLow(u8 bit) { LINK_CABLE_SET_LOW(REG_SIOCNT, bit); }
|
||||
};
|
||||
|
||||
extern LinkCable* linkCable;
|
||||
|
||||
inline void LINK_ISR_VBLANK() {
|
||||
inline void LINK_CABLE_ISR_VBLANK() {
|
||||
linkCable->_onVBlank();
|
||||
}
|
||||
|
||||
inline void LINK_ISR_TIMER() {
|
||||
inline void LINK_CABLE_ISR_TIMER() {
|
||||
linkCable->_onTimer();
|
||||
}
|
||||
|
||||
inline void LINK_ISR_SERIAL() {
|
||||
inline void LINK_CABLE_ISR_SERIAL() {
|
||||
linkCable->_onSerial();
|
||||
}
|
||||
|
||||
inline u16 LINK_QUEUE_POP(std::queue<u16>& q) {
|
||||
inline u16 LINK_CABLE_QUEUE_POP(std::queue<u16>& q) {
|
||||
if (q.empty())
|
||||
return LINK_NO_DATA;
|
||||
return LINK_CABLE_NO_DATA;
|
||||
|
||||
u16 value = q.front();
|
||||
q.pop();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline void LINK_QUEUE_CLEAR(std::queue<u16>& q) {
|
||||
inline void LINK_CABLE_QUEUE_CLEAR(std::queue<u16>& q) {
|
||||
while (!q.empty())
|
||||
LINK_QUEUE_POP(q);
|
||||
LINK_CABLE_QUEUE_POP(q);
|
||||
}
|
||||
|
||||
#endif // LINK_CABLE_H
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
// - 2) Initialize the library with:
|
||||
// linkGPIO->reset();
|
||||
// - 3) Write pins by using:
|
||||
// linkGPIO->setMode(LinkPin::SD, LinkDirection::OUTPUT);
|
||||
// linkGPIO->writePin(LinkPIN::SD, true);
|
||||
// linkGPIO->setMode(LinkGPIO::Pin::SD, LinkGPIO::Direction::OUTPUT);
|
||||
// linkGPIO->writePin(LinkGPIO::Pin::SD, true);
|
||||
// - 4) Read pins by using:
|
||||
// linkGPIO->setMode(LinkPin::SC, LinkDirection::INPUT);
|
||||
// bool isHigh = linkGPIO->readPin(LinkPin::SC);
|
||||
// linkGPIO->setMode(LinkGPIO::Pin::SC, LinkGPIO::Direction::INPUT);
|
||||
// bool isHigh = linkGPIO->readPin(LinkGPIO::Pin::SC);
|
||||
// - 5) Subscribe to SI falling:
|
||||
// linkGPIO->setSIInterrupts(true);
|
||||
// // (when SI changes from high to low, an IRQ will be generated)
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <tonc_core.h>
|
||||
|
||||
#define LINK_GPIO_MODE 15
|
||||
#define LINK_GPIO_BIT_SI_INTERRUPT 8
|
||||
#define LINK_GPIO_SET(REG, BIT, DATA) \
|
||||
if (DATA) \
|
||||
LINK_GPIO_SET_HIGH(REG, BIT); \
|
||||
@@ -34,42 +35,42 @@
|
||||
#define LINK_GPIO_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_GPIO_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
#define LINK_GPIO_GET(REG, BIT) ((REG >> BIT) & 1)
|
||||
#define LINK_GPIO_SI_INTERRUPT_BIT 8
|
||||
|
||||
enum LinkPin { SI, SO, SD, SC };
|
||||
enum LinkDirection { INPUT, OUTPUT };
|
||||
const u8 LINK_PIN_DATA_BITS[] = {2, 3, 1, 0};
|
||||
const u8 LINK_PIN_DIRECTION_BITS[] = {6, 7, 5, 4};
|
||||
const u8 LINK_GPIO_DATA_BITS[] = {2, 3, 1, 0};
|
||||
const u8 LINK_GPIO_DIRECTION_BITS[] = {6, 7, 5, 4};
|
||||
|
||||
class LinkGPIO {
|
||||
public:
|
||||
enum Pin { SI, SO, SD, SC };
|
||||
enum Direction { INPUT, OUTPUT };
|
||||
|
||||
void reset() {
|
||||
REG_RCNT = 1 << LINK_GPIO_MODE;
|
||||
REG_SIOCNT = 0;
|
||||
}
|
||||
|
||||
void setMode(LinkPin pin, LinkDirection direction) {
|
||||
if (pin == LinkPin::SI && LinkDirection::OUTPUT)
|
||||
void setMode(Pin pin, Direction direction) {
|
||||
if (pin == Pin::SI && Direction::OUTPUT)
|
||||
return; // (disabled for safety reasons)
|
||||
|
||||
LINK_GPIO_SET(REG_RCNT, LINK_PIN_DIRECTION_BITS[pin],
|
||||
direction == LinkDirection::OUTPUT);
|
||||
LINK_GPIO_SET(REG_RCNT, LINK_GPIO_DIRECTION_BITS[pin],
|
||||
direction == Direction::OUTPUT);
|
||||
}
|
||||
|
||||
LinkDirection getMode(LinkPin pin) {
|
||||
return LinkDirection(LINK_GPIO_GET(REG_RCNT, LINK_PIN_DIRECTION_BITS[pin]));
|
||||
Direction getMode(Pin pin) {
|
||||
return Direction(LINK_GPIO_GET(REG_RCNT, LINK_GPIO_DIRECTION_BITS[pin]));
|
||||
}
|
||||
|
||||
bool readPin(LinkPin pin) {
|
||||
return (REG_RCNT & (1 << LINK_PIN_DATA_BITS[pin])) != 0;
|
||||
bool readPin(Pin pin) {
|
||||
return (REG_RCNT & (1 << LINK_GPIO_DATA_BITS[pin])) != 0;
|
||||
}
|
||||
|
||||
void writePin(LinkPin pin, bool isHigh) {
|
||||
LINK_GPIO_SET(REG_RCNT, LINK_PIN_DATA_BITS[pin], isHigh);
|
||||
void writePin(Pin pin, bool isHigh) {
|
||||
LINK_GPIO_SET(REG_RCNT, LINK_GPIO_DATA_BITS[pin], isHigh);
|
||||
}
|
||||
|
||||
void setSIInterrupts(bool isEnabled) {
|
||||
LINK_GPIO_SET(REG_RCNT, LINK_GPIO_SI_INTERRUPT_BIT, isEnabled);
|
||||
LINK_GPIO_SET(REG_RCNT, LINK_GPIO_BIT_SI_INTERRUPT, isEnabled);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user