summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/macros.h14
-rw-r--r--source/state.h57
-rw-r--r--source/states/menu.c98
-rw-r--r--source/template.c303
-rw-r--r--source/term.h13
-rw-r--r--source/test-impl.inc.h53
-rw-r--r--source/test.c453
-rw-r--r--source/test.h122
-rw-r--r--source/tests/basic.c79
-rw-r--r--source/tests/led.c38
10 files changed, 0 insertions, 1230 deletions
diff --git a/source/macros.h b/source/macros.h
deleted file mode 100644
index 9a9db83..0000000
--- a/source/macros.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef EXITEST_MACROS_H_INCLUDED
-#define EXITEST_MACROS_H_INCLUDED
-
-#define STR(_s) STR2(_s)
-#define STR2(_s) #_s
-
-#define PASTE(_x, _y) PASTE2(_x, _y)
-#define PASTE2(_x, _y) _x ## _y
-
-#define COMMA ,
-
-#define ARRLEN(_a) sizeof(_a) / sizeof(*(_a))
-
-#endif /* include guard */
diff --git a/source/state.h b/source/state.h
deleted file mode 100644
index 2f70527..0000000
--- a/source/state.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef EXITEST_STATE_H_INCLUDED
-#define EXITEST_STATE_H_INCLUDED
-
-#include <stdint.h>
-#include <stddef.h>
-
-struct et_state;
-
-typedef union {
- uintptr_t i;
- void *p;
-} et_state_init_data;
-
-extern const et_state_init_data et_init_data_null;
-
-struct et_next_state {
- const struct et_state *state;
- et_state_init_data init_data;
-};
-
-/* Sets up the state. The second argument (void *) should point to at least state->private_size bytes
- * of data. The state assumes responsibility for clearing/initializing this buffer before use.
- *
- * Returns < 0 for error, >= 0 for success.
- * This function conceptually takes ownership of init_data. The implications of this depend
- * on what init_data actually contains -- sometimes it's globally shared data.
- *
- * State authors: Free any data filled into init_data regardless of error states.
- * The caller will not touch init_data again. */
-typedef int (et_state_init_f)(const struct et_state *, void *, et_state_init_data);
-
-/* Ticks the state.
- *
- * Returns < 0 for error (still call cleanup or exit(...)), 0 for "continue", >0 for "advance state".
- * If a state requests to advance to the next state, the info will be in *next_state (which should be non-NULL).
- * Note that next_state->init_data may have malloc()'d data which must be handed off by passing to the init function
- * of the appropriate state. */
-typedef int (et_state_tick_f)(const struct et_state *, void *, struct et_next_state *);
-typedef void (et_state_cleanup_f)(const struct et_state *, void *);
-
-struct et_state {
- et_state_init_f *init_f;
- et_state_tick_f *tick_f;
- et_state_cleanup_f *cleanup_f;
- size_t private_size;
-};
-
-/* convenience macros because these existed as functions at one point
- * (note: state expression is evaluated twice. make sure it doesn't have side effects) */
-
-#define et_state_init(_st, _data, _init_data) ((_st)->init_f(_st, _data, _init_data))
-#define et_state_tick(_st, _data, _next) ((_st)->tick_f(_st, _data, _next))
-#define et_state_cleanup(_st, _data) ((_st)->cleanup_f(_st, _data))
-
-extern const struct et_state *et_state_setup;
-
-#endif /* include guard */
diff --git a/source/states/menu.c b/source/states/menu.c
deleted file mode 100644
index ea5134b..0000000
--- a/source/states/menu.c
+++ /dev/null
@@ -1,98 +0,0 @@
-#include <stdio.h>
-#include <gccore.h>
-#include <wiiuse/wpad.h>
-#include <stdlib.h>
-
-#define EXITEST_STATE_INTERNAL
-#include "../state.h"
-#include "../term.h"
-#include "../test.h"
-
-static void print_setup_menu(int selected_slot) {
- fputs(TERM_CUR_UP(2), stdout);
- printf(TERM_CLEARLINE "- [DL/DR] EXI Slot %c\n", selected_slot == 0 ? 'A' : 'B');
- printf(TERM_CLEARLINE "Press A to begin testing.\n");
-}
-
-static int st_setup_init(const struct et_state *state, void *state_data, et_state_init_data init_data) {
- u32 *setup_data = state_data;
-
- *setup_data = 0;
-
- printf("\nTest setup menu:\n\n\n\n");
- print_setup_menu(*setup_data);
-
- return 0;
-}
-
-static int begin_testing(u32 menu_state, struct et_next_state *next_state) {
- struct et_test_plan *plan = calloc(1, sizeof(struct et_test_plan));
- if (!plan) {
- puts("Failed to allocate new test plan!");
- return -1;
- }
-
- size_t num_tests;
- const struct et_test *const *all_tests = et_get_tests(&num_tests);
-
- struct et_test_plan_entry *plan_entries = calloc(num_tests, sizeof(struct et_test_plan_entry));
- if (!plan_entries) {
- puts("Failed to allocate new test plan entries!");
- free(plan);
- return -1;
- }
-
- for (size_t i = 0; i < num_tests; ++i) {
- plan_entries[i].test = all_tests[i];
- plan_entries[i].status = TEST_PRIMORDIAL;
- plan_entries[i].ext_status = NULL;
- plan_entries[i].ext_status_free = NULL;
- }
-
- plan->exi_channel = (int)menu_state;
- plan->next_state = et_state_summarize_test_plan;
- plan->next_state_init.p = plan;
- plan->num_tests = num_tests;
- plan->current_test = 0;
- plan->tests = plan_entries;
-
- next_state->state = et_state_begin_testing;
- next_state->init_data.p = plan;
-
- putchar('\n');
-
- return 1;
-}
-
-static int st_setup_tick(const struct et_state *state, void *state_data, struct et_next_state *next_state) {
- u32 *setup_data = state_data;
- u32 wpad_pressed = WPAD_ButtonsDown(0);
- u32 pad_pressed = PAD_ButtonsDown(0);
-
- if (wpad_pressed & WPAD_BUTTON_LEFT || wpad_pressed & WPAD_BUTTON_RIGHT || pad_pressed & PAD_BUTTON_LEFT || pad_pressed & PAD_BUTTON_RIGHT) {
- *setup_data = !*setup_data;
- print_setup_menu(*setup_data);
- }
-
- if (wpad_pressed & WPAD_BUTTON_A || pad_pressed & PAD_BUTTON_A) {
- /* set up test plan */
- return begin_testing(*setup_data, next_state);
- }
-
- return 0;
-}
-
-static void st_setup_cleanup(const struct et_state *state, void *state_data) {
- /* do nothing */
-}
-
-const et_state_init_data et_init_data_null = { .p = NULL };
-
-static struct et_state et__state_setup = {
- .init_f = &st_setup_init,
- .tick_f = &st_setup_tick,
- .cleanup_f = &st_setup_cleanup,
- .private_size = sizeof(u32)
-};
-
-const struct et_state *et_state_setup = &et__state_setup;
diff --git a/source/template.c b/source/template.c
deleted file mode 100644
index 8665774..0000000
--- a/source/template.c
+++ /dev/null
@@ -1,303 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <gccore.h>
-#include <wiiuse/wpad.h>
-#include <inttypes.h>
-#include <string.h>
-
-#include "term.h"
-#include "state.h"
-
-static void *xfb = NULL;
-static GXRModeObj *rmode = NULL;
-
-#define TARGET_IOS 58
-
-static void initialize(int again) {
- VIDEO_Init();
-
- rmode = VIDEO_GetPreferredMode(NULL);
- xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
-
- console_init(xfb, 20, 20, rmode->fbWidth - 20, rmode->xfbHeight - 20, rmode->fbWidth * VI_DISPLAY_PIX_SZ);
-
- VIDEO_Configure(rmode);
- VIDEO_SetNextFramebuffer(xfb);
- VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
- VIDEO_SetBlack(FALSE);
- VIDEO_Flush();
- VIDEO_WaitVSync();
- if (rmode->viTVMode & VI_NON_INTERLACE) {
- VIDEO_WaitVSync();
- }
-
- fputs(TERM_CLEAR TERM_CUR_POS(2, 5), stdout);
- printf("USB Gecko (newnewexi) test tool by figboot\n\n");
-
- s32 iosver = IOS_GetVersion();
- s32 iosrev = IOS_GetRevision();
- printf("You're running IOS%" PRId32 " rev %" PRId32 ".\n", iosver, iosrev);
-
- if (iosver != TARGET_IOS) {
- if (again) {
- printf(TERM_CSI("93m") "Failed to set up IOS" STR(TARGET_IOS) "! Bailing out.\n");
- exit(1);
- }
-
- printf("Trying to load IOS" STR(TARGET_IOS) "...\n");
-
- s32 res;
- if ((res = IOS_ReloadIOS(TARGET_IOS)) < 0) {
- printf(TERM_CSI("93m") "Failed to set up IOS" STR(TARGET_IOS) "! IOS_ReloadIOS returned %" PRId32 "\n", res);
- exit(1);
- }
-
- free(MEM_K1_TO_K0(xfb));
- initialize(1);
- }
-}
-
-static void __attribute__((noreturn)) fatal_error(void) {
- printf("The program will now abort due to the fatal error.\n");
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- void *state_data = NULL;
- size_t state_data_size = 0;
- struct et_next_state next;
- const struct et_state *cur_state = NULL;
- int stateres = 0;
-
- u32 wpad_pressed;
- u32 pad_pressed;
-
- initialize(0);
-
- WPAD_Init();
- PAD_Init();
-
- printf("Done initializing.\n");
-
- /* Set up initial state */
- cur_state = et_state_setup;
-
- if (cur_state->private_size > 0) {
- state_data = malloc(cur_state->private_size);
- state_data_size = cur_state->private_size;
- if (!state_data) {
- printf("Failed to allocate private space for setup state %p!", cur_state);
- fatal_error();
- }
- }
-
- if ((stateres = et_state_init(cur_state, state_data, et_init_data_null)) < 0) {
- printf("Failed to init setup state %p: %d\n", cur_state, stateres);
- fatal_error();
- }
-
- while (SYS_MainLoop()) {
- WPAD_ScanPads();
- PAD_ScanPads();
-
- wpad_pressed = WPAD_ButtonsDown(0);
- pad_pressed = PAD_ButtonsDown(0);
-
- if (wpad_pressed & WPAD_BUTTON_HOME || pad_pressed & PAD_BUTTON_START) {
- printf("Exit button pressed. Goodbye!\n");
- exit(0);
- }
-
- stateres = et_state_tick(cur_state, state_data, &next);
- if (stateres < 0) {
- printf("Failed to tick state %p: %d\n", cur_state, stateres);
- fatal_error();
- }
-
- if (stateres > 0) {
- /* tear down the old state first... */
- et_state_cleanup(cur_state, state_data);
-
- cur_state = next.state;
-
- if (state_data_size < cur_state->private_size) {
- void *new_data = realloc(state_data, cur_state->private_size);
- if (!new_data) {
- printf("Failed to allocate %zu bytes for new state %p\n", cur_state->private_size, cur_state);
- fatal_error();
- }
-
- state_data = new_data;
- state_data_size = cur_state->private_size;
- }
-
- if ((stateres = et_state_init(cur_state, state_data, next.init_data)) < 0) {
- printf("Failed to init new state %p: %d\n", cur_state, stateres);
- fatal_error();
- }
- }
-
- VIDEO_WaitVSync();
- }
-
- return 0;
-}
-
-#if 0
-
-//---------------------------------------------------------------------------------
-int main(int argc, char **argv) {
-//---------------------------------------------------------------------------------
-
- // Initialise the video system
- VIDEO_Init();
-
- // This function initialises the attached controllers
- WPAD_Init();
-
- // Obtain the preferred video mode from the system
- // This will correspond to the settings in the Wii menu
- rmode = VIDEO_GetPreferredMode(NULL);
-
- // Allocate memory for the display in the uncached region
- xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
-
- // Initialise the console, required for printf
- console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
-
- // Set up the video registers with the chosen mode
- VIDEO_Configure(rmode);
-
- // Tell the video hardware where our display memory is
- VIDEO_SetNextFramebuffer(xfb);
-
- // Make the display visible
- VIDEO_SetBlack(false);
-
- // Flush the video register changes to the hardware
- VIDEO_Flush();
-
- // Wait for Video setup to complete
- VIDEO_WaitVSync();
- if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
-
-
- // The console understands VT terminal escape codes
- // This positions the cursor on row 2, column 0
- // we can use variables for this with format codes too
- // e.g. printf ("\x1b[%d;%dH", row, column );
- printf("\x1b[2;0H");
-
-
- printf("Hello World!\n");
-
-#define UGCHAN EXI_CHANNEL_1 /* slot B */
-#define UGDEV EXI_DEVICE_0 /* memory card */
-
- if (EXI_Lock(UGCHAN, UGDEV, NULL) == 1) {
- EXI_Select(UGCHAN, UGDEV, EXI_SPEED32MHZ);
- uint32_t cmd = 0x90000000;
- int res = 0;
- if (EXI_Imm(UGCHAN, &cmd, sizeof(cmd), EXI_READWRITE, NULL) == 0) res |= 0x01;
- if (EXI_Sync(UGCHAN) == 0) res |= 0x02;
-
- if (res == 0) {
- printf("Got: 0x%08x\n", cmd);
- if (cmd != 0x04700000) {
- printf("This is probably not a USB gecko...\n");
- }
- } else {
- printf("EXI read/write error :( %#04x\n", res);
- }
-
- EXI_Deselect(UGCHAN);
- EXI_Unlock(UGCHAN);
- } else {
- printf("Failed to lock EXI channel %d %d\n", UGCHAN, UGDEV);
- goto waitexit;
- }
-
- for (int i = 0; i < 10; ++i) {
- if (EXI_Lock(UGCHAN, UGDEV, NULL) == 0) {
- printf("Failed to lock EXI for LED\n");
- break;
- }
-
- int res = 0;
-
- if (EXI_Select(UGCHAN, UGDEV, EXI_SPEED32MHZ) == 0) res |= 0x01;
- uint32_t cmd = (i & 1) ? 0x80000000 : 0x70000000;
- if (EXI_Imm(UGCHAN, &cmd, sizeof(cmd), EXI_WRITE, NULL) == 0) res |= 0x02;
- if (EXI_Sync(UGCHAN) == 0) res |= 0x04;
- if (EXI_Deselect(UGCHAN) == 0) res |= 0x08;
-
- if (EXI_Unlock(UGCHAN) == 0) res |= 0x10;
-
- printf("Error for LED: 0x%02x\n", res);
-
- for (int j = 0; j < 60; ++j) {
- VIDEO_WaitVSync();
- }
- }
-
-
- for (int j = 0; j < 10; ++j) {
- if (EXI_Lock(UGCHAN, UGDEV, NULL) == 1) {
- printf("Sending a zillion bytes to your so-called \"usb gecko\"...\n");
-
- for (int i = 0; i < 4096; ++i) {
- EXI_Select(UGCHAN, UGDEV, EXI_SPEED32MHZ);
-
- uint16_t cmd = 0xB000 | (uint16_t)(((i & 63) + 32) << 4);
- if (EXI_Imm(UGCHAN, &cmd, sizeof(cmd), EXI_READWRITE, NULL) == 0) {
- printf("Failed when writing %d\n", i);
- goto error;
- }
-
- if (EXI_Sync(UGCHAN) == 0) {
- printf("Failed sync when writing %d\n", i);
- goto error;
- }
-
- if ((cmd & 0x0400) == 0) {
- printf("Out of FIFO space at %d\n", i);
- goto error;
- }
-
- EXI_Deselect(UGCHAN);
- continue;
-error:
- EXI_Deselect(UGCHAN);
- break;
- }
-
- EXI_Unlock(UGCHAN);
- } else {
- printf("Failed to lock EXI channel %d %d\n", UGCHAN, UGDEV);
- goto waitexit;
- }
- }
-
-waitexit:
- printf("That's all! Press HOME to exit.\n");
-
- while(SYS_MainLoop()) {
-
- // Call WPAD_ScanPads each loop, this reads the latest controller states
- WPAD_ScanPads();
-
- // WPAD_ButtonsDown tells us which buttons were pressed in this loop
- // this is a "one shot" state which will not fire again until the button has been released
- u32 pressed = WPAD_ButtonsDown(0);
-
- // We return to the launcher application via exit
- if ( pressed & WPAD_BUTTON_HOME ) exit(0);
-
- // Wait for the next frame
- VIDEO_WaitVSync();
- }
-
- return 0;
-}
-#endif
diff --git a/source/term.h b/source/term.h
deleted file mode 100644
index cc65615..0000000
--- a/source/term.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef EXITEST_TERM_H_INCLUDED
-#define EXITEST_TERM_H_INCLUDED
-
-#include "macros.h"
-
-#define TERM_ESC "\x1b"
-#define TERM_CSI(_s) TERM_ESC "[" _s
-#define TERM_CLEAR TERM_CSI("2J")
-#define TERM_CLEARLINE TERM_CSI("2K")
-#define TERM_CUR_POS(_row, _col) TERM_CSI(STR(_row) ";" STR(_col) "f")
-#define TERM_CUR_UP(_rows) TERM_CSI(STR(_rows) "A")
-
-#endif /* include guard */
diff --git a/source/test-impl.inc.h b/source/test-impl.inc.h
deleted file mode 100644
index 8e1559f..0000000
--- a/source/test-impl.inc.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef ET__ALLOW_TEST_IMPL_INC
-#error "Do not include this file directly! Include test.h instead."
-#endif
-
-#undef ET__ALLOW_TEST_IMPL_INC
-
-/* This file will be included in .c files which implement tests. */
-#ifdef _CLANGD
-#include <gccore.h>
-#include "test.h"
-/* include stuff this file uses here to make clangd happy (will not be visible to test.h) */
-#endif
-
-struct et_test_state_private_base {
- struct et_test_plan *plan;
-};
-
-/* function prototypes for test-internal stuff */
-int test_next(struct et_test_plan *plan, struct et_next_state *next_state);
-
-int test_state_init(const struct et_state *state, void *data, et_state_init_data init_data);
-void test_state_cleanup(const struct et_state *state, void *data);
-
-void test_plan_entry_set_error(struct et_test_plan_entry *entry, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-void test_plan_entry_set_error_static(struct et_test_plan_entry *entry, const char *str);
-
-et_test_status test_exi_readwrite(struct et_test_plan *plan, void *data, size_t data_sz, et_test_error base);
-
-/* Expands to a struct initializer for a struct et_test */
-#define TEST_STRUCT_INIT_FULL(_namestr, _flags, _init_f, _tick_f, _cleanup_f, _private_type) \
-{ \
- .parent = { \
- .init_f = test_state_init, \
- .tick_f = _tick_f, \
- .cleanup_f = test_state_cleanup, \
- .private_size = sizeof(_private_type), \
- }, \
- .test_init_f = _init_f, \
- .test_cleanup_f = _cleanup_f, \
- .name = _namestr, \
- .flags = _flags \
-}
-
-#define TEST__STRUCT_NAME(_name) PASTE(TEST_SYM(_name), __struct)
-#define TEST__STRUCT_DEF(_name, _ini) static const struct et_test TEST__STRUCT_NAME(_name) = _ini
-#define TEST__STRUCT_SANITY_CHECK(_ty) static_assert(sizeof(_ty) >= sizeof(struct et_test_state_private_base), "private data type too small (does it include base?)")
-#define TEST__SYM_DEF(_name) const struct et_test *const TEST_SYM(_name) = &TEST__STRUCT_NAME(_name)
-#define TEST_DEF(_name, _namestr, _flags, _init_f, _tick_f, _cleanup_f, _private_type) \
- TEST__STRUCT_SANITY_CHECK(_private_type); \
- TEST__STRUCT_DEF(_name, TEST_STRUCT_INIT_FULL(_namestr, _flags, _init_f, _tick_f, _cleanup_f, _private_type)); \
- TEST__SYM_DEF(_name)
-
-#define test_current(_plan) ((_plan)->tests + (_plan)->current_test)
diff --git a/source/test.c b/source/test.c
deleted file mode 100644
index c59deaf..0000000
--- a/source/test.c
+++ /dev/null
@@ -1,453 +0,0 @@
-#include <assert.h>
-#include <stdio.h>
-#include <gccore.h>
-#include <wiiuse/wpad.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <inttypes.h>
-
-#define TEST_INTERNAL
-#include "test.h"
-#include "term.h"
-
-typedef u32 et_test_status;
-
-#define test_current(_plan) ((_plan)->tests + (_plan)->current_test)
-
-static int crit_test_fail_init(const struct et_state *state, void *data, et_state_init_data init_data) {
- struct et_test_plan *plan = init_data.p;
- struct et_test_plan_entry *last_ent;
-
- *(void **)data = plan;
-
- assert(plan->current_test > 0); /* NOTE: current_test has been incremented by this point */
-
- last_ent = plan->tests + (plan->current_test - 1);
-
- printf("\nCritical test failed: [%4s] %s\n", et_test_get_status_mnemonic(last_ent->status), last_ent->test->name);
- if (last_ent->ext_status) {
- printf("Test says:\n%s\n", last_ent->ext_status);
- } else {
- printf("No extended status.\n");
- }
-
- putchar('\n');
-
- printf("Press A to continue.\n");
- printf("Press B to finish testing.\n");
- printf("Press HOME/START to exit.\n");
-
- return 0;
-}
-
-static int crit_test_fail_tick(const struct et_state *state, void *data, struct et_next_state *next_state) {
- struct et_test_plan *plan = *(void **)data;
- u32 wpad_pressed = WPAD_ButtonsDown(0);
- u32 pad_pressed = PAD_ButtonsDown(0);
-
- if (wpad_pressed & WPAD_BUTTON_A || pad_pressed & PAD_BUTTON_A) {
- next_state->state = et_state_begin_testing; /* also works to resume testing */
- next_state->init_data.p = plan; /* test plan */
- return 1;
- }
-
- if (wpad_pressed & WPAD_BUTTON_B || pad_pressed & PAD_BUTTON_B) {
- next_state->state = plan->next_state;
- next_state->init_data = plan->next_state_init;
- return 1;
- }
-
- if (wpad_pressed & WPAD_BUTTON_HOME || pad_pressed & PAD_BUTTON_START) {
- printf("Goodbye!\n");
- exit(0);
- }
-
- return 0;
-}
-
-static void crit_test_fail_cleanup(const struct et_state *state, void *data) {
- /* do nothing */
-}
-
-static const struct et_state state_crit_test_fail = {
- .private_size = sizeof(struct et_test_plan *),
- .init_f = crit_test_fail_init,
- .tick_f = crit_test_fail_tick,
- .cleanup_f = crit_test_fail_cleanup
-};
-
-int test_next(struct et_test_plan *plan, struct et_next_state *next_state) {
- /* NOTE: this function doesn't increment current_test because the incremented value
- * would be visible in the cleanup function of the test state. */
-
- /* NOTE: this condition will not trigger for states that leak their TEST_PRIMORDIAL status.
- * I don't care about this situation so much, since that should only happen for bugged tests. */
- const struct et_test_plan_entry *ent = test_current(plan);
- switch (TEST_STATUS_GET_TYPE(ent->status)) {
- case TEST_SERROR:
- case TEST_SFAIL:
- if (ent->test->flags & TEST_PAUSE_ON_ERROR) {
- next_state->state = &state_crit_test_fail;
- next_state->init_data.p = plan;
- return 1;
- }
- break;
- default:
- /* do nothing */
- (void)0;
- }
-
- if (plan->current_test == plan->num_tests - 1) {
- /* this is the last state... we're done! */
- next_state->state = plan->next_state;
- next_state->init_data = plan->next_state_init;
- } else {
- next_state->state = &plan->tests[plan->current_test + 1].test->parent;
- next_state->init_data.p = plan;
- }
-
- return 1; /* always return 1: advance to next state */
-}
-
-int test_state_init(const struct et_state *state, void *data, et_state_init_data init_data) {
- struct et_test_plan *plan = init_data.p;
- struct et_test_state_private_base *testdata = data;
- struct et_test_plan_entry *cur = test_current(plan);
- const struct et_test *test = (const struct et_test *)state;
-
- testdata->plan = plan;
-
- assert(cur->test == test); /* ensure correct test was loaded */
- assert(TEST_STATUS_IS_CLEAN(cur->status));
-
- if (test->test_init_f) {
- return test->test_init_f(state, data, init_data);
- }
-
- return 0;
-}
-
-void test_state_cleanup(const struct et_state *state, void *data) {
- struct et_test_state_private_base *testdata = data;
- struct et_test_plan_entry *cur = test_current(testdata->plan);
- const struct et_test *test = (const struct et_test *)state;
-
- if (test->test_cleanup_f) {
- test->test_cleanup_f(state, data);
- }
-
- if (TEST_STATUS_IS_CLEAN(cur->status)) {
- /* test didn't set status :( */
- test_plan_entry_set_error_static(cur, "test aborted");
- cur->status = TEST_ERROR(TEST_EABORT);
- }
-
- printf("[%4s] %s\n", et_test_get_status_mnemonic(cur->status), test->name);
-
- ++testdata->plan->current_test;
-}
-
-static int begin_testing_init(const struct et_state *state, void *state_data, et_state_init_data init_data) {
- struct et_test_plan *test_plan = init_data.p;
- struct et_test_plan **pst_test_plan = state_data;
- *pst_test_plan = test_plan;
- return 0;
-}
-
-static int begin_testing_tick(const struct et_state *state, void *state_data, struct et_next_state *next_state) {
- struct et_test_plan **ptest_plan = state_data;
- struct et_test_plan *test_plan = *ptest_plan;
-
- assert(test_plan->current_test <= test_plan->num_tests);
-
- if (test_plan->current_test < test_plan->num_tests) {
- const struct et_test_plan_entry *next_test = test_plan->tests + test_plan->current_test;
- assert(test_plan->tests);
- assert(next_test->status == TEST_PRIMORDIAL);
-
- next_state->state = &next_test->test->parent;
- next_state->init_data.p = test_plan;
- } else {
- /* no tests to run in this plan */
- next_state->state = test_plan->next_state;
- next_state->init_data = test_plan->next_state_init;
- }
-
- return 1;
-
-}
-
-static void begin_testing_cleanup(const struct et_state *state, void *state_data) {
- /* do nothing */
-}
-
-static const struct et_state state_begin_testing_struct = {
- .private_size = sizeof(const struct et_test_plan *),
- .init_f = begin_testing_init,
- .tick_f = begin_testing_tick,
- .cleanup_f = begin_testing_cleanup
-};
-
-const struct et_state *et_state_begin_testing = &state_begin_testing_struct;
-
-struct summ_test_plan_private {
- struct et_test_plan *plan;
- size_t selected_test;
-};
-
-#define SUMM_MENU_ROWS 3
-
-static void summ_test_print_menu(struct summ_test_plan_private *priv) {
- const struct et_test *test = priv->plan->tests[priv->selected_test].test;
-
- fputs(TERM_CUR_UP(SUMM_MENU_ROWS), stdout);
- puts(TERM_CLEARLINE "Press A to test again. Press HOME/START to exit.");
- puts(TERM_CLEARLINE "Press +/X to show output for [DL/DR]:");
- printf(TERM_CLEARLINE "%s\n", test->name);
-}
-
-static int summ_test_plan_init(const struct et_state *state, void *state_data, et_state_init_data init_data) {
- struct summ_test_plan_private *priv = state_data;
- struct et_test_plan *ptest_plan = init_data.p;
- size_t passed = 0;
- size_t failed = 0;
- size_t errored = 0;
- size_t skipped = 0;
- size_t unknown = 0;
-
- priv->plan = ptest_plan;
- priv->selected_test = 0;
-
- for (size_t i = 0; i < ptest_plan->num_tests; ++i) {
- switch (TEST_STATUS_GET_TYPE(ptest_plan->tests[i].status)) {
- case TEST_SPASS: ++passed; break;
- case TEST_SFAIL: ++failed; break;
- case TEST_SERROR: ++errored; break;
- case TEST_SSKIPPED: ++skipped; break;
- default: ++unknown; break;
- }
- }
-
- printf("\nTesting complete.\nPASS: %zu, FAIL: %zu, ERROR: %zu, SKIP: %zu, UNK: %zu\n\n", passed, failed, errored, skipped, unknown);
-
- for (int i = 0; i < SUMM_MENU_ROWS; ++i) putchar('\n');
- summ_test_print_menu(priv);
-
- return 0;
-}
-
-static int summ_test_plan_tick(const struct et_state *state, void *state_data, struct et_next_state *next_state) {
- struct summ_test_plan_private *priv = state_data;
-
- u32 wpad_buttons = WPAD_ButtonsDown(0);
- u32 pad_buttons = PAD_ButtonsDown(0);
-
- if (wpad_buttons & WPAD_BUTTON_A || pad_buttons & PAD_BUTTON_A) {
- next_state->state = et_state_setup;
- next_state->init_data = et_init_data_null;
- return 1;
- }
-
- if (wpad_buttons & WPAD_BUTTON_HOME || pad_buttons & PAD_BUTTON_START) {
- puts("Goodbye!");
- exit(0);
- }
-
- if (wpad_buttons & WPAD_BUTTON_LEFT || pad_buttons & PAD_BUTTON_LEFT) {
- if (priv->selected_test > 0) {
- --priv->selected_test;
- } else {
- priv->selected_test = priv->plan->num_tests - 1;
- }
-
- summ_test_print_menu(priv);
- }
-
- if (wpad_buttons & WPAD_BUTTON_RIGHT || pad_buttons & PAD_BUTTON_RIGHT) {
- if (priv->selected_test < priv->plan->num_tests - 1) {
- ++priv->selected_test;
- } else {
- priv->selected_test = 0;
- }
-
- summ_test_print_menu(priv);
- }
-
- if (wpad_buttons & WPAD_BUTTON_1 || pad_buttons & PAD_BUTTON_X) {
- struct et_test_plan_entry *entry = priv->plan->tests + priv->selected_test;
- printf("\nExtended status for %s:\n", entry->test->name);
- if (entry->ext_status) {
- puts(entry->ext_status);
- } else {
- puts("(no status)");
- }
-
- for (int i = 0; i < SUMM_MENU_ROWS + 1; ++i) putchar('\n');
- summ_test_print_menu(priv);
- }
-
- return 0;
-}
-
-static void summ_test_plan_cleanup(const struct et_state *state, void *state_data) {
- struct summ_test_plan_private *priv = state_data;
- struct et_test_plan *ptest_plan = priv->plan;
-
- for (size_t i = 0; i < ptest_plan->num_tests; ++i) {
- et_test_plan_entry_cleanup(ptest_plan->tests + i);
- }
-
- free(ptest_plan->tests);
- free(ptest_plan);
-}
-
-static const struct et_state summ_test_plan_struct = {
- .private_size = sizeof(struct summ_test_plan_private),
- .init_f = summ_test_plan_init,
- .tick_f = summ_test_plan_tick,
- .cleanup_f = summ_test_plan_cleanup
-};
-
-const struct et_state *et_state_summarize_test_plan = &summ_test_plan_struct;
-
-#define COUNT_TESTS(_x) 1
-#define NUM_TESTS FOREACH_TEST(COUNT_TESTS, +)
-static const struct et_test *all_tests[NUM_TESTS + 1];
-static bool tests_array_initialized = false;
-
-const struct et_test *const *et_get_tests(size_t *ntests) {
- size_t idx = 0;
-
- if (ntests) *ntests = NUM_TESTS;
- if (tests_array_initialized) return all_tests;
-
-#define A(_name) all_tests[idx++] = TEST_SYM(_name)
- FOREACH_TEST(A, ;);
-#undef A
-
- all_tests[idx] = NULL;
-
- tests_array_initialized = true;
- return all_tests;
-}
-
-static const char *error_oom = "(failed to allocate error message)";
-static const char *error_bad_fmt = "(bad extended error format)";
-
-void et_test_plan_entry_cleanup(struct et_test_plan_entry *entry) {
- if (entry->ext_status_free) {
- /* okay to cast away const here. we're careful about making sure this pointer is non-NULL iff this pointer
- * was malloc'd */
- entry->ext_status_free((void *)entry->ext_status);
- }
-
- entry->ext_status = NULL;
- entry->ext_status_free = NULL;
-}
-
-void test_plan_entry_set_error(struct et_test_plan_entry *entry, const char *fmt, ...) {
- int res;
- va_list vp;
- char *dest;
- size_t dest_sz;
-
- et_test_plan_entry_cleanup(entry);
-
- va_start(vp, fmt);
- res = vsnprintf(NULL, 0, fmt, vp);
- va_end(vp);
-
- if (res < 0) {
- entry->ext_status = error_bad_fmt;
- entry->ext_status_free = NULL;
- return;
- }
-
- dest_sz = MIN((size_t)res + 1, (size_t)1024);
- dest = malloc(dest_sz);
- dest[0] = '\0';
-
- if (!dest) {
- entry->ext_status = error_oom;
- entry->ext_status_free = NULL;
- return;
- }
-
- va_start(vp, fmt);
- res = vsnprintf(dest, dest_sz, fmt, vp);
- va_end(vp);
-
- dest[dest_sz - 1] = '\0';
-
- assert(res >= 0);
-
- entry->ext_status = dest;
- entry->ext_status_free = free;
-}
-
-void test_plan_entry_set_error_static(struct et_test_plan_entry *entry, const char *str) {
- et_test_plan_entry_cleanup(entry);
- entry->ext_status = str;
- entry->ext_status_free = NULL;
-}
-
-const char *et_test_get_status_mnemonic(et_test_status status) {
- switch (TEST_STATUS_GET_TYPE(status)) {
- case TEST_SPASS: return "PASS";
- case TEST_SFAIL: return "FAIL";
- case TEST_SSKIPPED:
- if (TEST_STATUS_IS_CLEAN(status)) {
- return "SKI!";
- } else {
- return "SKIP";
- }
- case TEST_SERROR:
- switch (TEST_STATUS_GET_ERROR(status)) {
- case TEST_ENONE: return "ERR0";
- case TEST_EABORT: return "ERRA";
- default: return "ERRP";
- }
- default:
- return "UNKS";
- }
-}
-
-et_test_status test_exi_readwrite(struct et_test_plan *plan, void *data, size_t data_sz, et_test_error base) {
- struct et_test_plan_entry *cur = test_current(plan);
- int chan = plan->exi_channel;
- et_test_status status = TEST_PASS;
- s32 exi_res;
-
- if ((exi_res = EXI_Lock(chan, EXI_DEVICE_0, NULL)) <= 0) {
- status = TEST_ERROR(base);
- test_plan_entry_set_error(cur, "failed to lock EXI channel: %" PRId32, exi_res);
- goto fail_lock;
- }
-
- if ((exi_res = EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED32MHZ)) <= 0) {
- status = TEST_ERROR(base + 1);
- test_plan_entry_set_error(cur, "failed to select EXI channel: %" PRId32, exi_res);
- goto fail_select;
- }
-
- if ((exi_res = EXI_Imm(chan, data, data_sz, EXI_READWRITE, NULL)) <= 0) {
- status = TEST_ERROR(base + 2);
- test_plan_entry_set_error(cur, "failed to send EXI data: %" PRId32, exi_res);
- goto fail_data;
- }
-
- if ((exi_res = EXI_Sync(chan)) <= 0) {
- status = TEST_ERROR(base + 3);
- test_plan_entry_set_error(cur, "failed to complete transfer: %" PRId32, exi_res);
- goto fail_data;
- }
-
-fail_data:
- EXI_Deselect(chan);
-
-fail_select:
- EXI_Unlock(chan);
-
-fail_lock:
- return status;
-}
diff --git a/source/test.h b/source/test.h
deleted file mode 100644
index 81a107a..0000000
--- a/source/test.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifndef EXITEST_TEST_H_INCLUDED
-#define EXITEST_TEST_H_INCLUDED
-
-#include <gccore.h>
-#include <assert.h>
-#include "state.h"
-#include "macros.h"
-
-typedef enum {
- TEST_INTERACTIVE = 0x01u,
- TEST_PAUSE_ON_ERROR = 0x02u /* for "essential" tests that should pass */
-} et_test_flags;
-
-struct et_test;
-struct et_test_plan;
-
-struct et_test {
- struct et_state parent;
- const char *name;
- et_test_flags flags;
-
- et_state_init_f *test_init_f;
- et_state_cleanup_f *test_cleanup_f;
-};
-
-/* 0000eeee eeeeeeee eeeeeeee x00000ss */
-/* e = error code bits,
- * x = 1 if this test is still in the "clean" (not executed) state
- * ss = status type (pass/fail/etc.) */
-typedef u32 et_test_status;
-
-typedef enum {
- TEST_ENONE = (u32)0,
-
- /* test was aborted (i.e., requested to go to next test without setting a status code) */
- TEST_EABORT,
-
- /* minimum private test error (define test-private error codes as TEST_EPRIV_BASE+n) */
- TEST_EPRIV_BASE = 32,
-
- /* largest error code allowed */
- TEST_EMAX = ((u32)1 << 20) - 1
-} et_test_error;
-
-typedef enum {
- TEST_SSKIPPED = 0u,
- TEST_SERROR,
- TEST_SFAIL,
- TEST_SPASS,
-
- TEST_SMAX = ((u32)1 << 2) - 1
-} et_test_status_type;
-
-#define TEST_STATUS_GET_ERROR(_status) (et_test_error)(((u32)(_status) >> 8) & TEST_EMAX)
-#define TEST_STATUS_GET_TYPE(_status) (et_test_status_type)((u32)(_status) & TEST_SMAX)
-#define TEST_STATUS_IS_CLEAN(_status) (!!((u32)(_status) & 0x80u))
-
-#define TEST_MAKE_STATUS(_type, _error, _clean) (et_test_status) \
- (((u32)(_type) & TEST_SMAX) | \
- (((u32)(_clean) & 1) << 7) | \
- (((u32)(_error) & TEST_EMAX) << 8))
-
-#define TEST_SKIPPED TEST_MAKE_STATUS(TEST_SSKIPPED, TEST_ENONE, 0)
-#define TEST_FAIL TEST_MAKE_STATUS(TEST_SFAIL, TEST_ENONE, 0)
-#define TEST_PASS TEST_MAKE_STATUS(TEST_SPASS, TEST_ENONE, 0)
-#define TEST_ERROR(_e) TEST_MAKE_STATUS(TEST_SERROR, _e, 0)
-
-#define TEST_PRIMORDIAL TEST_MAKE_STATUS(TEST_SSKIPPED, TEST_ENONE, 1)
-
-/* Expected setup date: pointer to test plan */
-extern const struct et_state *et_state_begin_testing;
-extern const struct et_state *et_state_summarize_test_plan;
-
-const char *et_test_get_status_mnemonic(et_test_status status);
-
-struct et_test_plan_entry {
- const struct et_test *test;
- et_test_status status;
- const char *ext_status;
- void (*ext_status_free)(void *);
-};
-
-/* a properly initialized test plan will have all the tests' statuses set to TEST_PRIMORDIAL */
-struct et_test_plan {
- int exi_channel;
-
- /* this state will be set after testing is complete.
- * NOTE: next_state_init should somehow point to this test plan,
- * since it's probably dynamically allocated and will be leaked if not
- * freed. */
- const struct et_state *next_state;
- et_state_init_data next_state_init;
-
- size_t num_tests;
- size_t current_test;
- struct et_test_plan_entry *tests;
-};
-
-void et_test_plan_entry_cleanup(struct et_test_plan_entry *entry);
-
-#define FOREACH_TEST(O, _sep) \
- O(check_id) _sep \
- O(bad_commands) _sep \
- O(flash_led)
-
-#define TEST_SYM(_name) PASTE(et_test_, _name)
-#define DECL_TEST(_name) extern const struct et_test *const TEST_SYM(_name)
-
-FOREACH_TEST(DECL_TEST, ;);
-#undef DECL_TEST
-
-const struct et_test *const *et_get_tests(size_t *ntests);
-
-#if defined(ET_TEST_IMPL) || defined(TEST_INTERNAL)
-#define ET__ALLOW_TEST_IMPL_INC
-#include "test-impl.inc.h"
-#else
-#undef FOREACH_TEST
-#undef TEST_SYM
-#endif
-
-#endif /* include guard */
diff --git a/source/tests/basic.c b/source/tests/basic.c
deleted file mode 100644
index 4f34ba4..0000000
--- a/source/tests/basic.c
+++ /dev/null
@@ -1,79 +0,0 @@
-#define ET_TEST_IMPL
-#include "../test.h"
-#include <inttypes.h>
-#include <stdio.h>
-
-#define TEST_ITERATIONS 16
-
-struct test_with_iterations {
- struct et_test_state_private_base base;
- int iteration;
-};
-
-static int init_test_with_iterations(const struct et_state *state, void *data, et_state_init_data init_data) {
- struct test_with_iterations *priv = data;
- priv->iteration = 0;
- return 0;
-}
-
-static int check_id_tick(const struct et_state *state, void *data, struct et_next_state *next_state) {
- struct test_with_iterations *priv = data;
- struct et_test_plan *test_plan = priv->base.plan;
- struct et_test_plan_entry *cur = test_current(test_plan);
- et_test_status status = TEST_PASS;
- u16 command = 0x9000;
-
- if ((status = test_exi_readwrite(test_plan, &command, sizeof(command), TEST_EPRIV_BASE)) != TEST_PASS) {
- cur->status = status;
- return test_next(test_plan, next_state);
- }
-
- if (command != 0x0470) {
- test_plan_entry_set_error(cur, "bad identifier from gecko: expected 0x0470, got 0x%04" PRIx16, command);
- status = TEST_FAIL;
- }
-
- cur->status = status;
-
- if (status != TEST_PASS || ++priv->iteration >= TEST_ITERATIONS) {
- return test_next(test_plan, next_state);
- }
-
- return 0;
-}
-
-TEST_DEF(check_id, "Identify Gecko (0x09)", TEST_PAUSE_ON_ERROR, init_test_with_iterations, check_id_tick, NULL, struct test_with_iterations);
-
-static int bad_commands_tick(const struct et_state *state, void *data, struct et_next_state *next_state) {
- struct test_with_iterations *priv = data;
- struct et_test_plan *test_plan = priv->base.plan;
- struct et_test_plan_entry *cur = test_current(test_plan);
- et_test_status status = TEST_PASS;
-
- static const u16 bad_commands[] = { 0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0xe000, 0xf000 };
-
- for (int i = 0; i < ARRLEN(bad_commands); ++i) {
- u16 orig_cmd = bad_commands[i];
- u16 cmd = orig_cmd;
- if ((status = test_exi_readwrite(test_plan, &cmd, sizeof(cmd), TEST_EPRIV_BASE)) != TEST_PASS) {
- goto test_fail;
- }
-
- if (cmd != 0x0000) {
- test_plan_entry_set_error(cur, "got bogus response from invalid command 0x%04" PRIx16 ": 0x%04" PRIx16, orig_cmd, cmd);
- status = TEST_FAIL;
- break;
- }
- }
-
-test_fail:
- cur->status = status;
-
- if (status != TEST_PASS || ++priv->iteration >= TEST_ITERATIONS) {
- return test_next(test_plan, next_state);
- }
-
- return 0;
-}
-
-TEST_DEF(bad_commands, "Bad commands", 0, init_test_with_iterations, bad_commands_tick, NULL, struct test_with_iterations);
diff --git a/source/tests/led.c b/source/tests/led.c
deleted file mode 100644
index 82913ae..0000000
--- a/source/tests/led.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#define ET_TEST_IMPL
-#include "../test.h"
-#include <inttypes.h>
-
-static int flash_led_tick(const struct et_state *state, void *data, struct et_next_state *next_state) {
- struct et_test_state_private_base *priv = data;
- struct et_test_plan *plan = priv->plan;
- struct et_test_plan_entry *cur = test_current(plan);
- et_test_status status = TEST_PASS;
-
- for (int i = 0; i < 1024; ++i) {
- u16 cmd_orig, cmd;
-
- if (i & 1) {
- /* LED off */
- cmd_orig = 0x7000;
- } else {
- /* LED on */
- cmd_orig = 0x8000;
- }
-
- cmd = cmd_orig;
- if ((status = test_exi_readwrite(plan, &cmd, sizeof(cmd), TEST_EPRIV_BASE)) != TEST_PASS) {
- break;
- }
-
- if (cmd != 0x0000) {
- status = TEST_FAIL;
- test_plan_entry_set_error(cur, "spurious response to 0x%04" PRIx16 ": 0x%04" PRIx16 " (should be 0x0000)", cmd_orig, cmd);
- break;
- }
- }
-
- cur->status = status;
- return test_next(plan, next_state);
-}
-
-TEST_DEF(flash_led, "Flash LED", 0, NULL, flash_led_tick, NULL, struct et_test_state_private_base);