diff options
| author | spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> | 2021-11-11 00:37:10 +0100 |
|---|---|---|
| committer | spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> | 2021-11-11 00:37:10 +0100 |
| commit | 8b6a76055ca426c494e16042e21f5e19b870b2ac (patch) | |
| tree | e6c875e8c1bd9169e4f49a1b4ad86026547d7020 /examples | |
| parent | b55bc88017aac1bbe9eab21b480093459c0fd0e1 (diff) | |
| download | psn00bsdk-8b6a76055ca426c494e16042e21f5e19b870b2ac.tar.gz | |
Cleaned up pads example, added CMake script for cartrom
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/io/pads/main.c | 100 | ||||
| -rw-r--r-- | examples/io/pads/spi.c | 22 | ||||
| -rw-r--r-- | examples/lowlevel/cartrom/CMakeLists.txt | 36 | ||||
| -rw-r--r-- | examples/lowlevel/cartrom/makefile | 14 | ||||
| -rw-r--r-- | examples/system/dynlink/display.c | 8 |
5 files changed, 114 insertions, 66 deletions
diff --git a/examples/io/pads/main.c b/examples/io/pads/main.c index bb56a27..ea7219b 100644 --- a/examples/io/pads/main.c +++ b/examples/io/pads/main.c @@ -15,9 +15,12 @@ * but the code in spi.c can be used to read/write sectors on a memory card and * combined with a higher-level filesystem driver for full support. * - * IMPORTANT: this example doesn't work on pcsx-redux, and hasn't yet been - * tested on real hardware and/or with unofficial controllers. It works on - * DuckStation and no$psx though. + * IMPORTANT: this example hasn't yet been tested on real hardware and/or with + * unofficial controllers, which might behave differently at higher poll rates. + * Also keep in mind that many emulators emulate controllers and memory cards + * inaccurately. It is thus recommended to test controller I/O code extensively + * and handle as many edge cases as possible (e.g. partial but valid responses, + * zerofilled responses, slow replies) for maximum compatibility. */ #include <sys/types.h> @@ -54,6 +57,10 @@ static const char *const PAD_TYPEIDS[] = { #define SCREEN_XRES 320 #define SCREEN_YRES 240 +#define BGCOLOR_R 48 +#define BGCOLOR_G 24 +#define BGCOLOR_B 0 + typedef struct { DISPENV disp; DRAWENV draw; @@ -73,14 +80,14 @@ void init_context(CONTEXT *ctx) { db = &(ctx->db[0]); SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES); SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); - setRGB0(&(db->draw), 63, 0, 127); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); db->draw.isbg = 1; db->draw.dtd = 1; db = &(ctx->db[1]); SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES); - setRGB0(&(db->draw), 63, 0, 127); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); db->draw.isbg = 1; db->draw.dtd = 1; @@ -139,13 +146,17 @@ void send_pad_cmd( ); } -// This callback determines whether a pad that identifies as digital is -// actually a DualShock in digital mode by checking how it replied to the -// CONFIG_MODE command. +// This callback determines whether a pad that identified as digital is +// actually a DualShock in digital mode by checking if it started identifying +// as CONFIG_MODE after receiving a configuration command. void dualshock_init_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) { - // Flag the pad as digital-only if it didn't reply. - // FIXME: rx_len should be 8 for digital pads, but sometimes it's only 4 - if (rx_len < 4) { + PADTYPE *pad = (PADTYPE *) buff; + + if ( + (rx_len < 2) || + (pad->raw.prefix != 0x5a) || + (pad->raw.type != PAD_ID_CONFIG_MODE) + ) { printf("no, pad is digital-only (len = %d)\n", rx_len); pad_digital_only[port] = 1; @@ -154,9 +165,13 @@ void dualshock_init_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_le printf("yes, forcing analog mode (len = %d)\n", rx_len); - // Issue further commands to finish configuring the controller. + // Issue further commands to force analog mode on, unlock rumble (not used + // in this example) and enable longer responses containing button pressure + // readings. + // TODO: find out if passing 0x03 instead of 0x02 in PAD_CMD_SET_ANALOG + // locks the analog button, as emulated by DuckStation... // https://gist.github.com/scanlime/5042071 - send_pad_cmd(port, PAD_CMD_SET_ANALOG, 0x01, 0x02, 0); // 0x03 disables analog button...? + send_pad_cmd(port, PAD_CMD_SET_ANALOG, 0x01, 0x02, 0); send_pad_cmd(port, PAD_CMD_INIT_PRESSURE, 0x00, 0x00, 0); // Ignored by DualShock 1 send_pad_cmd(port, PAD_CMD_REQUEST_CONFIG, 0x00, 0x01, 0); send_pad_cmd(port, PAD_CMD_RESPONSE_CONFIG, 0xff, 0xff, 0); // Ignored by DualShock 1 @@ -179,21 +194,22 @@ void poll_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) { // configuration mode. It this fails, it will be flagged as digital-only. // The digital-only flag is reset when the controller is unplugged or stops // returning digital pad responses. - if ((pad->raw.prefix == 0x5a) && (pad->raw.type == PAD_ID_DIGITAL)) { + if ( + rx_len && + (pad->raw.prefix == 0x5a) && + (pad->raw.type == PAD_ID_DIGITAL) + ) { if (!pad_digital_only[port]) { printf("Detecting if pad %d supports config mode... ", port + 1); - send_pad_cmd( - port, - PAD_CMD_CONFIG_MODE, - 0x01, - 0x00, - &dualshock_init_cb - ); + // The pad only identifies as CONFIG_MODE after at least another + // command is sent. + send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, 0); + send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, &dualshock_init_cb); } - } else if (pad_digital_only[port]) { - printf("Clearing digital-only flag for pad %d\n", port + 1); + } else { + //printf("Clearing digital-only flag for pad %d\n", port + 1); pad_digital_only[port] = 0; } @@ -213,13 +229,7 @@ int main(int argc, const char* argv[]) { FntPrint(-1, "COUNTER=%d", counter++); for (uint32_t port = 0; port < 2; port++) { - PADTYPE *pad = (PADTYPE *) pad_buff[port]; - - // According to nocash docs, there is a hardware bug in DualShock - // controllers that causes the prefix byte (normally 0x5a) to turn - // into 0x00 if the analog button is pressed after configuration - // commands have been used. - //if (!pad->raw.prefix != 0x5a) { + // TODO. if (!pad_buff_len[port]) { FntPrint(-1, "\n\nPORT %d: NO DEVICE FOUND\n", port + 1); if ((counter % 64) < 32) @@ -228,26 +238,36 @@ int main(int argc, const char* argv[]) { continue; } - uint32_t type = pad->raw.type; - uint32_t len = pad->raw.len * 2; - if (type == PAD_ID_MULTITAP) - len = 32; + PADTYPE *pad = (PADTYPE *) pad_buff[port]; + PAD_TYPEID type = pad->raw.type; + + // According to nocash docs, there is a hardware bug in DualShock + // controllers that causes the prefix byte (normally 0x5a) to turn + // into 0x00 if the analog button is pressed after configuration + // commands have been used. Thus making sure the prefix is 0x5a + // isn't enough to reliably detect pads. + /*if ((pad->raw.prefix != 0x5a) && (type != PAD_ID_ANALOG)) { + FntPrint(-1, "\n\nPORT %d: INVALID RESPONSE\n", port + 1); + if ((counter % 64) < 32) + FntPrint(-1, " CHECK CONNECTION..."); + + continue; + }*/ FntPrint( -1, - "\n\nPORT %d: %s\n TYPE=%d LEN=%d", + "\n\nPORT %d: %s (TYPE=%d)\n", port + 1, PAD_TYPEIDS[type], - type, - len + type ); // Print a hexdump of the payload returned by the pad. - for (uint32_t i = 0; i < len; i++) + for (uint32_t i = 0; i < pad_buff_len[port]; i++) FntPrint( -1, - (i % 8) ? " %02x" : "\n %02x", - pad_buff[port][i + 2] + ((i - 2) % 8) ? " %02x" : "\n %02x", + pad_buff[port][i] ); } diff --git a/examples/io/pads/spi.c b/examples/io/pads/spi.c index 4728626..5fc2648 100644 --- a/examples/io/pads/spi.c +++ b/examples/io/pads/spi.c @@ -2,9 +2,9 @@ * PSn00bSDK controller polling example (SPI driver) * (C) 2021 spicyjpeg - MPL licensed * - * This is a fairly complete timer driven high-speed SPI driver, with support - * for sending custom commands (including memory card reads/writes), in about - * 200 lines of code. Feel free to copypaste and adapt it. + * This is a fairly complete timer driven, asynchronous high-speed SPI driver, + * with support for sending custom commands (including memory card access), in + * about 200 lines of code. Feel free to copypaste and adapt it. * * The way this works is by maintaining a queue of requests to send, each with * its own payload and callback. Timer 2 is configured to trigger an IRQ at @@ -42,8 +42,12 @@ #define TIM_VALUE(N) *((volatile uint32_t *) 0x1f801100 + 4 * (N)) #define TIM_CTRL(N) *((volatile uint32_t *) 0x1f801104 + 4 * (N)) #define TIM_RELOAD(N) *((volatile uint32_t *) 0x1f801108 + 4 * (N)) -#define JOY_TXRX *((volatile uint32_t *) 0x1f801040) -#define JOY_STAT *((volatile uint32_t *) 0x1f801044) + +// IMPORTANT: even though JOY_TXRX is a 32-bit register, it should only be +// accessed as 8-bit. Reading it as 16 or 32-bit works fine on real hardware, +// but leads to problems in some emulators. +#define JOY_TXRX *((volatile uint8_t *) 0x1f801040) +#define JOY_STAT *((volatile uint16_t *) 0x1f801044) #define JOY_MODE *((volatile uint16_t *) 0x1f801048) #define JOY_CTRL *((volatile uint16_t *) 0x1f80104a) #define JOY_BAUD *((volatile uint16_t *) 0x1f80104e) @@ -142,11 +146,9 @@ static void spi_ack_handler(void) { if (!ctx.rx_len) { // We just sent the first address byte. Obviously the response we // received was read from an open bus, so the SPI port's internal FIFO - // must be flushed to ensure we are only going to read valid data from - // now on. - volatile uint32_t dummy; - while (JOY_STAT & 0x0002) - dummy = JOY_TXRX; + // must be flushed (by performing dummy reads) to ensure we are only + // going to read valid data from now on. + JOY_TXRX; } else if (ctx.rx_len <= SPI_BUFF_LEN) { // If this is not the first byte, put it in the RX buffer. diff --git a/examples/lowlevel/cartrom/CMakeLists.txt b/examples/lowlevel/cartrom/CMakeLists.txt new file mode 100644 index 0000000..3e807a3 --- /dev/null +++ b/examples/lowlevel/cartrom/CMakeLists.txt @@ -0,0 +1,36 @@ +# PSn00bSDK example CMake script +# (C) 2021 spicyjpeg - MPL licensed + +cmake_minimum_required(VERSION 3.21) + +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) + set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) +endif() + +project( + cartrom + LANGUAGES C ASM + VERSION 1.0.0 + DESCRIPTION "PSn00bSDK expansion port ROM example" + HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" +) + +file(GLOB _sources *.c *.s) + +# This example only uses the toolchain (without the rest of the SDK), so the +# executable has to be created manually and converted into raw binary format +# (for testing on emulators or flashing to a cheat cartridge). +add_executable (cartrom ${_sources}) +target_link_libraries(cartrom psn00bsdk_static_exe) +set_target_properties(cartrom PROPERTIES PREFIX "" SUFFIX ".elf") +target_link_options (cartrom PRIVATE -T${PROJECT_SOURCE_DIR}/rom.ld) + +target_include_directories(cartrom PRIVATE ${PROJECT_SOURCE_DIR}) + +add_custom_command( + TARGET cartrom POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary cartrom.elf cartrom.bin + BYPRODUCTS cartrom.bin +) + +install(FILES ${PROJECT_BINARY_DIR}/cartrom.bin TYPE BIN) diff --git a/examples/lowlevel/cartrom/makefile b/examples/lowlevel/cartrom/makefile deleted file mode 100644 index 2434685..0000000 --- a/examples/lowlevel/cartrom/makefile +++ /dev/null @@ -1,14 +0,0 @@ -PREFIX = mipsel-unknown-elf- - -CC = $(PREFIX)gcc -AS = $(PREFIX)as -LD = $(PREFIX)ld - -all: rom.o - $(LD) --oformat binary -T rom.ld -o cartrom.rom rom.o - -%.o: %.s - $(AS) -msoft-float --warn $< -o $@ - -clean: - rm -f rom.o cartrom.rom
\ No newline at end of file diff --git a/examples/system/dynlink/display.c b/examples/system/dynlink/display.c index d8ad3ed..573f17c 100644 --- a/examples/system/dynlink/display.c +++ b/examples/system/dynlink/display.c @@ -10,6 +10,10 @@ #define SCREEN_XRES 320 #define SCREEN_YRES 240 +#define BGCOLOR_R 48 +#define BGCOLOR_G 24 +#define BGCOLOR_B 0 + /* Display/GPU context utilities */ void init_context(CONTEXT *ctx) { @@ -23,14 +27,14 @@ void init_context(CONTEXT *ctx) { db = &(ctx->db[0]); SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES); SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); - setRGB0(&(db->draw), 63, 0, 127); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); db->draw.isbg = 1; db->draw.dtd = 1; db = &(ctx->db[1]); SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES); - setRGB0(&(db->draw), 63, 0, 127); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); db->draw.isbg = 1; db->draw.dtd = 1; |
