Using prefixes and moving structs/enums inside classes

This commit is contained in:
Rodrigo Alfonso
2023-01-17 21:50:15 -03:00
parent 3e48ff5a42
commit 4ae3fcb8f0
8 changed files with 169 additions and 168 deletions

View File

@@ -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*.

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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";
}

View File

@@ -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

View File

@@ -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);
}
};