diff --git a/include/controller.h b/include/controller.h new file mode 100644 index 0000000..b3db6ce --- /dev/null +++ b/include/controller.h @@ -0,0 +1,43 @@ +#ifndef _CONTROLLER_H_ +#define _CONTROLLER_H_ + +struct Controller { + /* 0x00 */ s16 contId; + /* 0x02 */ s16 rawStickX; + /* 0x04 */ s16 rawStickY; + /* 0x06 */ u16 buttonDown; + /* 0x08 */ u16 buttonPressed; + /* 0x0A */ u16 unkA; + char fillerC[2]; + /* 0x0E */ u16 unkE; + /* 0x10 */ float stickMag; + /* 0x14 */ float stickX; + /* 0x18 */ float stickY; + /* 0x1C */ OSContStatus *statusData; + /* 0x20 */ OSContPad *controllerData; +}; + +extern struct Controller gControllers[4]; +extern OSMesgQueue gSIEventMesgQueue; +extern u8 gControllerBits; +extern u8 gEepromProbe; +extern OSContStatus gControllerStatuses[4]; +extern OSContPad gControllerPads[4]; +extern OSMesg gSIEventMesgBuf[1]; +extern OSMesg gEepromMesgBuf[1]; +extern OSMesgQueue gEepromMesgQueue; + +void Cont_InitControllers(void); +void Cont_AdjustAnalogStick(struct Controller *controller); +void Cont_StartReadInputs(void); +void Cont_ReadInputs(void); +u8 Cont_GetControllerBits(void); +s32 Cont_IsEepromPresent(void); +s32 Cont_AttemptReadEeprom(u8* buffer, u32 size, s32 inaddr); +s32 Cont_AttemptWriteEeprom(u8* buffer, u32 size, s32 inaddr); +void Cont_BlockEepromQueue(void); +void Cont_NoBlockEepromQueue(void); +void Cont_InitEepromQueue(void); +u8 Cont_SetupControllers(void); + +#endif // _CONTROLLER_H_ diff --git a/include/macros.h b/include/macros.h index 348832d..919c14c 100644 --- a/include/macros.h +++ b/include/macros.h @@ -25,4 +25,8 @@ typedef unsigned long uintptr_t; #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 +#define ALIGN4(val) (((val) + 0x3) & ~0x3) +#define ALIGN8(val) (((val) + 0x7) & ~0x7) +#define ALIGN16(val) (((val) + 0xF) & ~0xF) + #endif diff --git a/splat.yaml b/splat.yaml index 908b3bb..8c5170b 100644 --- a/splat.yaml +++ b/splat.yaml @@ -41,7 +41,7 @@ segments: - [0x3A80, asm] # transition loader - [0x3FB0, asm] # PRES-JPEG decoder - [0x60A0, asm] # - - [0x6430, asm] # controller code + - [0x6430, c, controller] # controller code - [0x6A40, asm] # - [0x6BC0, asm] # - [0x75F0, asm] # stage loader @@ -366,6 +366,8 @@ segments: - {vram: 0x8007F190, type: .bss, name: main} - {vram: 0x80081900, type: .bss, name: rsp} - {vram: 0x80083CA0, type: .bss, name: unk_bss} + - {vram: 0x800A7320, type: .bss, name: controller} + - {vram: 0x800A7420, type: .bss, name: unk_bss_3} - {vram: 0x800A74C0, type: .bss, name: crash_screen} - {vram: 0x800A7EA0, type: .bss, name: unk_bss_2} - {vram: 0x80103880, type: .bss, name: libultra/gu/rotate} diff --git a/src/controller.c b/src/controller.c new file mode 100644 index 0000000..9888e16 --- /dev/null +++ b/src/controller.c @@ -0,0 +1,230 @@ +#include +#include "controller.h" + +// TODO: Identify/move to header +extern s16 func_8000A360(float, float); + +struct Controller gControllers[4]; +OSMesgQueue gSIEventMesgQueue; +u8 gControllerBits; +u8 gEepromProbe; +OSContStatus gControllerStatuses[4]; +OSContPad gControllerPads[4]; +OSMesg gSIEventMesgBuf[1]; +OSMesg gEepromMesgBuf[1]; +OSMesgQueue gEepromMesgQueue; + +/* + * Initialize the gControllers structs. Clear each member, then set their cont + * id and set the status and pads pointers. + */ +void Cont_InitControllers(void) { + int i; + + // clear each gControllers member. + for(i = 0; i < MAXCONTROLLERS; i++) { + bzero((void*)&gControllers[i], sizeof(struct Controller)); + } + + // Initialize each connected controller. + for(i = 0; i < MAXCONTROLLERS; i++) { + // If the bit is set in this bitfield for each iteration, it means + // the controller is connected. Set the ID and pointers respectively. + if(gControllerBits & (1 << i)) { + gControllers[i].contId = (i+1); // indexed by 1. (cont 1, cont 2, etc) + gControllers[i].statusData = &gControllerStatuses[i]; + gControllers[i].controllerData = &gControllerPads[i]; + } + } +} + +/* + * Take the updated controller struct and calculate + * the new x, y, and distance floats. + */ +void Cont_AdjustAnalogStick(struct Controller *controller) { + // reset the controller's x and y floats. + controller->stickX = 0.0f; + controller->stickY = 0.0f; + + // modulate the rawStickX and rawStickY to be the new f32 values by adding/subtracting 6. + if (controller->rawStickX <= -8) { + controller->stickX = controller->rawStickX + 6; + } + + if (controller->rawStickX >= 8) { + controller->stickX = controller->rawStickX - 6; + } + + if (controller->rawStickY <= -8) { + controller->stickY = controller->rawStickY + 6; + } + + if (controller->rawStickY >= 8) { + controller->stickY = controller->rawStickY - 6; + } + + // calculate f32 magnitude from the center by vector length. + controller->stickMag = + sqrtf(controller->stickX * controller->stickX + controller->stickY * controller->stickY); + + // magnitude cannot exceed 64.0f: if it does, modify the values appropriately to + // flatten the values down to the allowed maximum value. + if (controller->stickMag > 64) { + controller->stickX *= 64 / controller->stickMag; + controller->stickY *= 64 / controller->stickMag; + controller->stickMag = 64; + } + + + if (controller->stickMag > 0.0f) { + controller->unkE = func_8000A360(-controller->stickY, controller->stickX); + } +} + +/* + * Start the reading of the controller inputs into the current structs. + */ +void Cont_StartReadInputs(void) { + Cont_BlockEepromQueue(); + osContStartReadData(&gSIEventMesgQueue); +} + +/* + * Read in the inputs into the pads and then update the controller structs accordingly based on + * new button masks and held button masks. + */ +void Cont_ReadInputs(void) { + s32 i; + struct Controller *controller = &gControllers[0]; + + osRecvMesg(&gSIEventMesgQueue, NULL, OS_MESG_BLOCK); + osContGetReadData(&gControllerPads[0]); + Cont_NoBlockEepromQueue(); + + for(i = 0; i < 4; i++, controller++) { + // if the contId is not 0, it means the controller is initialized. + if(controller->contId != 0) { + controller->rawStickX = controller->controllerData->stick_x; + controller->rawStickY = controller->controllerData->stick_y; + controller->buttonPressed = controller->controllerData->button + & (controller->controllerData->button ^ controller->buttonDown); + controller->unkA = controller->buttonDown + & (controller->controllerData->button ^ controller->buttonDown); + controller->buttonDown = controller->controllerData->button; + + Cont_AdjustAnalogStick(controller); + } else { + controller->buttonPressed = 0; + controller->unkA = 0; + controller->buttonDown = 0; + } + } + func_8000B330(); +} + +/* + * Retrieve the current controller bits. + */ +u8 Cont_GetControllerBits(void) { + return gControllerBits; +} + +/* + * Check if an EEPROM is connected. Since probe 0x00 is not connected and + * 0x01 and 0x02 are otherwise, a non-0 probe means it is connected. + */ +s32 Cont_IsEepromPresent(void) { + return gEepromProbe != 0; +} + +/* + * Attempt to read from EEPROM up to 4 times given a buffer and size and inaddr. + * A return of 0 indicates success while -1 is an EEPROM error. + */ +s32 Cont_AttemptReadEeprom(u8* buffer, u32 size, s32 inaddr) { + s32 result = 1; + if (gEepromProbe) { + s32 i = 4; + Cont_BlockEepromQueue(); + do { + // Get the number of 8-byte buffers to send, since we are sending in 8 + // byte chunks. + s32 count = size / 8; + // this value must be a multiple of 8 due to hardware restrictions as + // specified by http://n64devkit.square7.ch/n64man/os/osEepromLongRead.htm. + // Force the value to be a multiple of 8 to adhere to the restrictions. + s32 address = ALIGN8(inaddr); + i --; + // once the result is 0 (success), exit from the loop since the write was successful. + result = osEepromLongRead(&gSIEventMesgQueue, count, buffer, address); + } while (i > 0 && result); + Cont_NoBlockEepromQueue(); + } + return result; +} + +/* + * Attempt to write to EEPROM up to 4 times given a buffer and size and inaddr. + * A return of 0 indicates success while -1 is an EEPROM error. + */ +s32 Cont_AttemptWriteEeprom(u8* buffer, u32 size, s32 inaddr) { + s32 result = 1; + if (gEepromProbe) { + s32 i = 4; + Cont_BlockEepromQueue(); + do { + // Get the number of 8-byte buffers to send, since we are sending in 8 + // byte chunks. + s32 count = size / 8; + // this value must be a multiple of 8 due to hardware restrictions as + // specified by http://n64devkit.square7.ch/n64man/os/osEepromLongRead.htm. + // Force the value to be a multiple of 8 to adhere to the restrictions. + s32 address = ALIGN8(inaddr); + i --; + // once the result is 0 (success), exit from the loop since the write was successful. + result = osEepromLongWrite(&gSIEventMesgQueue, count, buffer, address); + } while (i > 0 && result); + Cont_NoBlockEepromQueue(); + } + return result; +} + +/* + * Run a Block Mesg against the Eeprom queue. + */ +void Cont_BlockEepromQueue(void) { + osRecvMesg(&gEepromMesgQueue, NULL, OS_MESG_BLOCK); +} + +/* + * Run a No Block Mesg against the Eeprom queue. + */ +void Cont_NoBlockEepromQueue(void) { + osSendMesg(&gEepromMesgQueue, NULL, OS_MESG_NOBLOCK); +} + +/* + * Initialize the Eeprom Mesg queue. + */ +void Cont_InitEepromQueue(void) { + osCreateMesgQueue(&gEepromMesgQueue, gEepromMesgBuf, 1); + osSendMesg(&gEepromMesgQueue, NULL, OS_MESG_NOBLOCK); +} + +/* + * Setup the controllers for initial use by initializing the EEPROM queue + * and SI Event queues. EEPROM probing was handled by game_init.c in Super + * Mario 64 which also handled the controllers in the same file. Since + * Nintendo EAD is also credited with co-developing Pokemon Stadium, this + * organization may be a holdover from that era. + */ +u8 Cont_SetupControllers(void) { + Cont_InitEepromQueue(); + osCreateMesgQueue(&gSIEventMesgQueue, gSIEventMesgBuf, 1); + osSetEventMesg(OS_EVENT_SI, &gSIEventMesgQueue, NULL); + osContInit(&gSIEventMesgQueue, &gControllerBits, &gControllerStatuses[0]); + gEepromProbe = osEepromProbe(&gSIEventMesgQueue); + Cont_InitControllers(); + return gControllerBits; +} diff --git a/src/crash_screen.c b/src/crash_screen.c index 2a7cc68..fd1a405 100644 --- a/src/crash_screen.c +++ b/src/crash_screen.c @@ -86,8 +86,8 @@ void crash_screen_wait_for_button_combo(void) { s32 i = 0; do { - func_80005A84(); - func_80005AB0(); + Cont_StartReadInputs(); + Cont_ReadInputs(); if (((u16*)D_80068BA0[0])[4] != 0) { if (((u16*)D_80068BA0[0])[4] == gCrashScreenUnlockInputs[i++]) { // have we reached the end of the array? exit the sleep loop. diff --git a/src/unk_bss.c b/src/unk_bss.c index 4c7642a..bdf95e6 100644 --- a/src/unk_bss.c +++ b/src/unk_bss.c @@ -1,4 +1,4 @@ #include // used for padding. Splat cant auto gen these I guess -static u8 unk_bss[0x800A74C0-0x80083CA0]; +static u8 unk_bss[0x800A7320-0x80083CA0]; diff --git a/src/unk_bss_3.c b/src/unk_bss_3.c new file mode 100644 index 0000000..31ed8e2 --- /dev/null +++ b/src/unk_bss_3.c @@ -0,0 +1,4 @@ +#include + +// used for padding. Splat cant auto gen these I guess +static u8 unk_bss[0x800A74C0-0x800A7420]; diff --git a/tools/symbol_addrs.txt b/tools/symbol_addrs.txt index 5016cdc..b2ffd4e 100644 --- a/tools/symbol_addrs.txt +++ b/tools/symbol_addrs.txt @@ -422,4 +422,24 @@ Memmap_GetFragmentBaseVaddr = 0x800020CC; Memmap_GetFragmentVaddr = 0x800020E0; Memmap_GetFragmentVaddrMask = 0x80002144; Memmap_ClearFragmentMemmap = 0x8000218C; -Memmap_GetLoadedFragmentVaddr = 0x800021A8; \ No newline at end of file +Memmap_GetLoadedFragmentVaddr = 0x800021A8; +gControllerStatuses = 0x800A73D0; +gControllerPads = 0x800A73E0; +gSIEventMesgQueue = 0x800A73B0; +gControllerBits = 0x800A73C8; +gEepromProbe = 0x800A73C9; +gSIEventMesgBuf = 0x800A73F8; +gEepromMesgQueue = 0x800A7400; +gEepromMesgBuf = 0x800A73FC; +Cont_InitControllers = 0x80005830; +Cont_AdjustAnalogStick = 0x80005950; +Cont_StartReadInputs = 0x80005A84; +Cont_ReadInputs = 0x80005AB0; +Cont_GetControllerBits = 0x80005B90; +Cont_IsEepromPresent = 0x80005B9C; +Cont_AttemptReadEeprom = 0x80005BAC; +Cont_AttemptWriteEeprom = 0x80005C64; +Cont_BlockEepromQueue = 0x80005D1C; +Cont_NoBlockEepromQueue = 0x80005D48; +Cont_InitEepromQueue = 0x80005D74; +Cont_SetupControllers = 0x80005DB8; \ No newline at end of file