diff --git a/include/n64/PR/os_cont.h b/include/n64/PR/os_cont.h index e46f2d7ba..e4cbf06cd 100644 --- a/include/n64/PR/os_cont.h +++ b/include/n64/PR/os_cont.h @@ -316,7 +316,7 @@ typedef union { } raw; /*0x08*/ } GCNInputData; /*0x08*/ -// -- Virtual Controller (OSContPadEx) buttons -- +// -- Virtual Controller buttons (used by OSContPadEx) -- typedef union { struct PACKED { @@ -340,8 +340,8 @@ typedef union { * Structure for controllers */ -typedef struct { - /*0x00*/ u16 type; /* Controller Type */ +typedef struct { //! TODO: Accessory type. + /*0x00*/ u16 type; /* Controller Type (SI identifier, byteswapped) */ /*0x02*/ u8 status; /* Controller status */ /*0x03*/ u8 error; /* Error */ } OSContStatus; /*0x04*/ @@ -365,17 +365,19 @@ typedef struct PACKED { typedef struct { /*0x00*/ OSContButtons button; /* Button data */ /*0x02*/ OSContButtons lockedButton; /* Button data to ignore */ - /*0x04*/ Analog_s8 stick; /* -80 <= stick <= 80 */ - /*0x06*/ Analog_s8 c_stick; /* -80 <= c_stick <= 80 */ - /*0x08*/ Analog_u8 trig; /* 0 <= trig <= 255 */ - /*0x0A*/ OSContOrigins origins; /* GCN analog origins */ - /*0x12*/ union { /* Extra bits not set by controller buttons */ + /*0x04*/ OSContButtons statPollButton; /* Previous frame's inputs when status polling. */ + /*0x06*/ Analog_s8 stick; /* -80 <= stick <= 80 */ + /*0x08*/ Analog_s8 c_stick; /* -80 <= c_stick <= 80 */ + /*0x0A*/ Analog_u8 trig; /* 0 <= trig <= 255 */ + /*0x0C*/ OSContOrigins origins; /* GCN analog origins */ + /*0x14*/ union { /* Extra bits not set by controller buttons */ N64Buttons n64; GCNButtons gcn; u16 raw; } ex; /*0x02*/ - /*0x14*/ u8 errno; /* Error number */ -} OSContPadEx; /*0x15*/ + /*0x16*/ u8 gcnRumble; /* Stored GCN rumble byte */ + /*0x17*/ u8 errno; /* Error number */ +} OSContPadEx; /*0x18*/ typedef struct { /*0x00*/ void *address; /* Ram pad Address: 11 bits */ diff --git a/src/game/area.c b/src/game/area.c index 2545fe0b2..f2647bf95 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -455,7 +455,6 @@ void render_controllers_overlay(void) { const s32 texW = 32; const s32 texH = 32; Texture* texture_controller = texture_controller_unknown; - OSPortInfo* portInfo = NULL; char text_buffer[32] = ""; int port; @@ -478,11 +477,9 @@ void render_controllers_overlay(void) { // Draw the port icons: for (port = 0; port < MAXCONTROLLERS; port++) { - portInfo = &gPortInfo[port]; - // Loop through sControllerIcons to get the port's corresponding texture. for (int i = 0; i < ARRAY_COUNT(sControllerIcons); i++) { - if (portInfo->type == sControllerIcons[i].type) { + if (gControllerStatuses[port].type == sControllerIcons[i].type) { texture_controller = sControllerIcons[i].texture; break; } @@ -531,10 +528,9 @@ void render_controllers_overlay(void) { // Print the assigned port numbers. for (port = 0; port < MAXCONTROLLERS; port++) { - portInfo = &gPortInfo[port]; - - if (portInfo->plugged && portInfo->playerNum) { - sprintf(text_buffer, "P%d", portInfo->playerNum); + // Print if a controller is plugged in and assigned to a player. + if ((gControllerStatuses[port].type != CONT_NONE) && (gControllerPlayerNumbers[port] != 0)) { + sprintf(text_buffer, "P%d", gControllerPlayerNumbers[port]); drawSmallString(&dlHead, ((SCREEN_CENTER_X - (w * (MAXCONTROLLERS / 2))) + (w * port) + 8), (SCREEN_CENTER_Y + 16), text_buffer); } } diff --git a/src/game/input.c b/src/game/input.c index a42a980bb..01ac39602 100644 --- a/src/game/input.c +++ b/src/game/input.c @@ -22,6 +22,7 @@ struct Controller* const gPlayer4Controller = &gControllers[3]; // OS Controllers. OSContStatus gControllerStatuses[MAXCONTROLLERS]; OSContPadEx gControllerPads[MAXCONTROLLERS]; +u8 gControllerPlayerNumbers[MAXCONTROLLERS]; // 0 = not assigned to a player. u8 gNumPlayers = 0; // The number of controllers currently assigned to a player. u8 gControllerBits = 0b0000; // Which ports have a controller connected to them (low to high). @@ -170,7 +171,7 @@ ALWAYS_INLINE _Bool check_button_pressed_combo(u16 buttonDown, u16 buttonPressed * @param[out] controller The controller to link. * @param[in ] port The port to get the data from. */ -void assign_controller_data(struct Controller* controller, int port) { +void assign_controller_data_to_port(struct Controller* controller, int port) { controller->statusData = &gControllerStatuses[port]; controller->controllerData = &gControllerPads[port]; controller->port = port; @@ -181,7 +182,6 @@ void assign_controller_data(struct Controller* controller, int port) { * Automatically assignins controller numbers based on port order. */ void assign_controllers_by_port_order(void) { - OSPortInfo* portInfo = NULL; int port, cont = 0; int lastUsedPort = -1; @@ -192,13 +192,11 @@ void assign_controllers_by_port_order(void) { break; } - portInfo = &gPortInfo[port]; + // Is a controller plugged in? + if (gControllerStatuses[port].type != CONT_NONE) { + gControllerPlayerNumbers[port] = (cont + 1); - // Is the controller plugged in? - if (portInfo->plugged) { - portInfo->playerNum = (cont + 1); - - assign_controller_data(&gControllers[cont], port); + assign_controller_data_to_port(&gControllers[cont], port); lastUsedPort = port; @@ -215,18 +213,17 @@ void assign_controllers_by_port_order(void) { * Assigns controllers based on assigned data from status polling. */ void assign_controllers_by_player_num(void) { - OSPortInfo* portInfo = NULL; int port; int lastUsedPort = -1; // Loop over the 4 ports and link the controller structs to the appropriate status and pad. // The game allows you to have a controller plugged into any port in order to play the game. for (port = 0; port < MAXCONTROLLERS; port++) { - portInfo = &gPortInfo[port]; + u8 playerNum = gControllerPlayerNumbers[port]; - // Is controller plugged in and assigned to a player? - if (portInfo->plugged && portInfo->playerNum) { - assign_controller_data(&gControllers[portInfo->playerNum - 1], port); + // Is a controller plugged in and assigned to a player? + if ((gControllerStatuses[port].type != CONT_NONE) && (playerNum != 0)) { + assign_controller_data_to_port(&gControllers[playerNum - 1], port); lastUsedPort = port; } @@ -282,12 +279,33 @@ static void poll_controller_statuses(OSMesg* mesg) { release_rumble_pak_control(); } +/** + * @brief Disconnects/resets all controller data. + */ +void reset_all_controller_data(void) { + gNumPlayers = 0; + + bzero(gControllers, sizeof(gControllers )); + bzero(gControllerStatuses, sizeof(gControllerStatuses )); + bzero(gControllerPads, sizeof(gControllerPads )); + bzero(gControllerPlayerNumbers, sizeof(gControllerPlayerNumbers)); + + // for (int port = 0; port < MAXCONTROLLERS; port++) { + // gControllerPads[port].statPollButton.raw = 0x0000; + // gControllerPads[port].gcnRumble = 0; + // } + + cancel_rumble(); +} + /** * @brief Starts polling for new controllers and open the UI. * @param[in] isBootMode Boolean. Only used when MAX_SUPPORTED_CONTROLLERS is 1. Triggers a separate mode where the UI is * invisible and the controller with the first detected input (including analog sticks) becomes player 1. */ void start_controller_status_polling(_Bool isBootMode) { + reset_all_controller_data(); + if (isBootMode) { gContStatusPollingReadyForInput = TRUE; } @@ -295,13 +313,6 @@ void start_controller_status_polling(_Bool isBootMode) { gContStatusPollingIsBootMode = isBootMode; gContStatusPolling = TRUE; gContStatusPollTimer = 0; - gNumPlayers = 0; - - bzero(gPortInfo, sizeof(gPortInfo )); - bzero(gControllers, sizeof(gControllers )); - bzero(gControllerStatuses, sizeof(gControllerStatuses)); - - cancel_rumble(); } /** @@ -349,22 +360,21 @@ static _Bool detect_analog_stick_input(OSContPadEx* pad, const s8 deadzone) { * @brief Assign player numbers to controllers based on player input. */ void read_controller_inputs_status_polling(void) { - OSPortInfo* portInfo = NULL; u16 totalInput = 0x0; // Read inputs from all four ports when status polling. for (int port = 0; port < MAXCONTROLLERS; port++) { - portInfo = &gPortInfo[port]; + OSContPadEx* pad = &gControllerPads[port]; - if (portInfo->plugged) { - OSContPadEx* pad = &gControllerPads[port]; + // Check whether a controller is plugged in to this port. + if (gControllerStatuses[port].type != CONT_NONE) { u16 button = pad->button.raw; totalInput |= button; if (gContStatusPollingReadyForInput) { // If a button is pressed on an unassigned controller, assign it the current player number. if ( - !portInfo->playerNum && + (gControllerPlayerNumbers[port] == 0) && ( button || ( @@ -373,15 +383,15 @@ void read_controller_inputs_status_polling(void) { ) // Only check analog sticks in boot mode. ) ) { - portInfo->playerNum = ++gNumPlayers; + gControllerPlayerNumbers[port] = ++gNumPlayers; } #if (defined(ALLOW_STATUS_REPOLLING_COMBO) && (MAX_NUM_PLAYERS > 1)) - u16 pressed = (~portInfo->statusPollButtons & button); + u16 pressed = (~pad->statPollButton.raw & button); // If the combo is pressed, stop polling and assign the current controllers. if ( !gContStatusPollingIsBootMode && - portInfo->playerNum && + (gControllerPlayerNumbers[port] != 0) && check_button_pressed_combo(button, pressed, TOGGLE_CONT_STATUS_POLLING_COMBO) ) { gContStatusPollingReadyForInput = FALSE; @@ -398,10 +408,10 @@ void read_controller_inputs_status_polling(void) { return; } - portInfo->statusPollButtons = button; + pad->statPollButton.raw = button; } } else { - portInfo->statusPollButtons = 0x0000; + pad->statPollButton.raw = 0x0000; } } diff --git a/src/game/input.h b/src/game/input.h index b34e1baab..0072c616c 100644 --- a/src/game/input.h +++ b/src/game/input.h @@ -33,6 +33,7 @@ extern struct Controller* const gPlayer4Controller; // OS Controllers. extern OSContStatus gControllerStatuses[MAXCONTROLLERS]; extern OSContPadEx gControllerPads[MAXCONTROLLERS]; +extern u8 gControllerPlayerNumbers[MAXCONTROLLERS]; extern u8 gNumPlayers; extern u8 gControllerBits; diff --git a/src/game/joybus.c b/src/game/joybus.c index 998c5caa7..b97f565d1 100644 --- a/src/game/joybus.c +++ b/src/game/joybus.c @@ -8,8 +8,6 @@ #include "input.h" #include "rumble.h" -OSPortInfo gPortInfo[MAXCONTROLLERS] = { 0 }; - void __osSiGetAccess(void); void __osSiRelAccess(void); @@ -104,10 +102,10 @@ s32 osStartRead_impl(OSMesgQueue* mq, u8 cmdID) { (dst) += sizeof(src); \ } -#define WRITE_PIF_CMD_WITH_GCN_RUMBLE(dst, src) { \ - (*(typeof(src)*)(dst)) = (src); \ - (*(typeof(src)*)(dst)).send.rumble = portInfo->gcnRumble; \ - (dst) += sizeof(src); \ +#define WRITE_PIF_CMD_WITH_GCN_RUMBLE(dst, src) { \ + (*(typeof(src)*)(dst)) = (src); \ + (*(typeof(src)*)(dst)).send.rumble = pad->gcnRumble; \ + (dst) += sizeof(src); \ } /** @@ -118,21 +116,22 @@ s32 osStartRead_impl(OSMesgQueue* mq, u8 cmdID) { */ static void __osPackRead_impl(u8 cmdID) { u8* ptr = (u8*)__osContPifRam.ramarray; - OSPortInfo* portInfo = NULL; + OSContPadEx* pad = NULL; int port; bzero(__osContPifRam.ramarray, sizeof(__osContPifRam.ramarray)); __osContPifRam.pifstatus = PIF_STATUS_EXE; for (port = 0; port < __osMaxControllers; port++) { - portInfo = &gPortInfo[port]; + pad = &gControllerPads[port]; // Make sure this port has a controller plugged in, and if not status repolling, only poll assigned ports. - _Bool isEnabled = (portInfo->plugged && (gContStatusPolling || portInfo->playerNum)); - _Bool isGCN = (portInfo->type & CONT_CONSOLE_GCN); + u16 type = gControllerStatuses[port].type; + _Bool isEnabled = ((type != CONT_NONE) && (gContStatusPolling || (gControllerPlayerNumbers[port] != 0))); + _Bool isGCN = (type & CONT_CONSOLE_GCN); switch (cmdID) { - case CONT_CMD_READ_BUTTON: + case CONT_CMD_READ_BUTTON: // Instead of running these commands separately, run one or the other per port depending on the connected controller type. case CONT_CMD_GCN_SHORT_POLL: if (isEnabled) { if (isGCN) { @@ -434,8 +433,7 @@ void osContGetQueryEx(u8* bitpattern, OSContStatus* status) { void __osContGetInitDataEx(u8* pattern, OSContStatus* status) { u8* ptr = (u8*)__osContPifRam.ramarray; __OSContRequestFormatAligned requestHeader; - OSPortInfo* portInfo = NULL; - u8 bits = 0x0; + u8 bits = 0b0000; int port; for (port = 0; port < __osMaxControllers; port++) { @@ -443,19 +441,18 @@ void __osContGetInitDataEx(u8* pattern, OSContStatus* status) { status->error = CHNL_ERR(requestHeader.fmt.size); if (status->error == (CHNL_ERR_SUCCESS >> 4)) { - portInfo = &gPortInfo[port]; - // Byteswap the SI identifier. This is done in vanilla libultra. status->type = ((requestHeader.fmt.recv.type.l << 8) | requestHeader.fmt.recv.type.h); // Check the type of controller device connected to the port. // Some mupen cores seem to send back a controller type of CONT_TYPE_NULL (0xFFFF) if the core doesn't initialize the input plugin quickly enough, // so check for that and set the input type to N64 controller if so. - portInfo->type = ((s16)status->type == (s16)CONT_TYPE_NULL) ? CONT_TYPE_NORMAL : status->type; + if ((s16)status->type == (s16)CONT_TYPE_NULL) { + status->type = CONT_TYPE_NORMAL; + } - // Set this port's status. + // Set this port's status byte. status->status = requestHeader.fmt.recv.status.raw; - portInfo->plugged = TRUE; bits |= (1 << port); } @@ -492,8 +489,9 @@ s32 __osMotorAccessEx(OSPfs* pfs, s32 motorState) { return PFS_ERR_INVALID; } - if (gPortInfo[channel].type & CONT_CONSOLE_GCN) { // GCN Controllers. - gPortInfo[channel].gcnRumble = motorState; + // Check whether the controller is a GCN controller. + if (gControllerStatuses[channel].type & CONT_CONSOLE_GCN) { + gControllerPads[channel].gcnRumble = motorState; // Change the last command ID so that input poll command (which includes rumble) gets written again. __osContLastCmd = PIF_CMD_END; @@ -599,7 +597,8 @@ s32 osMotorInitEx(OSMesgQueue* mq, OSPfs* pfs, int channel) { pfs->channel = channel; pfs->activebank = ACCESSORY_ID_NULL; - if (!(gPortInfo[channel].type & CONT_CONSOLE_GCN)) { + // Make sure the controller is not a GCN controller. + if (!(gControllerStatuses[channel].type & CONT_CONSOLE_GCN)) { // Write probe value (ensure Transfer Pak is turned off). err = __osPfsSelectBank(pfs, ACCESSORY_ID_TRANSFER_OFF); if (err == PFS_ERR_NEW_PACK) { diff --git a/src/game/joybus.h b/src/game/joybus.h index eda1e7a7c..53a14af84 100644 --- a/src/game/joybus.h +++ b/src/game/joybus.h @@ -656,15 +656,6 @@ typedef struct PACKED { /*0x04*/ void (*packFunc)(void); // The function that writes to __osContPifRam. } CommandPackFunc; /*0x08*/ -typedef struct PACKED { - /*0x00*/ u16 type; // The SI identifier of the device plugged into this port. - /*0x02*/ u16 accessory; //! TODO: Accessory type in the controller plugged into in this port. - /*0x04*/ u16 statusPollButtons; // Input, only used when status polling to save the previous frame's inputs. - /*0x06*/ _Bool plugged; // Whether a controller is plugged in to this port. - /*0x07*/ u8 playerNum; // The player number. [0, 4]. 0 = not assigned to a player. - /*0x08*/ u8 gcnRumble; // Stored GCN Rumble byte. -} OSPortInfo; /*0x09*/ - ///////////// // externs // ///////////// @@ -675,6 +666,6 @@ extern u8 __osMaxControllers; // The last port to read controllers on. extern u8 __osContLastCmd; // The ID of the last command that was executed. // From HackerSM64: -extern OSPortInfo gPortInfo[MAXCONTROLLERS]; +// extern OSPortInfo gPortInfo[MAXCONTROLLERS]; void __osContGetInitDataEx(u8* pattern, OSContStatus* status); diff --git a/src/game/profiling.c b/src/game/profiling.c index 154d1c466..761f996e6 100644 --- a/src/game/profiling.c +++ b/src/game/profiling.c @@ -231,7 +231,7 @@ u32 profiler_get_rdp_microseconds() { void profiler_print_times() { u32 microseconds[PROFILER_TIME_COUNT]; - char text_buffer[196]; + char text_buffer[256] = ""; update_fps_timer(); update_total_timer(); @@ -245,10 +245,11 @@ void profiler_print_times() { #endif #ifdef PUPPYPRINT_DEBUG - if (fDebug && sPPDebugPage == PUPPYPRINT_PAGE_PROFILER) { + if (fDebug && sPPDebugPage == PUPPYPRINT_PAGE_PROFILER) #else - if (show_profiler) { + if (show_profiler) #endif + { for (int i = 0; i < PROFILER_TIME_COUNT; i++) { if (i < PROFILER_TIME_TMEM) { microseconds[i] = OS_CYCLES_TO_USEC(all_profiling_data[i].total / PROFILING_BUFFER_SIZE); @@ -259,8 +260,8 @@ void profiler_print_times() { // audio time is removed from the main thread profiling, so add it back here u32 total_cpu = microseconds[PROFILER_TIME_TOTAL] + microseconds[PROFILER_TIME_AUDIO] * 2; - u32 total_rsp = microseconds[PROFILER_TIME_RSP_GFX] + microseconds[PROFILER_TIME_RSP_AUDIO] * 2; - u32 max_rdp = MAX(MAX(microseconds[PROFILER_TIME_TMEM], microseconds[PROFILER_TIME_CMD]), microseconds[PROFILER_TIME_PIPE]); + // u32 total_rsp = microseconds[PROFILER_TIME_RSP_GFX] + microseconds[PROFILER_TIME_RSP_AUDIO]; + // u32 max_rdp = MAX(MAX(microseconds[PROFILER_TIME_TMEM], microseconds[PROFILER_TIME_CMD]), microseconds[PROFILER_TIME_PIPE]); sprintf(text_buffer, "FPS: %5.2f\n" @@ -280,14 +281,14 @@ void profiler_print_times() { " Camera\t\t%d\n" #endif "\n" - "RDP\t\t%d (%d%%)\n" - " Tmem\t\t\t%d\n" - " Cmd\t\t\t%d\n" - " Pipe\t\t\t%d\n" - "\n" - "RSP\t\t%d (%d%%)\n" - " Gfx\t\t\t%d\n" - " Audio\t\t\t%d\n", + "%.8X %.8X\n" + "%.8X %.8X\n" + "%.8X %.8X\n" + "%.8X %.8X\n" + "%.8X %.8X\n" + "%.8X %.8X\n" + "%.8X %.8X\n" + "%.8X %.8X\n", 1000000.0f / microseconds[PROFILER_TIME_FPS], total_cpu, total_cpu / 333, microseconds[PROFILER_TIME_CONTROLLERS], @@ -303,13 +304,14 @@ void profiler_print_times() { #ifdef PUPPYPRINT_DEBUG microseconds[PROFILER_TIME_CAMERA], #endif - max_rdp, max_rdp / 333, - microseconds[PROFILER_TIME_TMEM], - microseconds[PROFILER_TIME_CMD], - microseconds[PROFILER_TIME_PIPE], - total_rsp, total_rsp / 333, - microseconds[PROFILER_TIME_RSP_GFX], - microseconds[PROFILER_TIME_RSP_AUDIO] * 2 + IO_READ(PIF_RAM_START + 0), IO_READ(PIF_RAM_START + 4), + IO_READ(PIF_RAM_START + 8), IO_READ(PIF_RAM_START + 12), + IO_READ(PIF_RAM_START + 16), IO_READ(PIF_RAM_START + 20), + IO_READ(PIF_RAM_START + 24), IO_READ(PIF_RAM_START + 28), + IO_READ(PIF_RAM_START + 32), IO_READ(PIF_RAM_START + 36), + IO_READ(PIF_RAM_START + 40), IO_READ(PIF_RAM_START + 44), + IO_READ(PIF_RAM_START + 48), IO_READ(PIF_RAM_START + 52), + IO_READ(PIF_RAM_START + 56), IO_READ(PIF_RAM_START + 60) ); drawSmallStringDL(10, 8, text_buffer); diff --git a/src/game/rumble.c b/src/game/rumble.c index 13d58e4eb..a274008a7 100644 --- a/src/game/rumble.c +++ b/src/game/rumble.c @@ -349,7 +349,7 @@ static void thread6_rumble_loop(UNUSED void* arg) { osRecvMesg(&gRumbleThreadVIMesgQueue, &msg, OS_MESG_BLOCK); for (int channel = 0; channel < __osMaxControllers; channel++) { - if (gPortInfo[channel].plugged) { + if (gControllerStatuses[channel].type != CONT_NONE) { struct RumbleInfo* info = &gRumbleInfos[channel]; update_rumble_data_queue(info);