2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* @file padmgr.c
|
|
|
|
*
|
|
|
|
* This file implements communicating with joybus devices at a high level and serving the results to other threads.
|
|
|
|
*
|
|
|
|
* Any device that can be plugged into one of the four controller ports such as a standard N64 controller is a joybus
|
|
|
|
* device. Some joybus devices are also located inside the cartridge such as EEPROM for save data or the Real-Time
|
|
|
|
* Clock, however neither of these are used in Zelda64 and so this type of communication is unimplemented. Of the
|
|
|
|
* possible devices that can be plugged into the controller ports, the only device that padmgr will recognize and
|
|
|
|
* attempt to communicate with is the standard N64 controller.
|
|
|
|
*
|
|
|
|
* Communicating with these devices is broken down into various layers:
|
|
|
|
*
|
|
|
|
* Other threads : The rest of the program that will use the polled data
|
|
|
|
* |
|
|
|
|
* PadMgr : Manages devices, submits polling commands at vertical retrace
|
|
|
|
* |
|
|
|
|
* Libultra osCont* routines : Interface for building commands and safely using the Serial Interface
|
|
|
|
* |
|
|
|
|
* Serial Interface : Hardware unit for sending joybus commands and receiving data via DMA
|
|
|
|
* |
|
|
|
|
* PIF : Forwards joybus commands and receives response data from the devices
|
|
|
|
* |---¬---¬---¬-------¬
|
|
|
|
* 1 2 3 4 5 : The joybus devices plugged into the four controller ports or on the cartridge
|
|
|
|
*
|
|
|
|
* Joybus communication is handled on another thread as polling and receiving controller data is a slow process; the
|
|
|
|
* N64 programming manual section 26.2.4.1 quotes 2 milliseconds as the expected delay from calling
|
|
|
|
* `osContStartReadData` to receiving the data. By running this on a separate thread to the game state, work can be
|
|
|
|
* done while waiting for this operation to complete.
|
|
|
|
*/
|
2020-10-03 15:22:44 +00:00
|
|
|
#include "global.h"
|
|
|
|
#include "vt.h"
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
#define PADMGR_LOG(controllerNo, msg) \
|
|
|
|
if (1) { \
|
|
|
|
osSyncPrintf(VT_FGCOL(YELLOW)); \
|
|
|
|
/* padmgr: Controller %d: %s */ \
|
|
|
|
osSyncPrintf("padmgr: %dコン: %s\n", (controllerNo) + 1, (msg)); \
|
|
|
|
osSyncPrintf(VT_RST); \
|
|
|
|
} \
|
|
|
|
(void)0
|
|
|
|
|
|
|
|
#define LOG_SEVERITY_NOLOG 0
|
|
|
|
#define LOG_SEVERITY_CRITICAL 1
|
|
|
|
#define LOG_SEVERITY_ERROR 2
|
|
|
|
#define LOG_SEVERITY_VERBOSE 3
|
|
|
|
|
|
|
|
s32 gPadMgrLogSeverity = LOG_SEVERITY_CRITICAL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Acquires exclusive access to the serial event queue.
|
|
|
|
*
|
|
|
|
* When a DMA to/from PIF RAM completes, an SI interrupt is generated to notify the process that the DMA has completed
|
|
|
|
* and a message is posted to the serial event queue. If multiple processes are trying to use the SI at the same time
|
|
|
|
* it becomes ambiguous as to which DMA has completed, so a locking system is required to arbitrate access to the SI.
|
|
|
|
*
|
|
|
|
* Once the task requiring the serial event queue is complete, it should be released with a call to
|
|
|
|
* `PadMgr_ReleaseSerialEventQueue()`.
|
|
|
|
*
|
|
|
|
* If another process tries to acquire the event queue, the current thread will be blocked until the event queue is
|
|
|
|
* released. Note the possibility for a deadlock, if the thread that already holds the serial event queue attempts to
|
|
|
|
* acquire it again it will block forever.
|
|
|
|
*
|
|
|
|
* @return The message queue to which SI interrupt events are posted.
|
|
|
|
*
|
|
|
|
* @see PadMgr_ReleaseSerialEventQueue
|
|
|
|
*/
|
|
|
|
OSMesgQueue* PadMgr_AcquireSerialEventQueue(PadMgr* padMgr) {
|
2022-04-09 00:20:23 +00:00
|
|
|
OSMesgQueue* serialEventQueue = NULL;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "serialMsgQ Waiting for lock"
|
2020-03-22 21:19:43 +00:00
|
|
|
osSyncPrintf("%2d %d serialMsgQロック待ち %08x %08x %08x\n", osGetThreadId(NULL),
|
2022-04-09 00:20:23 +00:00
|
|
|
MQ_GET_COUNT(&padMgr->serialLockQueue), padMgr, &padMgr->serialLockQueue, &serialEventQueue);
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
osRecvMesg(&padMgr->serialLockQueue, (OSMesg*)&serialEventQueue, OS_MESG_BLOCK);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "serialMsgQ Locked"
|
2020-03-22 21:19:43 +00:00
|
|
|
osSyncPrintf("%2d %d serialMsgQをロックしました %08x\n", osGetThreadId(NULL),
|
2022-04-09 00:20:23 +00:00
|
|
|
MQ_GET_COUNT(&padMgr->serialLockQueue), serialEventQueue);
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
return serialEventQueue;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Relinquishes access to the serial message queue, allowing another process to acquire and use it.
|
|
|
|
*
|
|
|
|
* @param serialEventQueue The serial message queue acquired by `PadMgr_AcquireSerialEventQueue`
|
|
|
|
*
|
|
|
|
* @see PadMgr_AcquireSerialEventQueue
|
|
|
|
*/
|
|
|
|
void PadMgr_ReleaseSerialEventQueue(PadMgr* padMgr, OSMesgQueue* serialEventQueue) {
|
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "serialMsgQ Unlock"
|
2020-03-22 21:19:43 +00:00
|
|
|
osSyncPrintf("%2d %d serialMsgQロック解除します %08x %08x %08x\n", osGetThreadId(NULL),
|
2022-04-09 00:20:23 +00:00
|
|
|
MQ_GET_COUNT(&padMgr->serialLockQueue), padMgr, &padMgr->serialLockQueue, serialEventQueue);
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
osSendMesg(&padMgr->serialLockQueue, (OSMesg)serialEventQueue, OS_MESG_BLOCK);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "serialMsgQ Unlocked"
|
2020-03-22 21:19:43 +00:00
|
|
|
osSyncPrintf("%2d %d serialMsgQロック解除しました %08x %08x %08x\n", osGetThreadId(NULL),
|
2022-04-09 00:20:23 +00:00
|
|
|
MQ_GET_COUNT(&padMgr->serialLockQueue), padMgr, &padMgr->serialLockQueue, serialEventQueue);
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Locks controller input data while padmgr is reading new inputs or another thread is using the current inputs.
|
|
|
|
* This prevents new inputs overwriting the current inputs while they are in use.
|
|
|
|
*
|
|
|
|
* @see PadMgr_UnlockPadData
|
|
|
|
*/
|
2021-02-14 00:49:40 +00:00
|
|
|
void PadMgr_LockPadData(PadMgr* padMgr) {
|
2022-04-09 00:20:23 +00:00
|
|
|
osRecvMesg(&padMgr->lockQueue, NULL, OS_MESG_BLOCK);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Unlocks controller input data, allowing padmgr to read new inputs or another thread to access the most recently
|
|
|
|
* polled inputs.
|
|
|
|
*
|
|
|
|
* @see PadMgr_LockPadData
|
|
|
|
*/
|
2021-02-14 00:49:40 +00:00
|
|
|
void PadMgr_UnlockPadData(PadMgr* padMgr) {
|
2022-04-09 00:20:23 +00:00
|
|
|
osSendMesg(&padMgr->lockQueue, NULL, OS_MESG_BLOCK);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Activates the rumble pak for all controllers it is enabled on, stops it for all controllers it is disabled on and
|
|
|
|
* attempts to initialize it for a controller if it is not already initialized.
|
|
|
|
*/
|
|
|
|
void PadMgr_UpdateRumble(PadMgr* padMgr) {
|
|
|
|
static u32 sRumbleErrorCount = 0; // original name: "errcnt"
|
|
|
|
static u32 sRumbleUpdateCounter;
|
|
|
|
s32 motorStart = MOTOR_START; // required for matching?
|
2020-04-14 17:17:25 +00:00
|
|
|
s32 triedRumbleComm;
|
2022-09-03 00:52:13 +00:00
|
|
|
OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue(padMgr);
|
|
|
|
s32 ret;
|
2020-03-17 04:31:30 +00:00
|
|
|
s32 i;
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
triedRumbleComm = false;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
for (i = 0; i < MAXCONTROLLERS; i++) {
|
2021-02-14 00:49:40 +00:00
|
|
|
if (padMgr->ctrlrIsConnected[i]) {
|
2022-09-03 00:52:13 +00:00
|
|
|
// Check status for whether a controller pak is connected
|
|
|
|
if (padMgr->padStatus[i].status & CONT_CARD_ON) {
|
|
|
|
if (padMgr->pakType[i] == CONT_PAK_RUMBLE) {
|
|
|
|
if (padMgr->rumbleEnable[i]) {
|
|
|
|
if (padMgr->rumbleTimer[i] < 3) {
|
|
|
|
// "Rumble pack brrr"
|
|
|
|
PADMGR_LOG(i, "振動パック ぶるぶるぶるぶる");
|
|
|
|
|
|
|
|
// This should be the osMotorStart macro, however the temporary variable motorStart is
|
|
|
|
// currently required for matching
|
|
|
|
if (__osMotorAccess(&padMgr->rumblePfs[i], motorStart) != 0) {
|
|
|
|
padMgr->pakType[i] = CONT_PAK_NONE;
|
|
|
|
|
2021-09-28 23:53:56 +00:00
|
|
|
// "A communication error has occurred with the vibration pack"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "振動パックで通信エラーが発生しました");
|
2020-03-22 21:19:43 +00:00
|
|
|
} else {
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->rumbleTimer[i] = 3;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
2020-03-18 00:09:21 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
triedRumbleComm = true;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
2020-03-22 21:19:43 +00:00
|
|
|
} else {
|
2022-09-03 00:52:13 +00:00
|
|
|
if (padMgr->rumbleTimer[i] != 0) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "Stop vibration pack"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "振動パック 停止");
|
|
|
|
|
|
|
|
if (osMotorStop(&padMgr->rumblePfs[i]) != 0) {
|
|
|
|
padMgr->pakType[i] = CONT_PAK_NONE;
|
2020-03-18 00:09:21 +00:00
|
|
|
|
2020-06-14 03:29:59 +00:00
|
|
|
// "A communication error has occurred with the vibration pack"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "振動パックで通信エラーが発生しました");
|
2020-03-22 21:19:43 +00:00
|
|
|
} else {
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->rumbleTimer[i]--;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
2020-03-18 00:09:21 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
triedRumbleComm = true;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-22 21:19:43 +00:00
|
|
|
} else {
|
2022-09-03 00:52:13 +00:00
|
|
|
if (padMgr->pakType[i] != CONT_PAK_NONE) {
|
|
|
|
if (padMgr->pakType[i] == CONT_PAK_RUMBLE) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "It seems that a vibration pack was pulled out"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "振動パックが抜かれたようです");
|
|
|
|
padMgr->pakType[i] = CONT_PAK_NONE;
|
2020-03-22 21:19:43 +00:00
|
|
|
} else {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "It seems that a controller pack that is not a vibration pack was pulled out"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "振動パックではないコントローラパックが抜かれたようです");
|
|
|
|
padMgr->pakType[i] = CONT_PAK_NONE;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 17:17:25 +00:00
|
|
|
if (!triedRumbleComm) {
|
2022-09-03 00:52:13 +00:00
|
|
|
// Try to initialize the rumble pak for controller port `i` if a controller pak is connected and
|
|
|
|
// not already known to be an initialized a rumble pak
|
|
|
|
i = sRumbleUpdateCounter % MAXCONTROLLERS;
|
|
|
|
|
|
|
|
if (padMgr->ctrlrIsConnected[i] && (padMgr->padStatus[i].status & CONT_CARD_ON) &&
|
|
|
|
padMgr->pakType[i] != CONT_PAK_RUMBLE) {
|
|
|
|
ret = osMotorInit(serialEventQueue, &padMgr->rumblePfs[i], i);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
if (ret == 0) {
|
|
|
|
padMgr->pakType[i] = CONT_PAK_RUMBLE;
|
|
|
|
osMotorStart(&padMgr->rumblePfs[i]);
|
|
|
|
osMotorStop(&padMgr->rumblePfs[i]);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2020-06-14 03:29:59 +00:00
|
|
|
// "Recognized vibration pack"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "振動パックを認識しました");
|
|
|
|
} else if (ret == PFS_ERR_DEVICE) {
|
|
|
|
padMgr->pakType[i] = CONT_PAK_OTHER;
|
|
|
|
} else if (ret == PFS_ERR_CONTRFAIL) {
|
|
|
|
LOG_NUM("++errcnt", ++sRumbleErrorCount, "../padmgr.c", 282);
|
|
|
|
|
2020-06-14 03:29:59 +00:00
|
|
|
// "Controller pack communication error"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "コントローラパックの通信エラー");
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-03 00:52:13 +00:00
|
|
|
sRumbleUpdateCounter++;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
PadMgr_ReleaseSerialEventQueue(padMgr, serialEventQueue);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Immediately stops rumble on all controllers
|
|
|
|
*/
|
2021-02-14 00:49:40 +00:00
|
|
|
void PadMgr_RumbleStop(PadMgr* padMgr) {
|
2020-03-17 04:31:30 +00:00
|
|
|
s32 i;
|
2022-09-03 00:52:13 +00:00
|
|
|
OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue(padMgr);
|
|
|
|
|
|
|
|
for (i = 0; i < MAXCONTROLLERS; i++) {
|
|
|
|
if (osMotorInit(serialEventQueue, &padMgr->rumblePfs[i], i) == 0) {
|
|
|
|
// If there is a rumble pak attached to this controller, stop it
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gFaultMgr.msgId == 0 && padMgr->rumbleOnTimer != 0) {
|
|
|
|
// "Stop rumble pak"
|
|
|
|
PADMGR_LOG(i, "振動パック 停止");
|
|
|
|
}
|
|
|
|
osMotorStop(&padMgr->rumblePfs[i]);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
PadMgr_ReleaseSerialEventQueue(padMgr, serialEventQueue);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Prevents rumble for 3 VI, ~0.05 seconds at 60 VI/sec
|
|
|
|
*/
|
2021-02-14 00:49:40 +00:00
|
|
|
void PadMgr_RumbleReset(PadMgr* padMgr) {
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->rumbleOffTimer = 3;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Enables or disables rumble on controller port `port` for 240 VI,
|
|
|
|
* ~4 seconds at 60 VI/sec and ~4.8 seconds at 50 VI/sec
|
|
|
|
*/
|
|
|
|
void PadMgr_RumbleSetSingle(PadMgr* padMgr, u32 port, u32 rumble) {
|
|
|
|
padMgr->rumbleEnable[port] = rumble;
|
|
|
|
padMgr->rumbleOnTimer = 240;
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Enables or disables rumble on all controller ports for 240 VI,
|
|
|
|
* ~4 seconds at 60 VI/sec and ~4.8 seconds at 50 VI/sec
|
|
|
|
*
|
|
|
|
* @param enable Array of u8 of length MAXCONTROLLERS containing either true or false to enable or disable rumble
|
|
|
|
* for that controller
|
|
|
|
*/
|
|
|
|
void PadMgr_RumbleSet(PadMgr* padMgr, u8* enable) {
|
2020-04-14 17:17:25 +00:00
|
|
|
s32 i;
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
for (i = 0; i < MAXCONTROLLERS; i++) {
|
|
|
|
padMgr->rumbleEnable[i] = enable[i];
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->rumbleOnTimer = 240;
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Updates `padMgr->inputs` based on the error response of each controller
|
|
|
|
*/
|
|
|
|
void PadMgr_UpdateInputs(PadMgr* padMgr) {
|
2020-04-14 17:17:25 +00:00
|
|
|
s32 i;
|
2020-06-14 03:29:59 +00:00
|
|
|
Input* input;
|
2022-09-03 00:52:13 +00:00
|
|
|
OSContPad* pad; // original name: "padnow1"
|
2020-06-14 03:29:59 +00:00
|
|
|
s32 buttonDiff;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_LockPadData(padMgr);
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
for (input = &padMgr->inputs[0], pad = &padMgr->pads[0], i = 0; i < padMgr->nControllers; i++, input++, pad++) {
|
2020-06-14 03:29:59 +00:00
|
|
|
input->prev = input->cur;
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
switch (pad->errno) {
|
2020-06-14 03:29:59 +00:00
|
|
|
case 0:
|
2022-09-03 00:52:13 +00:00
|
|
|
// No error, copy inputs
|
|
|
|
input->cur = *pad;
|
2021-02-14 00:49:40 +00:00
|
|
|
if (!padMgr->ctrlrIsConnected[i]) {
|
|
|
|
padMgr->ctrlrIsConnected[i] = true;
|
2022-09-03 00:52:13 +00:00
|
|
|
// "Recognized"
|
|
|
|
PADMGR_LOG(i, "認識しました");
|
2020-06-14 03:29:59 +00:00
|
|
|
}
|
|
|
|
break;
|
2022-09-03 00:52:13 +00:00
|
|
|
case (CHNL_ERR_OVERRUN >> 4):
|
|
|
|
// Overrun error, reuse previous inputs
|
2020-06-14 03:29:59 +00:00
|
|
|
input->cur = input->prev;
|
2021-02-14 00:49:40 +00:00
|
|
|
LOG_NUM("this->Key_switch[i]", padMgr->ctrlrIsConnected[i], "../padmgr.c", 380);
|
2021-09-04 13:33:19 +00:00
|
|
|
// "Overrun error occurred"
|
2022-09-03 00:52:13 +00:00
|
|
|
PADMGR_LOG(i, "オーバーランエラーが発生");
|
2020-06-14 03:29:59 +00:00
|
|
|
break;
|
2022-09-03 00:52:13 +00:00
|
|
|
case (CHNL_ERR_NORESP >> 4):
|
|
|
|
// No response error, take inputs as 0
|
2020-10-03 15:22:44 +00:00
|
|
|
input->cur.button = 0;
|
|
|
|
input->cur.stick_x = 0;
|
|
|
|
input->cur.stick_y = 0;
|
2022-09-03 00:52:13 +00:00
|
|
|
input->cur.errno = pad->errno;
|
2021-02-14 00:49:40 +00:00
|
|
|
if (padMgr->ctrlrIsConnected[i]) {
|
2022-09-03 00:52:13 +00:00
|
|
|
// If we get no response, consider the controller disconnected
|
2021-02-14 00:49:40 +00:00
|
|
|
padMgr->ctrlrIsConnected[i] = false;
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->pakType[i] = CONT_PAK_NONE;
|
|
|
|
padMgr->rumbleTimer[i] = UINT8_MAX;
|
|
|
|
// "Not responding"
|
|
|
|
PADMGR_LOG(i, "応答しません");
|
2020-06-14 03:29:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2022-09-03 00:52:13 +00:00
|
|
|
// Unknown error response
|
|
|
|
LOG_HEX("padnow1->errno", pad->errno, "../padmgr.c", 396);
|
2020-06-14 03:29:59 +00:00
|
|
|
Fault_AddHungupAndCrash("../padmgr.c", 397);
|
2022-09-03 00:52:13 +00:00
|
|
|
break;
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
// Calculate pressed and relative inputs
|
2020-10-03 15:22:44 +00:00
|
|
|
buttonDiff = input->prev.button ^ input->cur.button;
|
|
|
|
input->press.button |= (u16)(buttonDiff & input->cur.button);
|
|
|
|
input->rel.button |= (u16)(buttonDiff & input->prev.button);
|
2020-05-25 21:18:14 +00:00
|
|
|
PadUtils_UpdateRelXY(input);
|
2020-10-03 15:22:44 +00:00
|
|
|
input->press.stick_x += (s8)(input->cur.stick_x - input->prev.stick_x);
|
|
|
|
input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y);
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_UnlockPadData(padMgr);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
void PadMgr_HandleRetrace(PadMgr* padMgr) {
|
2020-06-14 03:29:59 +00:00
|
|
|
s32 i;
|
2022-09-03 00:52:13 +00:00
|
|
|
OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue(padMgr);
|
2020-04-14 17:17:25 +00:00
|
|
|
u32 mask;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
// Begin reading controller data
|
2022-04-09 00:20:23 +00:00
|
|
|
osContStartReadData(serialEventQueue);
|
2022-09-03 00:52:13 +00:00
|
|
|
|
|
|
|
// Execute retrace callback
|
|
|
|
if (padMgr->retraceCallback != NULL) {
|
2022-09-27 16:40:26 +00:00
|
|
|
padMgr->retraceCallback(padMgr, padMgr->retraceCallbackArg);
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
2022-09-03 00:52:13 +00:00
|
|
|
|
|
|
|
// Wait for controller data
|
2022-04-09 00:20:23 +00:00
|
|
|
osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);
|
2021-02-14 00:49:40 +00:00
|
|
|
osContGetReadData(padMgr->pads);
|
2022-09-03 00:52:13 +00:00
|
|
|
|
|
|
|
// If resetting, clear all controllers
|
|
|
|
if (padMgr->isResetting) {
|
2021-02-14 00:49:40 +00:00
|
|
|
bzero(padMgr->pads, sizeof(padMgr->pads));
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
2022-09-03 00:52:13 +00:00
|
|
|
|
|
|
|
// Update input data
|
|
|
|
PadMgr_UpdateInputs(padMgr);
|
|
|
|
|
|
|
|
// Query controller status for all controllers
|
2022-04-09 00:20:23 +00:00
|
|
|
osContStartQuery(serialEventQueue);
|
|
|
|
osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);
|
2021-02-14 00:49:40 +00:00
|
|
|
osContGetQuery(padMgr->padStatus);
|
2020-04-14 17:17:25 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
PadMgr_ReleaseSerialEventQueue(padMgr, serialEventQueue);
|
|
|
|
|
|
|
|
// Update the state of connected controllers
|
2020-04-14 17:17:25 +00:00
|
|
|
mask = 0;
|
2022-09-03 00:52:13 +00:00
|
|
|
for (i = 0; i < MAXCONTROLLERS; i++) {
|
2021-02-14 00:49:40 +00:00
|
|
|
if (padMgr->padStatus[i].errno == 0) {
|
2022-09-03 00:52:13 +00:00
|
|
|
// Only standard N64 controllers are supported
|
2021-12-07 14:17:48 +00:00
|
|
|
if (padMgr->padStatus[i].type == CONT_TYPE_NORMAL) {
|
2020-04-14 17:17:25 +00:00
|
|
|
mask |= 1 << i;
|
|
|
|
} else {
|
2021-02-14 00:49:40 +00:00
|
|
|
LOG_HEX("this->pad_status[i].type", padMgr->padStatus[i].type, "../padmgr.c", 458);
|
2020-06-14 03:29:59 +00:00
|
|
|
// "An unknown type of controller is connected"
|
2020-04-14 17:17:25 +00:00
|
|
|
osSyncPrintf("知らない種類のコントローラが接続されています\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-14 00:49:40 +00:00
|
|
|
padMgr->validCtrlrsMask = mask;
|
2020-04-14 17:17:25 +00:00
|
|
|
|
2022-02-02 21:43:34 +00:00
|
|
|
if (gFaultMgr.msgId != 0) {
|
2022-09-03 00:52:13 +00:00
|
|
|
// If fault is active, no rumble
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_RumbleStop(padMgr);
|
2022-09-03 00:52:13 +00:00
|
|
|
} else if (padMgr->rumbleOffTimer > 0) {
|
|
|
|
// If the rumble off timer is active, no rumble
|
|
|
|
--padMgr->rumbleOffTimer;
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_RumbleStop(padMgr);
|
2022-09-03 00:52:13 +00:00
|
|
|
} else if (padMgr->rumbleOnTimer == 0) {
|
|
|
|
// If the rumble on timer is inactive, no rumble
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_RumbleStop(padMgr);
|
2022-09-03 00:52:13 +00:00
|
|
|
} else if (!padMgr->isResetting) {
|
|
|
|
// If not resetting, update rumble
|
|
|
|
PadMgr_UpdateRumble(padMgr);
|
|
|
|
--padMgr->rumbleOnTimer;
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
void PadMgr_HandlePreNMI(PadMgr* padMgr) {
|
2020-03-17 04:31:30 +00:00
|
|
|
osSyncPrintf("padmgr_HandlePreNMI()\n");
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->isResetting = true;
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_RumbleReset(padMgr);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
/**
|
|
|
|
* Fetches the most recently polled inputs from padmgr
|
|
|
|
*
|
|
|
|
* @param inputs Array of Input of length MAXCONTROLLERS to copy inputs into
|
|
|
|
* @param gamePoll True if polling inputs for updating the game state
|
|
|
|
*/
|
|
|
|
void PadMgr_RequestPadData(PadMgr* padMgr, Input* inputs, s32 gameRequest) {
|
2020-06-14 03:29:59 +00:00
|
|
|
s32 i;
|
2022-09-03 00:52:13 +00:00
|
|
|
Input* inputIn;
|
|
|
|
Input* inputOut;
|
2020-06-14 03:29:59 +00:00
|
|
|
s32 buttonDiff;
|
2020-04-14 17:17:25 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_LockPadData(padMgr);
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
for (inputIn = &padMgr->inputs[0], inputOut = &inputs[0], i = 0; i < MAXCONTROLLERS; i++, inputIn++, inputOut++) {
|
|
|
|
if (gameRequest) {
|
|
|
|
// Copy inputs as-is, press and rel are calculated prior in `PadMgr_UpdateInputs`
|
|
|
|
*inputOut = *inputIn;
|
|
|
|
// Zero parts of the press and rel inputs in the polled inputs so they are not read more than once
|
|
|
|
inputIn->press.button = 0;
|
|
|
|
inputIn->press.stick_x = 0;
|
|
|
|
inputIn->press.stick_y = 0;
|
|
|
|
inputIn->rel.button = 0;
|
2020-04-14 17:17:25 +00:00
|
|
|
} else {
|
2022-09-03 00:52:13 +00:00
|
|
|
// Take as the previous inputs the inputs that are currently in the destination array
|
|
|
|
inputOut->prev = inputOut->cur;
|
|
|
|
// Copy current inputs from the polled inputs
|
|
|
|
inputOut->cur = inputIn->cur;
|
|
|
|
// Calculate press and rel from these
|
|
|
|
buttonDiff = inputOut->prev.button ^ inputOut->cur.button;
|
|
|
|
inputOut->press.button = inputOut->cur.button & buttonDiff;
|
|
|
|
inputOut->rel.button = inputOut->prev.button & buttonDiff;
|
|
|
|
PadUtils_UpdateRelXY(inputOut);
|
|
|
|
inputOut->press.stick_x += (s8)(inputOut->cur.stick_x - inputOut->prev.stick_x);
|
|
|
|
inputOut->press.stick_y += (s8)(inputOut->cur.stick_y - inputOut->prev.stick_y);
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_UnlockPadData(padMgr);
|
2020-04-14 17:17:25 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
void PadMgr_ThreadEntry(PadMgr* padMgr) {
|
2022-04-09 00:20:23 +00:00
|
|
|
s16* msg = NULL;
|
2020-04-14 17:17:25 +00:00
|
|
|
s32 exit;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-09-04 13:33:19 +00:00
|
|
|
osSyncPrintf("コントローラスレッド実行開始\n"); // "Controller thread execution start"
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2020-06-14 03:29:59 +00:00
|
|
|
exit = false;
|
2020-04-14 17:17:25 +00:00
|
|
|
while (!exit) {
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE && MQ_IS_EMPTY(&padMgr->interruptQueue)) {
|
2020-06-14 03:29:59 +00:00
|
|
|
// "Waiting for controller thread event"
|
2020-04-08 16:36:15 +00:00
|
|
|
osSyncPrintf("コントローラスレッドイベント待ち %lld\n", OS_CYCLES_TO_USEC(osGetTime()));
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
osRecvMesg(&padMgr->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
|
|
|
|
LogUtils_CheckNullPointer("msg", msg, "../padmgr.c", 563);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
switch (*msg) {
|
2020-03-17 04:31:30 +00:00
|
|
|
case OS_SC_RETRACE_MSG:
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE) {
|
2020-04-08 16:36:15 +00:00
|
|
|
osSyncPrintf("padmgr_HandleRetraceMsg START %lld\n", OS_CYCLES_TO_USEC(osGetTime()));
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
PadMgr_HandleRetrace(padMgr);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
if (gPadMgrLogSeverity >= LOG_SEVERITY_VERBOSE) {
|
2020-04-08 16:36:15 +00:00
|
|
|
osSyncPrintf("padmgr_HandleRetraceMsg END %lld\n", OS_CYCLES_TO_USEC(osGetTime()));
|
2020-03-22 21:19:43 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
break;
|
|
|
|
case OS_SC_PRE_NMI_MSG:
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_HandlePreNMI(padMgr);
|
2020-03-17 04:31:30 +00:00
|
|
|
break;
|
|
|
|
case OS_SC_NMI_MSG:
|
2020-06-14 03:29:59 +00:00
|
|
|
exit = true;
|
2020-03-17 04:31:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
IrqMgr_RemoveClient(padMgr->irqMgr, &padMgr->irqClient);
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2021-09-04 13:33:19 +00:00
|
|
|
osSyncPrintf("コントローラスレッド実行終了\n"); // "Controller thread execution end"
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
void PadMgr_Init(PadMgr* padMgr, OSMesgQueue* serialEventQueue, IrqMgr* irqMgr, OSId id, OSPri priority, void* stack) {
|
2021-09-04 13:33:19 +00:00
|
|
|
osSyncPrintf("パッドマネージャ作成 padmgr_Create()\n"); // "Pad Manager creation"
|
2020-06-14 03:29:59 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
bzero(padMgr, sizeof(PadMgr));
|
|
|
|
padMgr->irqMgr = irqMgr;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
osCreateMesgQueue(&padMgr->interruptQueue, padMgr->interruptMsgBuf, ARRAY_COUNT(padMgr->interruptMsgBuf));
|
|
|
|
IrqMgr_AddClient(padMgr->irqMgr, &padMgr->irqClient, &padMgr->interruptQueue);
|
2022-09-03 00:52:13 +00:00
|
|
|
|
|
|
|
osCreateMesgQueue(&padMgr->serialLockQueue, &padMgr->serialMsg, 1);
|
|
|
|
PadMgr_ReleaseSerialEventQueue(padMgr, serialEventQueue);
|
|
|
|
|
|
|
|
osCreateMesgQueue(&padMgr->lockQueue, &padMgr->lockMsg, 1);
|
2021-02-14 00:49:40 +00:00
|
|
|
PadMgr_UnlockPadData(padMgr);
|
2022-09-03 00:52:13 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
PadSetup_Init(serialEventQueue, (u8*)&padMgr->validCtrlrsMask, padMgr->padStatus);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2022-09-03 00:52:13 +00:00
|
|
|
padMgr->nControllers = MAXCONTROLLERS;
|
2021-02-14 00:49:40 +00:00
|
|
|
osContSetCh(padMgr->nControllers);
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-02-14 00:49:40 +00:00
|
|
|
osCreateThread(&padMgr->thread, id, (void (*)(void*))PadMgr_ThreadEntry, padMgr, stack, priority);
|
|
|
|
osStartThread(&padMgr->thread);
|
2020-03-17 04:31:30 +00:00
|
|
|
}
|