libtwl/common/source/ipc/ipcFifoSystem.c
2023-08-20 18:22:07 +02:00

90 lines
2.5 KiB
C

#include <nds.h>
#include "libtwl/rtos/rtosIrq.h"
#include "libtwl/ipc/ipcSync.h"
#include "libtwl/ipc/ipcFifo.h"
#include "libtwl/ipc/ipcFifoSystem.h"
#define HANDSHAKE_PART0 0xA
#define HANDSHAKE_PART1 0xB
#define HANDSHAKE_PART2 0xC
static ipc_fifo_ch_handler_func_t sHandlerFuncs[IPC_FIFO_MSG_CHANNEL_COUNT];
static void* sHandlerArgs[IPC_FIFO_MSG_CHANNEL_COUNT];
static void recvFifoNotEmptyIrq(u32 irqMask)
{
while (!ipc_isRecvFifoEmpty())
{
u32 msg = ipc_recvWordDirect();
u32 channel = msg & IPC_FIFO_MSG_CHANNEL_MASK;
sHandlerFuncs[channel](channel, msg >> IPC_FIFO_MSG_CHANNEL_BITS, sHandlerArgs[channel]);
}
}
static void dummyChannelHandler(u32 channel, u32 data, void* arg)
{
}
void ipc_initFifoSystem(void)
{
for (int i = 0; i < IPC_FIFO_MSG_CHANNEL_COUNT; i++)
sHandlerFuncs[i] = &dummyChannelHandler;
u32 irqs = rtos_disableIrqs();
{
ipc_clearSendFifo();
ipc_ackFifoError();
ipc_enableRecvFifoNotEmptyIrq();
ipc_enableFifo();
rtos_ackIrqMask(RTOS_IRQ_IPC_FIFO_RECV);
rtos_setIrqFunc(RTOS_IRQ_IPC_FIFO_RECV, recvFifoNotEmptyIrq);
rtos_enableIrqMask(RTOS_IRQ_IPC_FIFO_RECV);
#ifdef LIBTWL_ARM9
while (ipc_getArm7SyncBits() != HANDSHAKE_PART0);
ipc_setArm9SyncBits(HANDSHAKE_PART0);
while (ipc_getArm7SyncBits() != HANDSHAKE_PART1);
ipc_setArm9SyncBits(HANDSHAKE_PART1);
while (ipc_getArm7SyncBits() != HANDSHAKE_PART2);
ipc_setArm9SyncBits(HANDSHAKE_PART2);
#endif
#ifdef LIBTWL_ARM7
ipc_setArm7SyncBits(HANDSHAKE_PART0);
while (ipc_getArm9SyncBits() != HANDSHAKE_PART0);
ipc_setArm7SyncBits(HANDSHAKE_PART1);
while (ipc_getArm9SyncBits() != HANDSHAKE_PART1);
ipc_setArm7SyncBits(HANDSHAKE_PART2);
while (ipc_getArm9SyncBits() != HANDSHAKE_PART2);
#endif
}
rtos_restoreIrqs(irqs);
}
void ipc_setChannelHandler(u32 channel, ipc_fifo_ch_handler_func_t handler, void* arg)
{
if (handler == NULL)
handler = &dummyChannelHandler;
sHandlerFuncs[channel] = handler;
sHandlerArgs[channel] = arg;
}
bool ipc_trySendFifoMessage(u32 channel, u32 data)
{
u32 irqs = rtos_disableIrqs();
if (ipc_isSendFifoFull())
{
rtos_restoreIrqs(irqs);
return false;
}
ipc_sendWordDirect((channel & IPC_FIFO_MSG_CHANNEL_MASK) | (data << IPC_FIFO_MSG_CHANNEL_BITS));
rtos_restoreIrqs(irqs);
return true;
}
void ipc_sendFifoMessage(u32 channel, u32 data)
{
while (!ipc_trySendFifoMessage(channel, data));
}