summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/macros.h2
-rw-r--r--source/states/menu.c2
-rw-r--r--source/test-impl.inc.h4
-rw-r--r--source/test.c107
-rw-r--r--source/test.h4
-rw-r--r--source/tests/basic.c97
-rw-r--r--source/tests/led.c38
7 files changed, 207 insertions, 47 deletions
diff --git a/source/macros.h b/source/macros.h
index d2231ff..9a9db83 100644
--- a/source/macros.h
+++ b/source/macros.h
@@ -9,4 +9,6 @@
#define COMMA ,
+#define ARRLEN(_a) sizeof(_a) / sizeof(*(_a))
+
#endif /* include guard */
diff --git a/source/states/menu.c b/source/states/menu.c
index 15e0b3c..ea5134b 100644
--- a/source/states/menu.c
+++ b/source/states/menu.c
@@ -59,6 +59,8 @@ static int begin_testing(u32 menu_state, struct et_next_state *next_state) {
next_state->state = et_state_begin_testing;
next_state->init_data.p = plan;
+ putchar('\n');
+
return 1;
}
diff --git a/source/test-impl.inc.h b/source/test-impl.inc.h
index 2ecb7a6..8e1559f 100644
--- a/source/test-impl.inc.h
+++ b/source/test-impl.inc.h
@@ -24,6 +24,8 @@ 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) \
{ \
@@ -33,6 +35,8 @@ void test_plan_entry_set_error_static(struct et_test_plan_entry *entry, const ch
.cleanup_f = test_state_cleanup, \
.private_size = sizeof(_private_type), \
}, \
+ .test_init_f = _init_f, \
+ .test_cleanup_f = _cleanup_f, \
.name = _namestr, \
.flags = _flags \
}
diff --git a/source/test.c b/source/test.c
index 2013e04..c59deaf 100644
--- a/source/test.c
+++ b/source/test.c
@@ -4,9 +4,11 @@
#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;
@@ -188,14 +190,34 @@ static const struct et_state state_begin_testing_struct = {
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 et_test_plan *ptest_plan = (*(struct et_test_plan **)state_data = init_data.p);
+ 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;
@@ -208,12 +230,15 @@ static int summ_test_plan_init(const struct et_state *state, void *state_data, e
printf("\nTesting complete.\nPASS: %zu, FAIL: %zu, ERROR: %zu, SKIP: %zu, UNK: %zu\n\n", passed, failed, errored, skipped, unknown);
- puts("Press A to test again. Press HOME/START to exit.");
+ 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);
@@ -228,11 +253,45 @@ static int summ_test_plan_tick(const struct et_state *state, void *state_data, s
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 et_test_plan *ptest_plan = *(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);
@@ -243,7 +302,7 @@ static void summ_test_plan_cleanup(const struct et_state *state, void *state_dat
}
static const struct et_state summ_test_plan_struct = {
- .private_size = sizeof(struct et_test_plan *),
+ .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
@@ -352,3 +411,43 @@ const char *et_test_get_status_mnemonic(et_test_status status) {
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
index d45c2fe..81a107a 100644
--- a/source/test.h
+++ b/source/test.h
@@ -99,7 +99,9 @@ struct et_test_plan {
void et_test_plan_entry_cleanup(struct et_test_plan_entry *entry);
#define FOREACH_TEST(O, _sep) \
- O(check_id)
+ 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)
diff --git a/source/tests/basic.c b/source/tests/basic.c
index 8645b19..4f34ba4 100644
--- a/source/tests/basic.c
+++ b/source/tests/basic.c
@@ -1,66 +1,79 @@
#define ET_TEST_IMPL
#include "../test.h"
#include <inttypes.h>
+#include <stdio.h>
-et_test_status test_exi_readwrite(struct et_test_plan *plan, void *data, size_t data_sz, et_test_error base, struct et_next_state *next_state) {
- struct et_test_plan_entry *cur = test_current(plan);
- int chan = plan->exi_channel;
- et_test_status status = TEST_PASS;
- s32 exi_res;
+#define TEST_ITERATIONS 16
- 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;
- }
+struct test_with_iterations {
+ struct et_test_state_private_base base;
+ int iteration;
+};
- 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;
- }
+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;
+}
- 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;
+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 ((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;
+ if (command != 0x0470) {
+ test_plan_entry_set_error(cur, "bad identifier from gecko: expected 0x0470, got 0x%04" PRIx16, command);
+ status = TEST_FAIL;
}
-fail_data:
- EXI_Deselect(chan);
+ cur->status = status;
-fail_select:
- EXI_Unlock(chan);
+ if (status != TEST_PASS || ++priv->iteration >= TEST_ITERATIONS) {
+ return test_next(test_plan, next_state);
+ }
-fail_lock:
- cur->status = status;
- return status;
+ return 0;
}
-static int check_id_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 *test_plan = priv->plan;
+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;
- u16 command = 0x9000;
- if ((status = test_exi_readwrite(test_plan, &command, sizeof(command), TEST_EPRIV_BASE, next_state)) != TEST_PASS) {
- return test_next(test_plan, next_state);
+ 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;
+ }
}
- if (command != 0x0470) {
- test_plan_entry_set_error(cur, "bad identifier from gecko: expected 0x0470, got 0x%04" PRIx16, command);
- status = TEST_FAIL;
+test_fail:
+ cur->status = status;
+
+ if (status != TEST_PASS || ++priv->iteration >= TEST_ITERATIONS) {
+ return test_next(test_plan, next_state);
}
- cur->status = TEST_PASS;
- return test_next(test_plan, next_state);
+ return 0;
}
-TEST_DEF(check_id, "Identify Gecko (0x09)", TEST_PAUSE_ON_ERROR, NULL, check_id_tick, NULL, struct et_test_state_private_base);
+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
new file mode 100644
index 0000000..82913ae
--- /dev/null
+++ b/source/tests/led.c
@@ -0,0 +1,38 @@
+#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);