Extensive tool with subcommands to trigger the various P3IO commands and run the P3IO + EXTIO DDR hardware combo with a hardware test menu.
406 lines
12 KiB
C
406 lines
12 KiB
C
#define LOG_MODULE "mode-test"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "extiodrv/extio.h"
|
|
|
|
#include "p3io/ddr.h"
|
|
#include "p3iodrv/ddr.h"
|
|
#include "p3iodrv/device.h"
|
|
|
|
#include "util/log.h"
|
|
|
|
#include "mode-test.h"
|
|
|
|
struct mode_test_output_state {
|
|
struct p3io_ddr_output output;
|
|
struct extiodrv_extio_pad_lights pad_lights[EXTIO_PAD_LIGHT_MAX_PLAYERS];
|
|
bool neons;
|
|
};
|
|
|
|
struct mode_test_input_state {
|
|
struct p3io_ddr_jamma jamma[4];
|
|
};
|
|
|
|
static bool _check_input_state_change(
|
|
const struct mode_test_input_state *cur_state,
|
|
const struct mode_test_input_state *prev_state)
|
|
{
|
|
return !memcmp(cur_state, prev_state, sizeof(struct mode_test_input_state));
|
|
}
|
|
|
|
static void _input_state_swap(
|
|
struct mode_test_input_state **cur_state,
|
|
struct mode_test_input_state **prev_state)
|
|
{
|
|
struct mode_test_input_state *tmp;
|
|
|
|
tmp = *cur_state;
|
|
*cur_state = *prev_state;
|
|
*prev_state = tmp;
|
|
}
|
|
|
|
static bool _update_io_frame(
|
|
HANDLE handle_p3io,
|
|
HANDLE handle_extio,
|
|
bool polling_mode,
|
|
struct mode_test_input_state *input,
|
|
const struct mode_test_output_state *output)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = p3iodrv_ddr_set_outputs(handle_p3io, &output->output);
|
|
|
|
if (FAILED(hr)) {
|
|
log_warning("Setting outputs failed: %lX", hr);
|
|
return false;
|
|
}
|
|
|
|
if (polling_mode) {
|
|
hr = extiodrv_extio_transfer(
|
|
handle_extio,
|
|
EXTIODRV_EXTIO_SENSOR_READ_MODE_ALL,
|
|
output->pad_lights,
|
|
output->neons);
|
|
|
|
if (FAILED(hr)) {
|
|
log_warning("extio transfer failed: %lX", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = p3iodrv_ddr_get_jamma(handle_p3io, &input->jamma[0]);
|
|
|
|
if (FAILED(hr)) {
|
|
log_warning("Reading jamma failed: %lX", hr);
|
|
return false;
|
|
}
|
|
} else {
|
|
for (uint8_t i = 0; i < 4; i++) {
|
|
hr = extiodrv_extio_transfer(
|
|
handle_extio, i + 1, output->pad_lights, output->neons);
|
|
|
|
if (FAILED(hr)) {
|
|
log_warning("extio transfer failed: %lX", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = p3iodrv_ddr_get_jamma(handle_p3io, &input->jamma[i]);
|
|
|
|
if (FAILED(hr)) {
|
|
log_warning("Reading jamma failed: %lX", hr);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void _set_outputs_on_inputs(
|
|
const struct mode_test_input_state *input,
|
|
struct mode_test_output_state *output)
|
|
{
|
|
memset(&output->pad_lights, 0, sizeof(output->pad_lights));
|
|
|
|
output->output.cabinet.p1_menu_buttons = 0;
|
|
output->output.cabinet.p2_menu_buttons = 0;
|
|
|
|
for (uint8_t i = 0; i < 4; i++) {
|
|
output->pad_lights[0].up |= input->jamma[i].p1.pad_up ? 1 : 0;
|
|
output->pad_lights[0].down |= input->jamma[i].p1.pad_down ? 1 : 0;
|
|
output->pad_lights[0].left |= input->jamma[i].p1.pad_left ? 1 : 0;
|
|
output->pad_lights[0].right |= input->jamma[i].p1.pad_right ? 1 : 0;
|
|
|
|
output->pad_lights[1].up |= input->jamma[i].p2.pad_up ? 1 : 0;
|
|
output->pad_lights[1].down |= input->jamma[i].p2.pad_down ? 1 : 0;
|
|
output->pad_lights[1].left |= input->jamma[i].p2.pad_left ? 1 : 0;
|
|
output->pad_lights[1].right |= input->jamma[i].p2.pad_right ? 1 : 0;
|
|
|
|
output->output.cabinet.p1_menu_buttons |=
|
|
(input->jamma[i].p1.menu_left || input->jamma[i].p1.menu_right ||
|
|
input->jamma[i].p1.menu_start) ?
|
|
1 :
|
|
0;
|
|
output->output.cabinet.p2_menu_buttons |=
|
|
(input->jamma[i].p2.menu_left || input->jamma[i].p2.menu_right ||
|
|
input->jamma[i].p2.menu_start) ?
|
|
1 :
|
|
0;
|
|
}
|
|
}
|
|
|
|
static void _render_main(
|
|
uint8_t cnt, bool polling_mode, const struct mode_test_input_state *state)
|
|
{
|
|
printf("Counter: %d\n", cnt);
|
|
printf("Polling mode: %d\n", polling_mode);
|
|
printf("Player 1 Player 2\n");
|
|
printf("\n");
|
|
printf("Pad\n");
|
|
|
|
if (polling_mode) {
|
|
printf(
|
|
"Up: %d Up: %d\n",
|
|
state->jamma[0].p1.pad_up,
|
|
state->jamma[0].p2.pad_up);
|
|
printf(
|
|
"Down: %d Down: %d\n",
|
|
state->jamma[0].p1.pad_down,
|
|
state->jamma[0].p2.pad_down);
|
|
printf(
|
|
"Left: %d Left: %d\n",
|
|
state->jamma[0].p1.pad_left,
|
|
state->jamma[0].p2.pad_left);
|
|
printf(
|
|
"Right: %d Right: %d\n",
|
|
state->jamma[0].p1.pad_right,
|
|
state->jamma[0].p2.pad_right);
|
|
} else {
|
|
printf(
|
|
"Up: %c%c%c%c Up: %c%c%c%c\n",
|
|
state->jamma[0].p1.pad_up ? 'U' : '_',
|
|
state->jamma[1].p1.pad_up ? 'D' : '_',
|
|
state->jamma[2].p1.pad_up ? 'L' : '_',
|
|
state->jamma[3].p1.pad_up ? 'R' : '_',
|
|
state->jamma[0].p2.pad_up ? 'U' : '_',
|
|
state->jamma[1].p2.pad_up ? 'D' : '_',
|
|
state->jamma[2].p2.pad_up ? 'L' : '_',
|
|
state->jamma[3].p2.pad_up) ?
|
|
'R' :
|
|
'_';
|
|
printf(
|
|
"Down: %c%c%c%c Down: %c%c%c%c\n",
|
|
state->jamma[0].p1.pad_down ? 'U' : '_',
|
|
state->jamma[1].p1.pad_down ? 'D' : '_',
|
|
state->jamma[2].p1.pad_down ? 'L' : '_',
|
|
state->jamma[3].p1.pad_down ? 'R' : '_',
|
|
state->jamma[0].p2.pad_down ? 'U' : '_',
|
|
state->jamma[1].p2.pad_down ? 'D' : '_',
|
|
state->jamma[2].p2.pad_down ? 'L' : '_',
|
|
state->jamma[3].p2.pad_down ? 'R' : '_');
|
|
printf(
|
|
"Left: %c%c%c%c Left: %c%c%c%c\n",
|
|
state->jamma[0].p1.pad_left ? 'U' : '_',
|
|
state->jamma[1].p1.pad_left ? 'D' : '_',
|
|
state->jamma[2].p1.pad_left ? 'L' : '_',
|
|
state->jamma[3].p1.pad_left ? 'R' : '_',
|
|
state->jamma[0].p2.pad_left ? 'U' : '_',
|
|
state->jamma[1].p2.pad_left ? 'D' : '_',
|
|
state->jamma[2].p2.pad_left ? 'L' : '_',
|
|
state->jamma[3].p2.pad_left ? 'R' : '_');
|
|
printf(
|
|
"Right: %c%c%c%c Right: %c%c%c%c\n",
|
|
state->jamma[0].p1.pad_right ? 'U' : '_',
|
|
state->jamma[1].p1.pad_right ? 'D' : '_',
|
|
state->jamma[2].p1.pad_right ? 'L' : '_',
|
|
state->jamma[3].p1.pad_right ? 'R' : '_',
|
|
state->jamma[0].p2.pad_right ? 'U' : '_',
|
|
state->jamma[1].p2.pad_right ? 'D' : '_',
|
|
state->jamma[2].p2.pad_right ? 'L' : '_',
|
|
state->jamma[3].p2.pad_right ? 'R' : '_');
|
|
}
|
|
|
|
printf("\n");
|
|
printf("Menu\n");
|
|
printf(
|
|
"Start: %d Start: %d\n",
|
|
state->jamma[0].p1.menu_start,
|
|
state->jamma[0].p2.menu_start);
|
|
printf(
|
|
"Up: %d Up: %d\n",
|
|
state->jamma[0].operator.p1_menu_up,
|
|
state->jamma[0].operator.p2_menu_up);
|
|
printf(
|
|
"Down: %d Down: %d\n",
|
|
state->jamma[0].operator.p1_menu_down,
|
|
state->jamma[0].operator.p2_menu_down);
|
|
printf(
|
|
"Left: %d Left: %d\n",
|
|
state->jamma[0].p1.menu_left,
|
|
state->jamma[0].p2.menu_left);
|
|
printf(
|
|
"Right: %d Right: %d\n",
|
|
state->jamma[0].p1.menu_right,
|
|
state->jamma[0].p2.menu_right);
|
|
printf("\n");
|
|
printf("Operator\n");
|
|
printf(
|
|
"Test: %d Service: %d Coin: %d\n",
|
|
state->jamma[0].operator.test,
|
|
state->jamma[0].operator.service,
|
|
state->jamma[0].operator.coin);
|
|
}
|
|
|
|
static void
|
|
_render_menu(bool *continue_loop, struct mode_test_output_state *output)
|
|
{
|
|
printf(
|
|
"Menu options:\n"
|
|
" 0: Exit menu and continue loop\n"
|
|
" 1: Exit\n"
|
|
" 2: Set neon state\n"
|
|
" 3: Top lamp state\n"
|
|
" 4: Set all lights on\n"
|
|
" 5: Set all lights off\n"
|
|
"Waiting for input: ");
|
|
|
|
char c = getchar();
|
|
|
|
// Keyboard input debounce
|
|
Sleep(10);
|
|
|
|
switch (c) {
|
|
case '1': {
|
|
*continue_loop = false;
|
|
break;
|
|
}
|
|
|
|
case '2': {
|
|
int state;
|
|
int n;
|
|
|
|
printf("Enter neon state (0/1): ");
|
|
|
|
n = scanf("%d", &state);
|
|
|
|
if (n > 0) {
|
|
output->neons = state > 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '3': {
|
|
char buf[4];
|
|
int n;
|
|
|
|
printf("Enter top lamp state, chain of 0/1s: ");
|
|
|
|
n = scanf("%8s", buf);
|
|
|
|
if (n > 0) {
|
|
output->output.cabinet.top_p1_upper = buf[0] == '1';
|
|
output->output.cabinet.top_p1_lower = buf[1] == '1';
|
|
output->output.cabinet.top_p2_upper = buf[2] == '1';
|
|
output->output.cabinet.top_p2_lower = buf[3] == '1';
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '4': {
|
|
output->output.cabinet.top_p1_upper = 1;
|
|
output->output.cabinet.top_p1_lower = 1;
|
|
output->output.cabinet.top_p2_upper = 1;
|
|
output->output.cabinet.top_p2_lower = 1;
|
|
|
|
output->output.cabinet.p1_menu_buttons = 1;
|
|
output->output.cabinet.p2_menu_buttons = 1;
|
|
|
|
output->neons = true;
|
|
|
|
output->pad_lights[0].up = true;
|
|
output->pad_lights[0].down = true;
|
|
output->pad_lights[0].left = true;
|
|
output->pad_lights[0].right = true;
|
|
|
|
output->pad_lights[1].up = true;
|
|
output->pad_lights[1].down = true;
|
|
output->pad_lights[1].left = true;
|
|
output->pad_lights[1].right = true;
|
|
|
|
break;
|
|
}
|
|
|
|
case '5': {
|
|
output->output.cabinet.top_p1_upper = 0;
|
|
output->output.cabinet.top_p1_lower = 0;
|
|
output->output.cabinet.top_p2_upper = 0;
|
|
output->output.cabinet.top_p2_lower = 0;
|
|
|
|
output->output.cabinet.p1_menu_buttons = 0;
|
|
output->output.cabinet.p2_menu_buttons = 0;
|
|
|
|
output->neons = false;
|
|
|
|
output->pad_lights[0].up = false;
|
|
output->pad_lights[0].down = false;
|
|
output->pad_lights[0].left = false;
|
|
output->pad_lights[0].right = false;
|
|
|
|
output->pad_lights[1].up = false;
|
|
output->pad_lights[1].down = false;
|
|
output->pad_lights[1].left = false;
|
|
output->pad_lights[1].right = false;
|
|
|
|
break;
|
|
}
|
|
|
|
case '0':
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool mode_test_proc(HANDLE handle_p3io, HANDLE handle_extio)
|
|
{
|
|
struct mode_test_input_state state[2];
|
|
struct mode_test_input_state *cur_input_state;
|
|
struct mode_test_input_state *prev_input_state;
|
|
struct mode_test_output_state output_state;
|
|
|
|
bool polling_mode;
|
|
bool loop;
|
|
uint8_t cnt;
|
|
|
|
memset(&state, 0, sizeof(state));
|
|
cur_input_state = &state[0];
|
|
prev_input_state = &state[1];
|
|
memset(&output_state, 0, sizeof(output_state));
|
|
|
|
polling_mode = true;
|
|
loop = true;
|
|
cnt = 0;
|
|
|
|
fprintf(stderr, ">>> Press enter to start running test mode <<<\n");
|
|
|
|
if (getchar() != '\n') {
|
|
return true;
|
|
}
|
|
|
|
while (loop) {
|
|
if ((GetAsyncKeyState(VK_ESCAPE) & 0x8000) != 0) {
|
|
system("cls");
|
|
|
|
_render_menu(&loop, &output_state);
|
|
} else {
|
|
_input_state_swap(&cur_input_state, &prev_input_state);
|
|
|
|
memset(cur_input_state, 0, sizeof(struct mode_test_input_state));
|
|
|
|
if (!_update_io_frame(
|
|
handle_p3io,
|
|
handle_extio,
|
|
polling_mode,
|
|
cur_input_state,
|
|
&output_state)) {
|
|
return false;
|
|
}
|
|
|
|
_set_outputs_on_inputs(cur_input_state, &output_state);
|
|
|
|
if (_check_input_state_change(cur_input_state, prev_input_state)) {
|
|
system("cls");
|
|
|
|
_render_main(cnt, polling_mode, cur_input_state);
|
|
}
|
|
}
|
|
|
|
/* avoid CPU banging */
|
|
Sleep(1);
|
|
++cnt;
|
|
}
|
|
|
|
return true;
|
|
} |