mirror of
https://github.com/jiangzhengwenjz/katam.git
synced 2024-11-27 15:10:48 +00:00
265 lines
11 KiB
C
265 lines
11 KiB
C
#ifndef GUARD_MULTI_SIO_H
|
|
#define GUARD_MULTI_SIO_H
|
|
|
|
#include "global.h"
|
|
|
|
// Optimize the following settings based on the software specifications
|
|
|
|
#define MULTI_SIO_BLOCK_SIZE 20 // Communication Data Block Size (Max. 24 Bytes)
|
|
|
|
#define MULTI_SIO_PLAYERS_MAX 4 // Maximum Number of Players
|
|
|
|
#define MULTI_SIO_SYNC_DATA 0xfefe // Synchronized Data (0x0000/0xfffa~0xffff prohibited)
|
|
|
|
// Comment out if no space in CPU internal Work RAM
|
|
#define MULTI_SIO_DI_FUNC_FAST // SIO Interrupt Prohibit Function High Speed Flag (CPU Internal RAM Execution)
|
|
|
|
|
|
// Update if maximum delay for communication interrupt is larger than following.
|
|
#define MULTI_SIO_INTR_DELAY_MAX 2000 // Communication Interrupt Allowed Delay Clocks
|
|
|
|
#ifdef MULTI_SIO_DI_FUNC_FAST
|
|
#define MULTI_SIO_INTR_CLOCK_MAX 400 // Communication Interrupt Processing Maximum Clocks
|
|
#else
|
|
#define MULTI_SIO_INTR_CLOCK_MAX 1000
|
|
#endif
|
|
|
|
#define MULTI_SIO_1P_SEND_CLOCKS 3000 // Communication Time for 1 unit
|
|
|
|
#if MULTI_SIO_PLAYERS_MAX == 4
|
|
#define MULTI_SIO_START_BIT_WAIT 0 // Start Bit Wait Time
|
|
#else
|
|
#define MULTI_SIO_START_BIT_WAIT 512
|
|
#endif
|
|
|
|
// During development set NDEBUG to undefined and value below to 0,
|
|
// define with last check and confirm operation with changed to 600.
|
|
// (Even if increase setting the communication interval increases, but
|
|
// processing doesn't slow).
|
|
//#define NDEBUG // Can define with Makefile (MakefileDemo)
|
|
#ifdef NDEBUG
|
|
#define MULTI_SIO_INTR_MARGIN 600 // Communication Interrupt Error Guarantee Value
|
|
#else
|
|
#define MULTI_SIO_INTR_MARGIN 0
|
|
#endif
|
|
|
|
|
|
#define MULTI_SIO_BAUD_RATE 115200 // Baud Rate
|
|
#define MULTI_SIO_BAUD_RATE_NO SIO_115200_BPS // Baud Rate No.
|
|
|
|
|
|
#define MULTI_SIO_TIMER_NO 3 // Timer No.
|
|
#define MULTI_SIO_TIMER_INTR_FLAG (INTR_FLAG_TIMER0 << MULTI_SIO_TIMER_NO)
|
|
|
|
#define REG_MULTI_SIO_TIMER (*(vu32 *)(REG_ADDR_TMCNT + (MULTI_SIO_TIMER_NO * 4)))
|
|
#define REG_MULTI_SIO_TIMER_L (*(vu16 *)(REG_ADDR_TMCNT_L + (MULTI_SIO_TIMER_NO * 4)))
|
|
#define REG_MULTI_SIO_TIMER_H (*(vu16 *)(REG_ADDR_TMCNT_H + (MULTI_SIO_TIMER_NO * 4)))
|
|
// Timer Register
|
|
|
|
// Timer count number is calculated from communication data block size.
|
|
#define MULTI_SIO_TIMER_COUNT_TMP (SYSTEM_CLOCK / 60 / ((2 + 4 + MULTI_SIO_BLOCK_SIZE + 6) / (16 / 8)))
|
|
// Timer Count Temporary Value
|
|
#define MULTI_SIO_TIMER_COUNT_MIN ( MULTI_SIO_1P_SEND_CLOCKS * MULTI_SIO_PLAYERS_MAX \
|
|
+ MULTI_SIO_START_BIT_WAIT + MULTI_SIO_INTR_MARGIN \
|
|
+ MULTI_SIO_INTR_DELAY_MAX + MULTI_SIO_INTR_CLOCK_MAX)
|
|
// Timer Count Minimum Value
|
|
#define MULTI_SIO_TIMER_COUNT_MAX 0x10000 // Timer Count Maximum Value
|
|
#define MULTI_SIO_TIMER_COUNT (MULTI_SIO_TIMER_COUNT_MAX - MULTI_SIO_TIMER_COUNT_TMP)
|
|
// Timer Count
|
|
// Timer Count Setting Error
|
|
#if MULTI_SIO_TIMER_COUNT_TMP < MULTI_SIO_TIMER_COUNT_MIN
|
|
#error MULTI_SIO_TIMER_COUNT is too short,
|
|
#error because MULTI_SIO_BLOCK_SIZE or MULTI_SIO_INTR_DELAY_MAX is too large.
|
|
#elif MULTI_SIO_TIMER_COUNT_TMP > MULTI_SIO_TIMER_COUNT_MAX
|
|
#error MULTI_SIO_TIMER_COUNT is too long.
|
|
#endif
|
|
|
|
// Multi-play Communication Packet Structure
|
|
struct MultiSioPacket
|
|
{
|
|
u8 frameCounter; // Frame Counter
|
|
u8 recvErrorFlags:4; // Receive Error Flag
|
|
u8 loadRequest:1; // Load Request
|
|
u8 downloadSuccessFlag:1; // Download Success Flag
|
|
u8 loadSuccessFlag:1; // Load Success
|
|
u8 reserved_0:1; // Reserved
|
|
u16 checkSum; // Checksum
|
|
u16 data[MULTI_SIO_BLOCK_SIZE / 2]; // Communication Data
|
|
u16 overrunCatch[2]; // Overrun Protect Area
|
|
};
|
|
|
|
// Multi-play Communication Work Area Structure
|
|
struct MultiSioArea
|
|
{
|
|
u8 type; // Connection (Master/Slave)
|
|
u8 state; // Communication Function State
|
|
u8 connectedFlags; // Connection History Flag
|
|
u8 recvSuccessFlags; // Receive Success Flag
|
|
|
|
u8 syncRecvFlag[4]; // Receive Confirmation Flag
|
|
|
|
u8 downloadSuccessFlags:4; // Download Success Flag
|
|
u8 loadEnable:1; // Enable Load
|
|
u8 loadRequest:1; // Load Request
|
|
u8 loadSuccessFlag:1; // Load Success
|
|
u8 startFlag:1; // Communication Start Flag
|
|
|
|
u8 hardError; // Hard error
|
|
u8 recvFlagsAvailableCounter; // Receiving success flag validation counter
|
|
|
|
u8 sendFrameCounter; // Send Frame Counter
|
|
u8 recvFrameCounter[4][2]; // Receive Frame Counter
|
|
|
|
s32 sendBufCounter; // Send Buffer Counter
|
|
s32 recvBufCounter[4]; // Receive Buffer Counter
|
|
|
|
u16 *nextSendBufp; // Send Buffer Pointer
|
|
u16 *currentSendBufp;
|
|
u16 *currentRecvBufp[4]; // Receive Buffer Pointer
|
|
u16 *lastRecvBufp[4];
|
|
u16 *recvCheckBufp[4];
|
|
|
|
struct MultiSioPacket sendBuf[2]; // Send Buffer (Double Buffer)
|
|
struct MultiSioPacket recvBuf[MULTI_SIO_PLAYERS_MAX][3];
|
|
// Receive Buffer (Triple Buffer)
|
|
};
|
|
|
|
extern u32 gMultiSioRecvFuncBuf[0x40 / 4]; // Receive Data/Check Buffer Change Routine RAM Execution Buffer
|
|
extern u32 gMultiSioIntrFuncBuf[0x180 / 4]; // Interrupt Routine RAM Execution Buffer
|
|
|
|
extern struct MultiSioArea gMultiSioArea; // Multi-play Communication Work Area
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Multi-play Communication Initialization */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
extern void MultiSioInit(u32 connectedFlags);
|
|
|
|
//* Set serial communication mode to multi-play mode.
|
|
//* Initialize register and buffer.
|
|
//* Arguments:
|
|
// u32 connectedFlags Set appropriate flag if a unit recognized as connected
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Start Multi-play Communication */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void MultiSioStart(void);
|
|
|
|
//* If following master recognition set flag to start send.
|
|
//* If slave or prior to master recognition do nothing.
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Stop Multi-play Communication */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void MultiSioStop(void);
|
|
|
|
//* Stop Communication
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Multi-play Communication Main */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
extern u32 MultiSioMain(void *sendp, void *recvp, u32 loadRequest);
|
|
|
|
//* First determine if master or slave. If master recognized, initialize
|
|
// timer.
|
|
//* Call MultiSioSendDataSet() and set send data.
|
|
//* Call MultiSioRecvDataCheck() and check if normal receive done,
|
|
// and copy receive data to Recvp.
|
|
//
|
|
//* Set so called with as close a timing as possible within 1 frame.
|
|
//* Safer not to send data that matches flag data (SIO_SYNC_DATA) prior
|
|
// to connection determination.
|
|
//
|
|
//* Arguments:
|
|
// void *sendp User Send Buffer Pointer
|
|
// void *recvp User Receive Buffer Pointer
|
|
// u32 loadRequest Load Request
|
|
|
|
//* Return Value:
|
|
|
|
#define MULTI_SIO_RECV_ID_MASK 0x000f // Receive Success Flag
|
|
#define MULTI_SIO_CONNECTED_ID_MASK 0x0f00 // Connection History Flag
|
|
|
|
#define MULTI_SIO_RECV_ID0 0x0001 // Receive Success Flag Master
|
|
#define MULTI_SIO_RECV_ID1 0x0002 // Slave 1
|
|
#define MULTI_SIO_RECV_ID2 0x0004 // Slave 2
|
|
#define MULTI_SIO_RECV_ID3 0x0008 // Slave 3
|
|
#define MULTI_SIO_LD_ENABLE 0x0010 // Enable Load
|
|
#define MULTI_SIO_LD_REQUEST 0x0020 // Load Request
|
|
#define MULTI_SIO_LD_SUCCESS 0x0040 // Load Success
|
|
#define MULTI_SIO_TYPE 0x0080 // Connection (Master/Slave)
|
|
#define MULTI_SIO_PARENT 0x0080 // Master Connection
|
|
#define MULTI_SIO_CHILD 0x0000 // Slave Connection
|
|
#define MULTI_SIO_CONNECTED_ID0 0x0100 // Connection History Flag Master
|
|
#define MULTI_SIO_CONNECTED_ID1 0x0200 // Slave 1
|
|
#define MULTI_SIO_CONNECTED_ID2 0x0400 // Slave 2
|
|
#define MULTI_SIO_CONNECTED_ID3 0x0800 // Slave 3
|
|
#define MULTI_SIO_UNK_x1000 0x1000
|
|
#define MULTI_SIO_UNK_x2000 0x2000
|
|
|
|
|
|
// Return Value Structure
|
|
struct MultiSioReturn
|
|
{
|
|
u32 recvSuccessFlags:4; // Receive Success Flag
|
|
u32 loadEnable:1; // Enable Load
|
|
u32 loadRequest:1; // Load Request
|
|
u32 loadSuccessFlag:1; // Load Success
|
|
u32 type:1; // Connection (Master/Slave)
|
|
u32 connectedFlags:4; // Connection History Flag
|
|
u32 multisioreturn_unk00_0c:1;
|
|
u32 multisioreturn_unk00_0d:1;
|
|
};
|
|
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Multi-play Communication Interrupt */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
extern void MultiSioIntr(void);
|
|
|
|
//* During communication interrupt, store receive data from each unit
|
|
// in each receive buffer and set the send buffer data to the register.
|
|
//* If master, reset timer and restart send.
|
|
//
|
|
//* Program so slave is called with communication interrupt and master
|
|
// is called with timer interrupt.
|
|
//* Adjust setting so 1 packet (Except for OverRunCatch[]) can be
|
|
// transfered with 1 frame.
|
|
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Set Send Data */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
extern void MultiSioSendDataSet(void *sendp, u32 loadReq);
|
|
|
|
//* Set the user send buffer data to send buffer.
|
|
//
|
|
//* Called from MultiSioMain().
|
|
//* Not necessary to call directly.
|
|
//
|
|
//* Arguments:
|
|
// void *sendp User Send Buffer Pointer
|
|
// u32 loadReq Load Request
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* Check Receive Data */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
extern u32 MultiSioRecvDataCheck(void *recvp);
|
|
|
|
//* Check if receive done normally. If normal, copy the receive data
|
|
// to the user receive buffer.
|
|
//
|
|
//* Called from MultiSioMain().
|
|
//* Do not need to call directly.
|
|
//
|
|
//* Arguments:
|
|
// void *recvp User Receive Buffer Pointer
|
|
|
|
#endif // GUARD_MULTI_SIO_H
|