From 7838db26e3f3a8b7fb84a8d5c68797e99254d086 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 4 Feb 2024 14:12:52 +0900 Subject: [PATCH 01/25] Update --- include/jiangtun.h | 44 ++++++ src/internal.h | 45 ++++++ src/jiangtun.cpp | 115 +++++++++++++++ src/main.cpp | 347 ++++++++------------------------------------ src/orca.h | 23 --- src/orca_protocol.c | 126 ---------------- 6 files changed, 268 insertions(+), 432 deletions(-) create mode 100644 include/jiangtun.h create mode 100644 src/internal.h create mode 100644 src/jiangtun.cpp delete mode 100644 src/orca.h delete mode 100644 src/orca_protocol.c diff --git a/include/jiangtun.h b/include/jiangtun.h new file mode 100644 index 0000000..9e7ee5f --- /dev/null +++ b/include/jiangtun.h @@ -0,0 +1,44 @@ +#ifndef JIANGTUN_H_ +#define JIANGTUN_H_ + +#include + +#include "pico/mutex.h" + +#include "Bluewhale.h" + +#include "nthaka.h" + +typedef struct jiangtun_t +{ + Servo *_servo; + size_t *_idx_using_servo; + size_t _idx_using_servo_size; + mutex_t *_mtx; + + nthaka_button_state_t _reset_state; +} jiangtun_t; + +inline bool jiangtun_init(jiangtun_t *j, Servo *servo, size_t idx_using_servo[], size_t size, mutex_t *mtx) +{ + if (j == NULL || + servo == NULL || + idx_using_servo == NULL || + mtx == NULL) + { + return false; + } + + j->_servo = servo; + j->_idx_using_servo = idx_using_servo; + j->_idx_using_servo_size = size; + j->_mtx = mtx; + + j->_reset_state = NTHAKA_BUTTON_RELEASED; + + return true; +} + +void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, Gamecube_Data_t *gc); + +#endif // JIANGTUN_H_ \ No newline at end of file diff --git a/src/internal.h b/src/internal.h new file mode 100644 index 0000000..c092bd4 --- /dev/null +++ b/src/internal.h @@ -0,0 +1,45 @@ +#ifndef JIANGTUN_INTERNAL_H_ +#define JIANGTUN_INTERNAL_H_ + +#include "pico/mutex.h" + +#include "Bluewhale.h" + +void gc_console_data_init(CGamecubeConsole *console, Gamecube_Data_t *gc, mutex_t *mtx) +{ + if (console == NULL || + gc == NULL || + mtx == NULL) + { + return; + } + + mutex_enter_blocking(mtx); + gc->report.a = 0; + gc->report.b = 0; + gc->report.x = 0; + gc->report.y = 0; + gc->report.start = 0; + gc->report.dleft = 0; + gc->report.dright = 0; + gc->report.ddown = 0; + gc->report.dup = 0; + gc->report.z = 0; + gc->report.r = 0; + gc->report.l = 0; + gc->report.xAxis = 128; + gc->report.yAxis = 128; + gc->report.cxAxis = 128; + gc->report.cyAxis = 128; + gc->report.left = 0; + gc->report.right = 0; + + // Magic spell to make the controller be recognized by the Gamecube + gc->report.start = 1; + console->write(*gc); + gc->report.start = 0; + console->write(*gc); + mutex_exit(mtx); +} + +#endif // JIANGTUN_INTERNAL_H_ \ No newline at end of file diff --git a/src/jiangtun.cpp b/src/jiangtun.cpp new file mode 100644 index 0000000..48b44d3 --- /dev/null +++ b/src/jiangtun.cpp @@ -0,0 +1,115 @@ +#include "jiangtun.h" + +void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, Gamecube_Data_t *gc) +{ + if (j == NULL) + { + return; + } + + mutex_enter_blocking(j->_mtx); + + gc->report.y = (uint8_t)s->y; + gc->report.b = (uint8_t)s->b; + gc->report.a = (uint8_t)s->a; + gc->report.x = (uint8_t)s->x; + gc->report.l = (uint8_t)s->l; + gc->report.r = (uint8_t)s->r; + gc->report.z = (uint8_t)s->zr; + gc->report.start = (uint8_t)s->plus; + + bool servo_up = false; + if (j->_reset_state != s->home) + { + j->_servo->write(s->home == NTHAKA_BUTTON_PRESSED ? 65 : 90); + j->_reset_state = s->home; + + // For listed idx, use servo with blocking + for (size_t i = 0; i < j->_idx_using_servo_size; i++) + { + if (j->_idx_using_servo[i] == idx_from) + { + servo_up = true; + break; + } + } + } + + switch (s->hat) + { + case NTHAKA_HAT_UP: + gc->report.dup = 1; + gc->report.dright = 0; + gc->report.ddown = 0; + gc->report.dleft = 0; + break; + case NTHAKA_HAT_UPRIGHT: + gc->report.dup = 1; + gc->report.dright = 1; + gc->report.ddown = 0; + gc->report.dleft = 0; + break; + case NTHAKA_HAT_RIGHT: + gc->report.dup = 0; + gc->report.dright = 1; + gc->report.ddown = 0; + gc->report.dleft = 0; + break; + case NTHAKA_HAT_DOWNRIGHT: + gc->report.dup = 0; + gc->report.dright = 1; + gc->report.ddown = 1; + gc->report.dleft = 0; + break; + case NTHAKA_HAT_DOWN: + gc->report.dup = 0; + gc->report.dright = 0; + gc->report.ddown = 1; + gc->report.dleft = 0; + break; + case NTHAKA_HAT_DOWNLEFT: + gc->report.dup = 0; + gc->report.dright = 0; + gc->report.ddown = 1; + gc->report.dleft = 1; + break; + case NTHAKA_HAT_LEFT: + gc->report.dup = 0; + gc->report.dright = 0; + gc->report.ddown = 0; + gc->report.dleft = 1; + break; + case NTHAKA_HAT_UPLEFT: + gc->report.dup = 1; + gc->report.dright = 0; + gc->report.ddown = 0; + gc->report.dleft = 1; + break; + case NTHAKA_HAT_NEUTRAL: + default: + gc->report.dup = 0; + gc->report.dright = 0; + gc->report.ddown = 0; + gc->report.dleft = 0; + break; + } + + // There are a few games that do not handle yAxis=0 and cyAxis=0 correctly. + gc->report.xAxis = s->l_stick.x; + uint8_t y_axis = 0xFF - s->l_stick.y; + gc->report.yAxis = y_axis == 0 ? 1 : y_axis; + + gc->report.cxAxis = s->r_stick.x; + uint8_t cy_axis = 0xFF - s->r_stick.y; + gc->report.cyAxis = cy_axis == 0 ? 1 : cy_axis; + + mutex_exit(j->_mtx); + + if (servo_up) + { + delay(500); + j->_servo->write(90); + delay(500); + j->_reset_state = NTHAKA_BUTTON_RELEASED; + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ad978c2..c26f727 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,327 +1,108 @@ #include #include -#include "pico/stdlib.h" #include "pico/mutex.h" #include "hardware/timer.h" #include "Bluewhale.h" -#include "nxamf.h" -#include "nxamf/nxmc2.h" -#include "nxamf/pokecon.h" +#include "nthaka.h" +#include "nthaka/nxmc2.h" +#include "nthaka/orca.h" +#include "nthaka/pokecon.h" -#include "orca.h" +#include "jiangtun.h" +#include "internal.h" -static const int SERIAL_INACTIVE_TIMEOUT = 100; -static int inactive_count = 0; -static mutex_t serial1_mutex; +static jiangtun_t j; -static CGamecubeConsole console(5); static Servo servo; static const int PIN_SERVO = 6; -static Gamecube_Data_t d = defaultGamecubeData; -static mutex_t d_mutex; - -static Nxmc2Protocol *nxmc2; -static PokeConProtocol *pokecon; -static OrcaProtocol *orca; -static const size_t ORCA_INDEX = 2; -static NxamfBytesProtocolInterface *protocols[3]; -static NxamfProtocolMultiplexer *mux; -static NxamfBytesBuffer *buffer; - -static NxamfButtonState reset_state = NXAMF_BUTTON_STATE_RELEASED; - -static const char *_button_to_string(NxamfButtonState state) -{ - switch (state) - { - case NXAMF_BUTTON_STATE_RELEASED: - return "RELEASED"; - case NXAMF_BUTTON_STATE_PRESSED: - return "PRESSED"; - default: - return "[Unknown]"; - } -} -static const char *_hat_to_string(NxamfHatState state) -{ - switch (state) - { - case NXAMF_HAT_STATE_UP: - return "UP"; - case NXAMF_HAT_STATE_UPRIGHT: - return "UPRIGHT"; - case NXAMF_HAT_STATE_RIGHT: - return "RIGHT"; - case NXAMF_HAT_STATE_DOWNRIGHT: - return "DOWNRIGHT"; - case NXAMF_HAT_STATE_DOWN: - return "DOWN"; - case NXAMF_HAT_STATE_DOWNLEFT: - return "DOWNLEFT"; - case NXAMF_HAT_STATE_LEFT: - return "LEFT"; - case NXAMF_HAT_STATE_UPLEFT: - return "UPLEFT"; - case NXAMF_HAT_STATE_NEUTRAL: - return "NEUTRAL"; - default: - return "[Unknown]"; - } -} - -static char _format_state_buffer[1024]; -static char *format_state(const NxamfGamepadState *state) -{ - snprintf(_format_state_buffer, 1024, - "Gamepad State:\n" - " Y: %s\t" - "B: %s\t" - "A: %s\t" - "X: %s\n" - " L: %s\t" - "R: %s\t" - "ZL: %s\t" - "ZR: %s\n" - " Minus: %s\t" - "Plus: %s\t" - "L Click: %s\t" - "R Click: %s\n" - " Home: %s\t" - "Capture: %s\n" - " Hat: %s\n" - " Left Stick: (x=%u, y=%u)\n" - " Right Stick: (x=%u, y=%u)\n", - _button_to_string(state->y), _button_to_string(state->b), - _button_to_string(state->a), _button_to_string(state->x), - _button_to_string(state->l), _button_to_string(state->r), - _button_to_string(state->zl), _button_to_string(state->zr), - _button_to_string(state->minus), _button_to_string(state->plus), - _button_to_string(state->l_click), _button_to_string(state->r_click), - _button_to_string(state->home), _button_to_string(state->capture), - _hat_to_string(state->hat), - state->l_stick.x, state->l_stick.y, state->r_stick.x, state->r_stick.y); - - return _format_state_buffer; -} - -static int64_t led_off(alarm_id_t id, void *user_data) -{ - digitalWrite(LED_BUILTIN, LOW); - return false; -} - -static void async_led_on_for_100ms() +static mutex_t mtx; +static CGamecubeConsole console(5); +static Gamecube_Data_t gc = defaultGamecubeData; + +static nxmc2_format_handler_t nxmc2; +static orca_format_handler_t orca; +static pokecon_format_handler_t pokecon; +static nthaka_format_handler_t *fmts[] = {(nthaka_format_handler_t *)&nxmc2, // + (nthaka_format_handler_t *)&orca, // + (nthaka_format_handler_t *)&pokecon}; +static size_t idx_using_servo[] = {1}; +static nthaka_multi_format_handler_t fmt; +static nthaka_buffer_t buf; +static nthaka_gamepad_state_t out; + +static int64_t _led_off(alarm_id_t id, void *user_data) { - digitalWrite(LED_BUILTIN, HIGH); - alarm_id_t alarm_id = add_alarm_in_ms(100, led_off, NULL, false); + digitalWriteFast(LED_BUILTIN, LOW); + return 0; } -static void reflect_state(NxamfGamepadState *state) +static inline void async_led_on(uint32_t dur_ms) { - if (state == NULL) - { - return; - } - - async_led_on_for_100ms(); - - mutex_enter_blocking(&d_mutex); - - d.report.y = (uint8_t)state->y; - d.report.b = (uint8_t)state->b; - d.report.a = (uint8_t)state->a; - d.report.x = (uint8_t)state->x; - d.report.l = (uint8_t)state->l; - d.report.r = (uint8_t)state->r; - d.report.z = (uint8_t)state->zr; - d.report.start = (uint8_t)state->plus; - if (reset_state != state->home) - { - servo.write(state->home == NXAMF_BUTTON_STATE_PRESSED ? 65 : 90); - reset_state = state->home; - - // ORCAのサーボモータ使用はブロッキング処理 - if (mux->ready_index == ORCA_INDEX) - { - delay(500); - servo.write(90); - delay(500); - reset_state = NXAMF_BUTTON_STATE_RELEASED; - } - } - - switch (state->hat) - { - case NXAMF_HAT_STATE_UP: - d.report.dup = 1; - d.report.dright = 0; - d.report.ddown = 0; - d.report.dleft = 0; - break; - case NXAMF_HAT_STATE_UPRIGHT: - d.report.dup = 1; - d.report.dright = 1; - d.report.ddown = 0; - d.report.dleft = 0; - break; - case NXAMF_HAT_STATE_RIGHT: - d.report.dup = 0; - d.report.dright = 1; - d.report.ddown = 0; - d.report.dleft = 0; - break; - case NXAMF_HAT_STATE_DOWNRIGHT: - d.report.dup = 0; - d.report.dright = 1; - d.report.ddown = 1; - d.report.dleft = 0; - break; - case NXAMF_HAT_STATE_DOWN: - d.report.dup = 0; - d.report.dright = 0; - d.report.ddown = 1; - d.report.dleft = 0; - break; - case NXAMF_HAT_STATE_DOWNLEFT: - d.report.dup = 0; - d.report.dright = 0; - d.report.ddown = 1; - d.report.dleft = 1; - break; - case NXAMF_HAT_STATE_LEFT: - d.report.dup = 0; - d.report.dright = 0; - d.report.ddown = 0; - d.report.dleft = 1; - break; - case NXAMF_HAT_STATE_UPLEFT: - d.report.dup = 1; - d.report.dright = 0; - d.report.ddown = 0; - d.report.dleft = 1; - break; - case NXAMF_HAT_STATE_NEUTRAL: - default: - d.report.dup = 0; - d.report.dright = 0; - d.report.ddown = 0; - d.report.dleft = 0; - break; - } - - d.report.xAxis = state->l_stick.x; - // There are a few games that do not handle yAxis=0 correctly. - uint8_t y_axis = 0xFF - state->l_stick.y; - d.report.yAxis = y_axis == 0 ? 1 : y_axis; - - d.report.cxAxis = state->r_stick.x; - // There are a few games that do not handle cyAxis=0 correctly. - uint8_t cy_axis = 0xFF - state->r_stick.y; - d.report.cyAxis = cy_axis == 0 ? 1 : cy_axis; - - mutex_exit(&d_mutex); + digitalWriteFast(LED_BUILTIN, HIGH); + add_alarm_in_ms(dur_ms, _led_off, NULL, false); } void setup() { + Serial.setTimeout(100); Serial.begin(9600); -#ifndef NDEBUG - mutex_init(&serial1_mutex); - mutex_enter_blocking(&serial1_mutex); Serial1.setTX(0); Serial1.setRX(1); - Serial1.begin(); - mutex_exit(&serial1_mutex); -#define debug_println(msg) \ - mutex_enter_blocking(&serial1_mutex); \ - Serial1.println(msg); \ - mutex_exit(&serial1_mutex); -#else -#define debug_println(msg) ((void)0) -#endif + Serial1.begin(115200); + + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); // Setup for SG90 servo.attach(PIN_SERVO, 500, 2400); - mutex_init(&d_mutex); - mutex_enter_blocking(&d_mutex); - d.report.a = 0; - d.report.b = 0; - d.report.x = 0; - d.report.y = 0; - d.report.start = 0; - d.report.dleft = 0; - d.report.dright = 0; - d.report.ddown = 0; - d.report.dup = 0; - d.report.z = 0; - d.report.r = 0; - d.report.l = 0; - d.report.xAxis = 128; - d.report.yAxis = 128; - d.report.cxAxis = 128; - d.report.cyAxis = 128; - d.report.left = 0; - d.report.right = 0; + mutex_init(&mtx); - // Omajinai to recognize the controller - d.report.start = 1; - console.write(d); - d.report.start = 0; - console.write(d); - mutex_exit(&d_mutex); + gc_console_data_init(&console, &gc, &mtx); - nxmc2 = nxmc2_protocol_new(); - pokecon = pokecon_protocol_new(); - orca = orca_protocol_new(); - protocols[0] = (NxamfBytesProtocolInterface *)nxmc2; - protocols[1] = (NxamfBytesProtocolInterface *)pokecon; - protocols[2] = (NxamfBytesProtocolInterface *)orca; - mux = nxamf_protocol_multiplexer_new(protocols, 3); - buffer = nxamf_bytes_buffer_new((NxamfBytesProtocolInterface *)mux); - assert( - nxmc2 != NULL && - pokecon != NULL && - orca != NULL && - mux != NULL && - buffer != NULL); + if (!(nxmc2_format_handler_init(&nxmc2) && + orca_format_handler_init(&orca) && + pokecon_format_handler_init(&pokecon) && + nthaka_multi_format_handler_init(&fmt, fmts, 3) && + nthaka_buffer_init(&buf, (nthaka_format_handler_t *)&fmt) && - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); + jiangtun_init(&j, &servo, idx_using_servo, sizeof(idx_using_servo) / sizeof(size_t), &mtx))) + { + digitalWrite(LED_BUILTIN, HIGH); + while (true) + ; + } } void loop() { - if (Serial.available() == 0) + uint8_t d; + nthaka_buffer_state_t s; + if (Serial.readBytes(&d, 1) != 1 || + (s = nthaka_buffer_append(&buf, d, &out)) == NTHAKA_BUFFER_REJECTED) { - inactive_count++; - if (SERIAL_INACTIVE_TIMEOUT < inactive_count) - { - inactive_count = 0; - nxamf_bytes_buffer_clear(buffer); - } + nthaka_buffer_clear(&buf); return; } - inactive_count = 0; - - uint8_t packet = Serial.read(); - debug_println(packet); - NxamfGamepadState *state = nxamf_bytes_buffer_append(buffer, packet); - if (state == NULL) + else if (s == NTHAKA_BUFFER_PENDING) { return; } - debug_println(format_state(state)); - reflect_state(state); + size_t *idx = nthaka_multi_format_handler_get_last_deserialized_index(&fmt); + if (idx == NULL) + { + *idx = 0; + }; - nxamf_gamepad_state_delete(state); - state = NULL; + async_led_on(100); + jiangtun_update(&j, &out, *idx, &gc); + nthaka_buffer_clear(&buf); } void setup1() @@ -330,12 +111,12 @@ void setup1() void loop1() { - mutex_enter_blocking(&d_mutex); - bool ret = console.write(d); - mutex_exit(&d_mutex); + mutex_enter_blocking(&mtx); + bool ret = console.write(gc); + mutex_exit(&mtx); if (!ret) { - debug_println("GC is not powered on or not connected."); + Serial1.println("GC is not powered on or not connected."); } } \ No newline at end of file diff --git a/src/orca.h b/src/orca.h deleted file mode 100644 index 4cac332..0000000 --- a/src/orca.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ORCA_H_ -#define ORCA_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "nxamf.h" - -typedef struct OrcaProtocol -{ - NxamfBytesProtocolInterface parent; -} OrcaProtocol; - -OrcaProtocol *orca_protocol_new(void); -void orca_protocol_delete(OrcaProtocol *self); - -#ifdef __cplusplus -} -#endif - -#endif // ORCA_H_ \ No newline at end of file diff --git a/src/orca_protocol.c b/src/orca_protocol.c deleted file mode 100644 index 6be0f3c..0000000 --- a/src/orca_protocol.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "orca.h" - -#include - -// - 0x40('@')のみ -// - {0x80, A, B}、ただし0xFFでない - -static bool orca_protocol_is_acceptable(NxamfBytesProtocolInterface *self, const uint8_t packet, const uint8_t buffer[], const size_t length) -{ - return (length == 0 && (packet == (uint8_t)'@' || packet == 0x80)) || - ((0 < length && length <= 2) && packet != 0xFF); -} - -static bool orca_protocol_is_ready(NxamfBytesProtocolInterface *self, const uint8_t buffer[], const size_t length) -{ - return (length == 1 && buffer[0] == (uint8_t)'@') || - (length == 3 && buffer[0] == 0x80 && buffer[1] != 0xFF && buffer[2] != 0xFF); -} - -static void orca_protocol_convert(NxamfBytesProtocolInterface *self, const uint8_t buffer[], const size_t length, NxamfGamepadState *state) -{ - if (length == 1) - { - state->home = NXAMF_BUTTON_STATE_PRESSED; - return; - } - - if (buffer[1] == 0x80) - { - state->a = NXAMF_BUTTON_STATE_RELEASED; - state->b = NXAMF_BUTTON_STATE_RELEASED; - state->x = NXAMF_BUTTON_STATE_RELEASED; - state->y = NXAMF_BUTTON_STATE_RELEASED; - state->l = NXAMF_BUTTON_STATE_RELEASED; - state->r = NXAMF_BUTTON_STATE_RELEASED; - } - else - { - state->a = (NxamfButtonState)(buffer[1] & 1); - state->b = (NxamfButtonState)((buffer[1] >> 1) & 1); - state->x = (NxamfButtonState)((buffer[1] >> 2) & 1); - state->y = (NxamfButtonState)((buffer[1] >> 3) & 1); - state->l = (NxamfButtonState)((buffer[1] >> 4) & 1); - state->r = (NxamfButtonState)((buffer[1] >> 5) & 1); - } - - uint8_t dleft = 0; - uint8_t dright = 0; - uint8_t dup = 0; - uint8_t ddown = 0; - - if (buffer[2] == 0x80) - { - state->zr = NXAMF_BUTTON_STATE_RELEASED; - state->plus = NXAMF_BUTTON_STATE_RELEASED; - dleft = 0; - dright = 0; - dup = 0; - ddown = 0; - } - else - { - state->zr = (NxamfButtonState)(buffer[2] & 1); - state->plus = (NxamfButtonState)((buffer[2] >> 1) & 1); - dleft = (buffer[2] >> 2) & 1; - dright = (buffer[2] >> 3) & 1; - dup = (buffer[2] >> 4) & 1; - ddown = (buffer[2] >> 5) & 1; - } - - switch (dup << 3 | dright << 2 | ddown << 1 | dleft) - { - case 0b1000: - state->hat = NXAMF_HAT_STATE_UP; - break; - case 0b1100: - state->hat = NXAMF_HAT_STATE_UPRIGHT; - break; - case 0b0100: - state->hat = NXAMF_HAT_STATE_RIGHT; - break; - case 0b0110: - state->hat = NXAMF_HAT_STATE_DOWNRIGHT; - break; - case 0b0010: - state->hat = NXAMF_HAT_STATE_DOWN; - break; - case 0b0011: - state->hat = NXAMF_HAT_STATE_DOWNLEFT; - break; - case 0b0001: - state->hat = NXAMF_HAT_STATE_LEFT; - break; - case 0b1001: - state->hat = NXAMF_HAT_STATE_UPLEFT; - break; - default: - state->hat = NXAMF_HAT_STATE_NEUTRAL; - break; - } -} - -OrcaProtocol *orca_protocol_new(void) -{ - OrcaProtocol *self = (OrcaProtocol *)malloc(sizeof(OrcaProtocol)); - if (self == NULL) - { - return NULL; - } - - self->parent.is_acceptable = orca_protocol_is_acceptable; - self->parent.is_ready = orca_protocol_is_ready; - self->parent.convert = orca_protocol_convert; - - return self; -} - -void orca_protocol_delete(OrcaProtocol *self) -{ - if (self == NULL) - { - return; - } - - free(self); -} \ No newline at end of file From 4ee1e5caaf08dbc0c7c175d9aa807f1fe27e2c83 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 4 Feb 2024 15:12:20 +0900 Subject: [PATCH 02/25] Add build flags --- platformio.ini | 36 +++++++++++++++++++++++++++++++++--- src/main.cpp | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/platformio.ini b/platformio.ini index 1a18b7a..4455663 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,10 +15,40 @@ framework = arduino board_build.core = earlephilhower debug_tool = cmsis-dap -[env:release] +[env:pico] platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = pico framework = arduino board_build.core = earlephilhower -debug_tool = cmsis-dap -build_flags = -DNDEBUG +build_flags = + -DNDEBUG + -DJIANGTUN_CONFIG_BOARD_PICO + +[env:dol-pico] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = pico +framework = arduino +board_build.core = earlephilhower +build_flags = + -DNDEBUG + -DJIANGTUN_CONFIG_BOARD_PICO + -DJIANGTUN_CONFIG_ENABLE_DOL + +[env:xiao-rp2040] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = seeed_xiao_rp2040 +framework = arduino +board_build.core = earlephilhower +build_flags = + -DNDEBUG + -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 + +[env:dol-xiao-rp2040] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = seeed_xiao_rp2040 +framework = arduino +board_build.core = earlephilhower +build_flags = + -DNDEBUG + -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 + -DJIANGTUN_CONFIG_ENABLE_DOL \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c26f727..9dce63a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "Bluewhale.h" #include "nthaka.h" +#include "nthaka/dol.h" #include "nthaka/nxmc2.h" #include "nthaka/orca.h" #include "nthaka/pokecon.h" @@ -16,20 +17,39 @@ static jiangtun_t j; +#ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 +#define PIN_RESET 3 +#define PIN_GC 7 +#define PIN_SERVO 0 +#else // JIANGTUN_CONFIG_BOARD_PICO +#define PIN_RESET 3 +#define PIN_GC 5 +#define PIN_SERVO 6 +#endif + static Servo servo; -static const int PIN_SERVO = 6; static mutex_t mtx; -static CGamecubeConsole console(5); +static CGamecubeConsole console(PIN_GC); static Gamecube_Data_t gc = defaultGamecubeData; +static dol_format_handler_t dol; static nxmc2_format_handler_t nxmc2; static orca_format_handler_t orca; static pokecon_format_handler_t pokecon; -static nthaka_format_handler_t *fmts[] = {(nthaka_format_handler_t *)&nxmc2, // - (nthaka_format_handler_t *)&orca, // - (nthaka_format_handler_t *)&pokecon}; -static size_t idx_using_servo[] = {1}; +static nthaka_format_handler_t *fmts[] = {(nthaka_format_handler_t *)&nxmc2, + (nthaka_format_handler_t *)&orca, +#ifdef JIANGTUN_CONFIG_ENABLE_DOL + (nthaka_format_handler_t *)&dol +#else + (nthaka_format_handler_t *)&pokecon +#endif // JIANGTUN_CONFIG_ENABLE_DOL +}; +static size_t idx_using_servo[] = {1, +#ifdef JIANGTUN_CONFIG_ENABLE_DOL + 2 +#endif // JIANGTUN_CONFIG_ENABLE_DOL +}; static nthaka_multi_format_handler_t fmt; static nthaka_buffer_t buf; static nthaka_gamepad_state_t out; @@ -51,10 +71,6 @@ void setup() Serial.setTimeout(100); Serial.begin(9600); - Serial1.setTX(0); - Serial1.setRX(1); - Serial1.begin(115200); - pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); @@ -65,7 +81,8 @@ void setup() gc_console_data_init(&console, &gc, &mtx); - if (!(nxmc2_format_handler_init(&nxmc2) && + if (!(dol_format_handler_init(&dol) && + nxmc2_format_handler_init(&nxmc2) && orca_format_handler_init(&orca) && pokecon_format_handler_init(&pokecon) && nthaka_multi_format_handler_init(&fmt, fmts, 3) && @@ -98,7 +115,7 @@ void loop() if (idx == NULL) { *idx = 0; - }; + } async_led_on(100); jiangtun_update(&j, &out, *idx, &gc); @@ -117,6 +134,6 @@ void loop1() if (!ret) { - Serial1.println("GC is not powered on or not connected."); + Serial.println("GC is not powered on or not connected."); } } \ No newline at end of file From 4849df6f207bbdc0b141fe3e856badaa4559e2c3 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 4 Feb 2024 15:42:56 +0900 Subject: [PATCH 03/25] Add Makefile --- .gitignore | 6 ++-- .vscode/extensions.json | 10 ------ .vscode/settings.json | 72 ----------------------------------------- Makefile | 46 ++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 86 deletions(-) delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/settings.json create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 89cc49c..fe12972 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ .pio -.vscode/.browse.c_cpp.db* -.vscode/c_cpp_properties.json -.vscode/launch.json -.vscode/ipch +.vscode +dist \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 080e70d..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ], - "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5e9627b..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "files.associations": { - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "list": "cpp", - "map": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "limits": "cpp", - "new": "cpp", - "ostream": "cpp", - "ranges": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "cinttypes": "cpp", - "typeinfo": "cpp", - "any": "cpp", - "chrono": "cpp", - "condition_variable": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "set": "cpp", - "unordered_set": "cpp", - "ratio": "cpp", - "fstream": "cpp", - "iomanip": "cpp", - "iostream": "cpp", - "istream": "cpp", - "mutex": "cpp", - "numbers": "cpp", - "semaphore": "cpp", - "sstream": "cpp", - "stop_token": "cpp", - "thread": "cpp", - "variant": "cpp", - "serialusb.h": "c", - "codecvt": "cpp" - }, - "cmake.configureOnOpen": false -} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bad6845 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +.PHONY: all clean + +ifeq ($(OS),Windows_NT) + RM = powershell -Command Remove-Item -Recurse -Force + CP = copy + FIXPATH = $(subst /,\,$1) +else + RM = rm -rf + CP = cp + FIXPATH = $1 +endif + +PIO = C:\Users\mukai\.platformio\penv\Scripts\platformio.exe + +.pio/build/pico/firmware.uf2: + $(PIO) run --environment pico + +.pio/build/dol-pico/firmware.uf2: + $(PIO) run --environment dol-pico + +.pio/build/xiao-rp2040/firmware.uf2: + $(PIO) run --environment xiao-rp2040 + +.pio/build/dol-xiao-rp2040/firmware.uf2: + $(PIO) run --environment dol-xiao-rp2040 + +dist: + mkdir dist + +dist/firmware-pico.uf2: .pio/build/pico/firmware.uf2 dist + $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) + +dist/firmware-dol-pico.uf2: .pio/build/dol-pico/firmware.uf2 dist + $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) + +dist/firmware-xiao-rp2040.uf2: .pio/build/xiao-rp2040/firmware.uf2 dist + $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) + +dist/firmware-dol-xiao-rp2040.uf2: .pio/build/dol-xiao-rp2040/firmware.uf2 dist + $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) + +all: dist/firmware-pico.uf2 dist/firmware-dol-pico.uf2 dist/firmware-xiao-rp2040.uf2 dist/firmware-dol-xiao-rp2040.uf2 + +clean: + $(RM) $(call FIXPATH,dist/*) + $(RM) $(call FIXPATH,.pio/build/*) \ No newline at end of file From b3a76c3954b1c588d18e41552d7dd1e5f253ca38 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 4 Feb 2024 16:04:47 +0900 Subject: [PATCH 04/25] Fix pio path --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bad6845..b9e3519 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,14 @@ ifeq ($(OS),Windows_NT) RM = powershell -Command Remove-Item -Recurse -Force CP = copy FIXPATH = $(subst /,\,$1) + PIO = $(USERPROFILE)\.platformio\penv\Scripts\platformio.exe else RM = rm -rf CP = cp FIXPATH = $1 + PIO = $(HOME)/.platformio/penv/bin/platformio endif -PIO = C:\Users\mukai\.platformio\penv\Scripts\platformio.exe - .pio/build/pico/firmware.uf2: $(PIO) run --environment pico From a3aa348003f24e5de1a069f9e14611f660dc876d Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 4 Feb 2024 20:13:12 +0900 Subject: [PATCH 05/25] Add reset pin support --- Makefile | 8 ++++---- include/jiangtun.h | 15 +++++++++------ src/jiangtun.cpp | 9 +++++++-- src/main.cpp | 18 +++++++++++++----- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index b9e3519..03a7680 100644 --- a/Makefile +++ b/Makefile @@ -12,16 +12,16 @@ else PIO = $(HOME)/.platformio/penv/bin/platformio endif -.pio/build/pico/firmware.uf2: +.pio/build/pico/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h $(PIO) run --environment pico -.pio/build/dol-pico/firmware.uf2: +.pio/build/dol-pico/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h $(PIO) run --environment dol-pico -.pio/build/xiao-rp2040/firmware.uf2: +.pio/build/xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h $(PIO) run --environment xiao-rp2040 -.pio/build/dol-xiao-rp2040/firmware.uf2: +.pio/build/dol-xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h $(PIO) run --environment dol-xiao-rp2040 dist: diff --git a/include/jiangtun.h b/include/jiangtun.h index 9e7ee5f..66b7c98 100644 --- a/include/jiangtun.h +++ b/include/jiangtun.h @@ -1,6 +1,7 @@ #ifndef JIANGTUN_H_ #define JIANGTUN_H_ +#include #include #include "pico/mutex.h" @@ -11,27 +12,29 @@ typedef struct jiangtun_t { + pin_size_t _reset; Servo *_servo; - size_t *_idx_using_servo; - size_t _idx_using_servo_size; + size_t *_idx_servo_blocking; + size_t _idx_servo_blocking_size; mutex_t *_mtx; nthaka_button_state_t _reset_state; } jiangtun_t; -inline bool jiangtun_init(jiangtun_t *j, Servo *servo, size_t idx_using_servo[], size_t size, mutex_t *mtx) +inline bool jiangtun_init(jiangtun_t *j, pin_size_t reset, Servo *servo, size_t idx_servo_blocking[], size_t size, mutex_t *mtx) { if (j == NULL || servo == NULL || - idx_using_servo == NULL || + idx_servo_blocking == NULL || mtx == NULL) { return false; } + j->_reset = reset; j->_servo = servo; - j->_idx_using_servo = idx_using_servo; - j->_idx_using_servo_size = size; + j->_idx_servo_blocking = idx_servo_blocking; + j->_idx_servo_blocking_size = size; j->_mtx = mtx; j->_reset_state = NTHAKA_BUTTON_RELEASED; diff --git a/src/jiangtun.cpp b/src/jiangtun.cpp index 48b44d3..633c077 100644 --- a/src/jiangtun.cpp +++ b/src/jiangtun.cpp @@ -24,10 +24,13 @@ void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, j->_servo->write(s->home == NTHAKA_BUTTON_PRESSED ? 65 : 90); j->_reset_state = s->home; + pinMode(j->_reset, OUTPUT); + digitalWrite(j->_reset, LOW); + // For listed idx, use servo with blocking - for (size_t i = 0; i < j->_idx_using_servo_size; i++) + for (size_t i = 0; i < j->_idx_servo_blocking_size; i++) { - if (j->_idx_using_servo[i] == idx_from) + if (j->_idx_servo_blocking[i] == idx_from) { servo_up = true; break; @@ -111,5 +114,7 @@ void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, j->_servo->write(90); delay(500); j->_reset_state = NTHAKA_BUTTON_RELEASED; + + pinMode(j->_reset, INPUT); } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9dce63a..890a62a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,9 +45,9 @@ static nthaka_format_handler_t *fmts[] = {(nthaka_format_handler_t *)&nxmc2, (nthaka_format_handler_t *)&pokecon #endif // JIANGTUN_CONFIG_ENABLE_DOL }; -static size_t idx_using_servo[] = {1, +static size_t idx_servo_blocking[] = {1, #ifdef JIANGTUN_CONFIG_ENABLE_DOL - 2 + 2 #endif // JIANGTUN_CONFIG_ENABLE_DOL }; static nthaka_multi_format_handler_t fmt; @@ -74,8 +74,11 @@ void setup() pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); + pinMode(PIN_RESET, INPUT); // Hi-Z + // Setup for SG90 servo.attach(PIN_SERVO, 500, 2400); + servo.write(90); mutex_init(&mtx); @@ -88,11 +91,15 @@ void setup() nthaka_multi_format_handler_init(&fmt, fmts, 3) && nthaka_buffer_init(&buf, (nthaka_format_handler_t *)&fmt) && - jiangtun_init(&j, &servo, idx_using_servo, sizeof(idx_using_servo) / sizeof(size_t), &mtx))) + jiangtun_init(&j, PIN_RESET, &servo, idx_servo_blocking, sizeof(idx_servo_blocking) / sizeof(size_t), &mtx))) { - digitalWrite(LED_BUILTIN, HIGH); while (true) - ; + { + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(100); + } } } @@ -124,6 +131,7 @@ void loop() void setup1() { + delay(10); } void loop1() From 995d26e4b861c482c8a4fde70640eccae45babeb Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 5 Feb 2024 00:31:03 +0900 Subject: [PATCH 06/25] Change pin assign --- Makefile | 10 +++---- platformio.ini | 4 +++ src/main.cpp | 71 ++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 03a7680..6114444 100644 --- a/Makefile +++ b/Makefile @@ -27,19 +27,19 @@ endif dist: mkdir dist -dist/firmware-pico.uf2: .pio/build/pico/firmware.uf2 dist +dist/jiangtun-pico.uf2: .pio/build/pico/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -dist/firmware-dol-pico.uf2: .pio/build/dol-pico/firmware.uf2 dist +dist/jiangtun-dol-pico.uf2: .pio/build/dol-pico/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -dist/firmware-xiao-rp2040.uf2: .pio/build/xiao-rp2040/firmware.uf2 dist +dist/jiangtun-xiao-rp2040.uf2: .pio/build/xiao-rp2040/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -dist/firmware-dol-xiao-rp2040.uf2: .pio/build/dol-xiao-rp2040/firmware.uf2 dist +dist/jiangtun-dol-xiao-rp2040.uf2: .pio/build/dol-xiao-rp2040/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -all: dist/firmware-pico.uf2 dist/firmware-dol-pico.uf2 dist/firmware-xiao-rp2040.uf2 dist/firmware-dol-xiao-rp2040.uf2 +all: dist/jiangtun-pico.uf2 dist/jiangtun-dol-pico.uf2 dist/jiangtun-xiao-rp2040.uf2 dist/jiangtun-dol-xiao-rp2040.uf2 clean: $(RM) $(call FIXPATH,dist/*) diff --git a/platformio.ini b/platformio.ini index 4455663..5363770 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,6 +39,8 @@ platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = seeed_xiao_rp2040 framework = arduino board_build.core = earlephilhower +lib_deps = + adafruit/Adafruit NeoPixel@^1.12.0 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 @@ -48,6 +50,8 @@ platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = seeed_xiao_rp2040 framework = arduino board_build.core = earlephilhower +lib_deps = + adafruit/Adafruit NeoPixel@^1.12.0 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 diff --git a/src/main.cpp b/src/main.cpp index 890a62a..0a5f667 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,18 +15,41 @@ #include "jiangtun.h" #include "internal.h" -static jiangtun_t j; - #ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 -#define PIN_RESET 3 -#define PIN_GC 7 -#define PIN_SERVO 0 + +#define PIN_RESET D10 +#define PIN_GC D5 +#define PIN_SERVO D6 + +#include + +static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); + +inline void led_on() +{ + pixels.setPixelColor(0, pixels.Color(255, 255, 255)); + pixels.show(); +} + +inline void led_off() +{ + pixels.clear(); + pixels.show(); +} + #else // JIANGTUN_CONFIG_BOARD_PICO + #define PIN_RESET 3 #define PIN_GC 5 #define PIN_SERVO 6 + +#define led_on() (digitalWrite(LED_BUILTIN, HIGH)) +#define led_off() (digitalWrite(LED_BUILTIN, LOW)) + #endif +static jiangtun_t j; + static Servo servo; static mutex_t mtx; @@ -56,24 +79,42 @@ static nthaka_gamepad_state_t out; static int64_t _led_off(alarm_id_t id, void *user_data) { - digitalWriteFast(LED_BUILTIN, LOW); + led_off(); return 0; } static inline void async_led_on(uint32_t dur_ms) { - digitalWriteFast(LED_BUILTIN, HIGH); + led_on(); add_alarm_in_ms(dur_ms, _led_off, NULL, false); } void setup() { +#ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 + + pinMode(PIN_LED_R, OUTPUT); + pinMode(PIN_LED_G, OUTPUT); + pinMode(PIN_LED_B, OUTPUT); + digitalWrite(PIN_LED_R, HIGH); + digitalWrite(PIN_LED_G, HIGH); + digitalWrite(PIN_LED_B, HIGH); + + pinMode(NEOPIXEL_POWER, OUTPUT); + pinMode(NEOPIXEL_POWER, HIGH); + + pixels.begin(); + +#else // JIANGTUN_CONFIG_BOARD_PICO + + pinMode(PIN_LED_, OUTPUT); + digitalWrite(PIN_LED_, LOW); + +#endif + Serial.setTimeout(100); Serial.begin(9600); - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - pinMode(PIN_RESET, INPUT); // Hi-Z // Setup for SG90 @@ -93,13 +134,9 @@ void setup() jiangtun_init(&j, PIN_RESET, &servo, idx_servo_blocking, sizeof(idx_servo_blocking) / sizeof(size_t), &mtx))) { + led_on(); while (true) - { - digitalWrite(LED_BUILTIN, HIGH); - delay(100); - digitalWrite(LED_BUILTIN, LOW); - delay(100); - } + ; } } @@ -124,7 +161,7 @@ void loop() *idx = 0; } - async_led_on(100); + async_led_on(500); jiangtun_update(&j, &out, *idx, &gc); nthaka_buffer_clear(&buf); } From 9b905c436f66fdcdc885b8fa18ecef47c519876e Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 5 Feb 2024 07:11:08 +0900 Subject: [PATCH 07/25] Return the reset pin to INPUT --- src/jiangtun.cpp | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/jiangtun.cpp b/src/jiangtun.cpp index 633c077..a0f5f15 100644 --- a/src/jiangtun.cpp +++ b/src/jiangtun.cpp @@ -21,21 +21,31 @@ void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, bool servo_up = false; if (j->_reset_state != s->home) { - j->_servo->write(s->home == NTHAKA_BUTTON_PRESSED ? 65 : 90); - j->_reset_state = s->home; + if (s->home == NTHAKA_BUTTON_PRESSED) + { + j->_reset_state = NTHAKA_BUTTON_PRESSED; - pinMode(j->_reset, OUTPUT); - digitalWrite(j->_reset, LOW); + j->_servo->write(65); + pinMode(j->_reset, OUTPUT); + digitalWrite(j->_reset, LOW); - // For listed idx, use servo with blocking - for (size_t i = 0; i < j->_idx_servo_blocking_size; i++) - { - if (j->_idx_servo_blocking[i] == idx_from) + // For listed idx, use servo with blocking + for (size_t i = 0; i < j->_idx_servo_blocking_size; i++) { - servo_up = true; - break; + if (j->_idx_servo_blocking[i] == idx_from) + { + servo_up = true; + break; + } } } + else + { + j->_reset_state = NTHAKA_BUTTON_RELEASED; + + j->_servo->write(90); + pinMode(j->_reset, INPUT); + } } switch (s->hat) @@ -110,11 +120,11 @@ void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, if (servo_up) { - delay(500); - j->_servo->write(90); - delay(500); j->_reset_state = NTHAKA_BUTTON_RELEASED; + delay(500); + j->_servo->write(90); pinMode(j->_reset, INPUT); + delay(500); } } \ No newline at end of file From 33a9610e61efa59e30401f804c5c73496f3ca43f Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Wed, 7 Feb 2024 01:01:26 +0900 Subject: [PATCH 08/25] Use NeoPixel instead of LED_BUILTIN --- include/jiangtun.h | 47 ------ platformio.ini | 17 ++- src/internal.h | 45 ------ src/jiangtun.cpp | 130 ----------------- src/main.cpp | 355 ++++++++++++++++++++++++++++++++++++--------- 5 files changed, 296 insertions(+), 298 deletions(-) delete mode 100644 include/jiangtun.h delete mode 100644 src/internal.h delete mode 100644 src/jiangtun.cpp diff --git a/include/jiangtun.h b/include/jiangtun.h deleted file mode 100644 index 66b7c98..0000000 --- a/include/jiangtun.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef JIANGTUN_H_ -#define JIANGTUN_H_ - -#include -#include - -#include "pico/mutex.h" - -#include "Bluewhale.h" - -#include "nthaka.h" - -typedef struct jiangtun_t -{ - pin_size_t _reset; - Servo *_servo; - size_t *_idx_servo_blocking; - size_t _idx_servo_blocking_size; - mutex_t *_mtx; - - nthaka_button_state_t _reset_state; -} jiangtun_t; - -inline bool jiangtun_init(jiangtun_t *j, pin_size_t reset, Servo *servo, size_t idx_servo_blocking[], size_t size, mutex_t *mtx) -{ - if (j == NULL || - servo == NULL || - idx_servo_blocking == NULL || - mtx == NULL) - { - return false; - } - - j->_reset = reset; - j->_servo = servo; - j->_idx_servo_blocking = idx_servo_blocking; - j->_idx_servo_blocking_size = size; - j->_mtx = mtx; - - j->_reset_state = NTHAKA_BUTTON_RELEASED; - - return true; -} - -void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, Gamecube_Data_t *gc); - -#endif // JIANGTUN_H_ \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 5363770..29a85ec 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,31 +8,30 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:debug] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico -framework = arduino -board_build.core = earlephilhower -debug_tool = cmsis-dap - [env:pico] platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = pico framework = arduino board_build.core = earlephilhower +lib_deps = + adafruit/Adafruit NeoPixel@^1.12.0 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_PICO +debug_tool = cmsis-dap [env:dol-pico] platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = pico framework = arduino board_build.core = earlephilhower +lib_deps = + adafruit/Adafruit NeoPixel@^1.12.0 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_PICO -DJIANGTUN_CONFIG_ENABLE_DOL +debug_tool = cmsis-dap [env:xiao-rp2040] platform = https://github.com/maxgerhardt/platform-raspberrypi.git @@ -44,6 +43,7 @@ lib_deps = build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 +debug_tool = cmsis-dap [env:dol-xiao-rp2040] platform = https://github.com/maxgerhardt/platform-raspberrypi.git @@ -55,4 +55,5 @@ lib_deps = build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 - -DJIANGTUN_CONFIG_ENABLE_DOL \ No newline at end of file + -DJIANGTUN_CONFIG_ENABLE_DOL +debug_tool = cmsis-dap \ No newline at end of file diff --git a/src/internal.h b/src/internal.h deleted file mode 100644 index c092bd4..0000000 --- a/src/internal.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef JIANGTUN_INTERNAL_H_ -#define JIANGTUN_INTERNAL_H_ - -#include "pico/mutex.h" - -#include "Bluewhale.h" - -void gc_console_data_init(CGamecubeConsole *console, Gamecube_Data_t *gc, mutex_t *mtx) -{ - if (console == NULL || - gc == NULL || - mtx == NULL) - { - return; - } - - mutex_enter_blocking(mtx); - gc->report.a = 0; - gc->report.b = 0; - gc->report.x = 0; - gc->report.y = 0; - gc->report.start = 0; - gc->report.dleft = 0; - gc->report.dright = 0; - gc->report.ddown = 0; - gc->report.dup = 0; - gc->report.z = 0; - gc->report.r = 0; - gc->report.l = 0; - gc->report.xAxis = 128; - gc->report.yAxis = 128; - gc->report.cxAxis = 128; - gc->report.cyAxis = 128; - gc->report.left = 0; - gc->report.right = 0; - - // Magic spell to make the controller be recognized by the Gamecube - gc->report.start = 1; - console->write(*gc); - gc->report.start = 0; - console->write(*gc); - mutex_exit(mtx); -} - -#endif // JIANGTUN_INTERNAL_H_ \ No newline at end of file diff --git a/src/jiangtun.cpp b/src/jiangtun.cpp deleted file mode 100644 index a0f5f15..0000000 --- a/src/jiangtun.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "jiangtun.h" - -void jiangtun_update(jiangtun_t *j, nthaka_gamepad_state_t *s, size_t idx_from, Gamecube_Data_t *gc) -{ - if (j == NULL) - { - return; - } - - mutex_enter_blocking(j->_mtx); - - gc->report.y = (uint8_t)s->y; - gc->report.b = (uint8_t)s->b; - gc->report.a = (uint8_t)s->a; - gc->report.x = (uint8_t)s->x; - gc->report.l = (uint8_t)s->l; - gc->report.r = (uint8_t)s->r; - gc->report.z = (uint8_t)s->zr; - gc->report.start = (uint8_t)s->plus; - - bool servo_up = false; - if (j->_reset_state != s->home) - { - if (s->home == NTHAKA_BUTTON_PRESSED) - { - j->_reset_state = NTHAKA_BUTTON_PRESSED; - - j->_servo->write(65); - pinMode(j->_reset, OUTPUT); - digitalWrite(j->_reset, LOW); - - // For listed idx, use servo with blocking - for (size_t i = 0; i < j->_idx_servo_blocking_size; i++) - { - if (j->_idx_servo_blocking[i] == idx_from) - { - servo_up = true; - break; - } - } - } - else - { - j->_reset_state = NTHAKA_BUTTON_RELEASED; - - j->_servo->write(90); - pinMode(j->_reset, INPUT); - } - } - - switch (s->hat) - { - case NTHAKA_HAT_UP: - gc->report.dup = 1; - gc->report.dright = 0; - gc->report.ddown = 0; - gc->report.dleft = 0; - break; - case NTHAKA_HAT_UPRIGHT: - gc->report.dup = 1; - gc->report.dright = 1; - gc->report.ddown = 0; - gc->report.dleft = 0; - break; - case NTHAKA_HAT_RIGHT: - gc->report.dup = 0; - gc->report.dright = 1; - gc->report.ddown = 0; - gc->report.dleft = 0; - break; - case NTHAKA_HAT_DOWNRIGHT: - gc->report.dup = 0; - gc->report.dright = 1; - gc->report.ddown = 1; - gc->report.dleft = 0; - break; - case NTHAKA_HAT_DOWN: - gc->report.dup = 0; - gc->report.dright = 0; - gc->report.ddown = 1; - gc->report.dleft = 0; - break; - case NTHAKA_HAT_DOWNLEFT: - gc->report.dup = 0; - gc->report.dright = 0; - gc->report.ddown = 1; - gc->report.dleft = 1; - break; - case NTHAKA_HAT_LEFT: - gc->report.dup = 0; - gc->report.dright = 0; - gc->report.ddown = 0; - gc->report.dleft = 1; - break; - case NTHAKA_HAT_UPLEFT: - gc->report.dup = 1; - gc->report.dright = 0; - gc->report.ddown = 0; - gc->report.dleft = 1; - break; - case NTHAKA_HAT_NEUTRAL: - default: - gc->report.dup = 0; - gc->report.dright = 0; - gc->report.ddown = 0; - gc->report.dleft = 0; - break; - } - - // There are a few games that do not handle yAxis=0 and cyAxis=0 correctly. - gc->report.xAxis = s->l_stick.x; - uint8_t y_axis = 0xFF - s->l_stick.y; - gc->report.yAxis = y_axis == 0 ? 1 : y_axis; - - gc->report.cxAxis = s->r_stick.x; - uint8_t cy_axis = 0xFF - s->r_stick.y; - gc->report.cyAxis = cy_axis == 0 ? 1 : cy_axis; - - mutex_exit(j->_mtx); - - if (servo_up) - { - j->_reset_state = NTHAKA_BUTTON_RELEASED; - - delay(500); - j->_servo->write(90); - pinMode(j->_reset, INPUT); - delay(500); - } -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0a5f667..eb5cb03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include "pico/mutex.h" #include "hardware/timer.h" @@ -12,49 +14,81 @@ #include "nthaka/orca.h" #include "nthaka/pokecon.h" -#include "jiangtun.h" -#include "internal.h" - #ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 #define PIN_RESET D10 -#define PIN_GC D5 #define PIN_SERVO D6 - -#include +#define PIN_GAMECUBE D5 static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); - -inline void led_on() -{ - pixels.setPixelColor(0, pixels.Color(255, 255, 255)); - pixels.show(); -} - -inline void led_off() -{ - pixels.clear(); - pixels.show(); -} +#define initLED() \ + do \ + { \ + pinMode(PIN_LED_R, OUTPUT); \ + pinMode(PIN_LED_G, OUTPUT); \ + pinMode(PIN_LED_B, OUTPUT); \ + digitalWrite(PIN_LED_R, HIGH); \ + digitalWrite(PIN_LED_G, HIGH); \ + digitalWrite(PIN_LED_B, HIGH); \ + pixels.begin(); \ + pinMode(NEOPIXEL_POWER, OUTPUT); \ + digitalWrite(NEOPIXEL_POWER, HIGH); \ + } while (0) +#define turnOnLED() \ + do \ + { \ + pixels.setPixelColor(0, color); \ + pixels.show(); \ + } while (0) +#define turnOffLED() \ + do \ + { \ + pixels.clear(); \ + pixels.show(); \ + } while (0) #else // JIANGTUN_CONFIG_BOARD_PICO #define PIN_RESET 3 -#define PIN_GC 5 #define PIN_SERVO 6 +#define PIN_GAMECUBE 5 -#define led_on() (digitalWrite(LED_BUILTIN, HIGH)) -#define led_off() (digitalWrite(LED_BUILTIN, LOW)) +#define initLED() \ + do \ + { \ + pinMode(LED_BUILTIN, OUTPUT); \ + digitalWrite(LED_BUILTIN, LOW); \ + } while (0) +#define turnOnLED() (digitalWrite(LED_BUILTIN, HIGH)) +#define turnOffLED() (digitalWrite(LED_BUILTIN, LOW)) #endif -static jiangtun_t j; - static Servo servo; +static uint32_t color; +static uint16_t hue; + +typedef enum jiangtun_reset_action_t +{ + JIANGTUN_RESET_PRESS, + JIANGTUN_RESET_RELEASE, + JIANGTUN_RESET_PRESS_RELEASE, + JIANGTUN_RESET_NOTHING, +} jiangtun_reset_action_t; + +typedef struct jiangtun_gamecube_data_t +{ + Gamecube_Data_t gamecube; + nthaka_button_state_t current_reset_state; + jiangtun_reset_action_t next_action; +} jiangtun_gamecube_data_t; + static mutex_t mtx; -static CGamecubeConsole console(PIN_GC); -static Gamecube_Data_t gc = defaultGamecubeData; +static CGamecubeConsole gamecube(PIN_GAMECUBE); +static jiangtun_gamecube_data_t data = {.gamecube = defaultGamecubeData, + .current_reset_state = NTHAKA_BUTTON_RELEASED, + .next_action = JIANGTUN_RESET_NOTHING}; static dol_format_handler_t dol; static nxmc2_format_handler_t nxmc2; @@ -68,76 +102,226 @@ static nthaka_format_handler_t *fmts[] = {(nthaka_format_handler_t *)&nxmc2, (nthaka_format_handler_t *)&pokecon #endif // JIANGTUN_CONFIG_ENABLE_DOL }; -static size_t idx_servo_blocking[] = {1, +static size_t auto_reset_release_idx[] = {1, #ifdef JIANGTUN_CONFIG_ENABLE_DOL - 2 + 2 #endif // JIANGTUN_CONFIG_ENABLE_DOL }; +static size_t auto_reset_release_idx_size = sizeof(auto_reset_release_idx) / sizeof(auto_reset_release_idx[0]); static nthaka_multi_format_handler_t fmt; static nthaka_buffer_t buf; static nthaka_gamepad_state_t out; -static int64_t _led_off(alarm_id_t id, void *user_data) +static int64_t _turnOffLED(alarm_id_t _0, void *_1) { - led_off(); + turnOffLED(); return 0; } -static inline void async_led_on(uint32_t dur_ms) +static inline void blinkLEDAsync(uint32_t ms) { - led_on(); - add_alarm_in_ms(dur_ms, _led_off, NULL, false); + turnOnLED(); + add_alarm_in_ms(ms, _turnOffLED, NULL, false); } -void setup() +static inline void pressReset() { -#ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 + servo.write(65); + pinMode(PIN_RESET, OUTPUT); + digitalWrite(PIN_RESET, LOW); +} - pinMode(PIN_LED_R, OUTPUT); - pinMode(PIN_LED_G, OUTPUT); - pinMode(PIN_LED_B, OUTPUT); - digitalWrite(PIN_LED_R, HIGH); - digitalWrite(PIN_LED_G, HIGH); - digitalWrite(PIN_LED_B, HIGH); +static inline int64_t releaseReset(alarm_id_t _0, void *_1) +{ + servo.write(90); + pinMode(PIN_RESET, INPUT); - pinMode(NEOPIXEL_POWER, OUTPUT); - pinMode(NEOPIXEL_POWER, HIGH); + if (data.current_reset_state != NTHAKA_BUTTON_RELEASED) + { + mutex_enter_blocking(&mtx); + { + data.current_reset_state = NTHAKA_BUTTON_RELEASED; + } + mutex_exit(&mtx); + blinkLEDAsync(100); + } - pixels.begin(); + return 0; +} -#else // JIANGTUN_CONFIG_BOARD_PICO +static void updateData(nthaka_gamepad_state_t *state, size_t idx, size_t auto_reset_release_idx[], size_t auto_reset_release_idx_size, jiangtun_gamecube_data_t *data) +{ + // Update the reset state and determine the next reset action. + nthaka_button_state_t next_reset_state = state->home; + if (data->current_reset_state != next_reset_state) + { + if (next_reset_state == NTHAKA_BUTTON_PRESSED) + { + data->next_action = JIANGTUN_RESET_PRESS; + + for (size_t i = 0; i < auto_reset_release_idx_size; i++) + { + if (auto_reset_release_idx[i] == idx) + { + data->next_action = JIANGTUN_RESET_PRESS_RELEASE; + break; + } + } + } + else + { + data->next_action = JIANGTUN_RESET_RELEASE; + } + data->current_reset_state = next_reset_state; + } + else + { + data->next_action = JIANGTUN_RESET_NOTHING; + } - pinMode(PIN_LED_, OUTPUT); - digitalWrite(PIN_LED_, LOW); + data->gamecube.report.y = state->y == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.b = state->b == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.a = state->a == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.x = state->x == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.l = state->l == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.r = state->r == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.z = state->zr == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + data->gamecube.report.start = state->plus == NTHAKA_BUTTON_PRESSED ? 1U : 0U; -#endif + switch (state->hat) + { + case NTHAKA_HAT_UP: + data->gamecube.report.dup = 1U; + data->gamecube.report.dright = 0U; + data->gamecube.report.ddown = 0U; + data->gamecube.report.dleft = 0U; + break; + + case NTHAKA_HAT_UPRIGHT: + data->gamecube.report.dup = 1U; + data->gamecube.report.dright = 1U; + data->gamecube.report.ddown = 0U; + data->gamecube.report.dleft = 0U; + break; + + case NTHAKA_HAT_RIGHT: + data->gamecube.report.dup = 0U; + data->gamecube.report.dright = 1U; + data->gamecube.report.ddown = 0U; + data->gamecube.report.dleft = 0U; + break; + + case NTHAKA_HAT_DOWNRIGHT: + data->gamecube.report.dup = 0U; + data->gamecube.report.dright = 1U; + data->gamecube.report.ddown = 1U; + data->gamecube.report.dleft = 0U; + break; + + case NTHAKA_HAT_DOWN: + data->gamecube.report.dup = 0U; + data->gamecube.report.dright = 0U; + data->gamecube.report.ddown = 1U; + data->gamecube.report.dleft = 0U; + break; + + case NTHAKA_HAT_DOWNLEFT: + data->gamecube.report.dup = 0U; + data->gamecube.report.dright = 0U; + data->gamecube.report.ddown = 1U; + data->gamecube.report.dleft = 1U; + break; + + case NTHAKA_HAT_LEFT: + data->gamecube.report.dup = 0U; + data->gamecube.report.dright = 0U; + data->gamecube.report.ddown = 0U; + data->gamecube.report.dleft = 1U; + break; + + case NTHAKA_HAT_UPLEFT: + data->gamecube.report.dup = 1U; + data->gamecube.report.dright = 0U; + data->gamecube.report.ddown = 0U; + data->gamecube.report.dleft = 1U; + break; + + case NTHAKA_HAT_NEUTRAL: + default: + data->gamecube.report.dup = 0U; + data->gamecube.report.dright = 0U; + data->gamecube.report.ddown = 0U; + data->gamecube.report.dleft = 0U; + break; + } + + // There are a few games that do not handle yAxis=0 and cyAxis=0 correctly. + data->gamecube.report.xAxis = state->l_stick.x; + uint8_t y_axis = 0xFF - state->l_stick.y; + data->gamecube.report.yAxis = y_axis == 0U ? 1U : y_axis; + + data->gamecube.report.cxAxis = state->r_stick.x; + uint8_t cy_axis = 0xFF - state->r_stick.y; + data->gamecube.report.cyAxis = cy_axis == 0U ? 1U : cy_axis; +} + +static void initGamecube(CGamecubeConsole *console, jiangtun_gamecube_data_t *data) +{ + data->gamecube.report.a = 0; + data->gamecube.report.b = 0; + data->gamecube.report.x = 0; + data->gamecube.report.y = 0; + data->gamecube.report.start = 0; + data->gamecube.report.dleft = 0; + data->gamecube.report.dright = 0; + data->gamecube.report.ddown = 0; + data->gamecube.report.dup = 0; + data->gamecube.report.z = 0; + data->gamecube.report.r = 0; + data->gamecube.report.l = 0; + data->gamecube.report.xAxis = 128; + data->gamecube.report.yAxis = 128; + data->gamecube.report.cxAxis = 128; + data->gamecube.report.cyAxis = 128; + data->gamecube.report.left = 0; + data->gamecube.report.right = 0; + + // Magic spell to make the controller be recognized by the Gamecube + data->gamecube.report.start = 1; + console->write(data->gamecube); + data->gamecube.report.start = 0; + console->write(data->gamecube); + + data->current_reset_state = NTHAKA_BUTTON_RELEASED; + + data->next_action = JIANGTUN_RESET_NOTHING; +} + +void setup() +{ + mutex_init(&mtx); + mutex_enter_blocking(&mtx); + { + initGamecube(&gamecube, &data); + } + mutex_exit(&mtx); Serial.setTimeout(100); Serial.begin(9600); - pinMode(PIN_RESET, INPUT); // Hi-Z - - // Setup for SG90 servo.attach(PIN_SERVO, 500, 2400); servo.write(90); - mutex_init(&mtx); - - gc_console_data_init(&console, &gc, &mtx); + pinMode(PIN_RESET, INPUT); - if (!(dol_format_handler_init(&dol) && - nxmc2_format_handler_init(&nxmc2) && - orca_format_handler_init(&orca) && - pokecon_format_handler_init(&pokecon) && - nthaka_multi_format_handler_init(&fmt, fmts, 3) && - nthaka_buffer_init(&buf, (nthaka_format_handler_t *)&fmt) && + initLED(); - jiangtun_init(&j, PIN_RESET, &servo, idx_servo_blocking, sizeof(idx_servo_blocking) / sizeof(size_t), &mtx))) - { - led_on(); - while (true) - ; - } + dol_format_handler_init(&dol); + nxmc2_format_handler_init(&nxmc2); + orca_format_handler_init(&orca); + pokecon_format_handler_init(&pokecon); + nthaka_multi_format_handler_init(&fmt, fmts, 3); + nthaka_buffer_init(&buf, (nthaka_format_handler_t *)&fmt); } void loop() @@ -158,11 +342,18 @@ void loop() size_t *idx = nthaka_multi_format_handler_get_last_deserialized_index(&fmt); if (idx == NULL) { + // Unreachable code *idx = 0; } - async_led_on(500); - jiangtun_update(&j, &out, *idx, &gc); + blinkLEDAsync(100); + + mutex_enter_blocking(&mtx); + { + updateData(&out, *idx, auto_reset_release_idx, auto_reset_release_idx_size, &data); + } + mutex_exit(&mtx); + nthaka_buffer_clear(&buf); } @@ -173,8 +364,36 @@ void setup1() void loop1() { + color = Adafruit_NeoPixel::ColorHSV(hue); + hue += 16; + + bool ret; + mutex_enter_blocking(&mtx); - bool ret = console.write(gc); + { + ret = gamecube.write(data.gamecube); + + switch (data.next_action) + { + case JIANGTUN_RESET_PRESS: + pressReset(); + break; + + case JIANGTUN_RESET_RELEASE: + releaseReset(0, NULL); + break; + + case JIANGTUN_RESET_PRESS_RELEASE: + pressReset(); + add_alarm_in_ms(500, releaseReset, NULL, false); + break; + + case JIANGTUN_RESET_NOTHING: + default: + break; + } + data.next_action = JIANGTUN_RESET_NOTHING; + } mutex_exit(&mtx); if (!ret) From 51816aa61f5ab80c0a33c661087c542c6254eb67 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Wed, 7 Feb 2024 22:40:48 +0900 Subject: [PATCH 09/25] Separate core clearly --- src/jiangtun.h | 35 +++++ src/main.cpp | 388 +++++++++++++++++++++++++------------------------ 2 files changed, 233 insertions(+), 190 deletions(-) create mode 100644 src/jiangtun.h diff --git a/src/jiangtun.h b/src/jiangtun.h new file mode 100644 index 0000000..d9d0034 --- /dev/null +++ b/src/jiangtun.h @@ -0,0 +1,35 @@ +#ifndef JIANGTUN_H_ +#define JIANGTUN_H_ + +#include + +#include + +#include "Bluewhale.h" +#include "nthaka.h" + +namespace jiangtun +{ + + enum class ResetAction + { + Press, + Release, + PressRelease, + Nothing + }; + + struct State + { + Gamecube_Data_t gc_data; + nthaka_button_state_t gc_reset; + + ResetAction next_action; + + uint16_t hue; + uint32_t color; + }; + +} + +#endif // JIANGTUN_H_ \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index eb5cb03..b8c021e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,8 @@ #include "nthaka/orca.h" #include "nthaka/pokecon.h" +#include "jiangtun.h" + #ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 #define PIN_RESET D10 @@ -34,11 +36,11 @@ static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); pinMode(NEOPIXEL_POWER, OUTPUT); \ digitalWrite(NEOPIXEL_POWER, HIGH); \ } while (0) -#define turnOnLED() \ - do \ - { \ - pixels.setPixelColor(0, color); \ - pixels.show(); \ +#define turnOnLED(color) \ + do \ + { \ + pixels.setPixelColor(0, (color)); \ + pixels.show(); \ } while (0) #define turnOffLED() \ do \ @@ -59,36 +61,32 @@ static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); pinMode(LED_BUILTIN, OUTPUT); \ digitalWrite(LED_BUILTIN, LOW); \ } while (0) -#define turnOnLED() (digitalWrite(LED_BUILTIN, HIGH)) +#define turnOnLED(_) (digitalWrite(LED_BUILTIN, HIGH)) #define turnOffLED() (digitalWrite(LED_BUILTIN, LOW)) #endif -static Servo servo; - -static uint32_t color; -static uint16_t hue; - -typedef enum jiangtun_reset_action_t -{ - JIANGTUN_RESET_PRESS, - JIANGTUN_RESET_RELEASE, - JIANGTUN_RESET_PRESS_RELEASE, - JIANGTUN_RESET_NOTHING, -} jiangtun_reset_action_t; - -typedef struct jiangtun_gamecube_data_t -{ - Gamecube_Data_t gamecube; - nthaka_button_state_t current_reset_state; - jiangtun_reset_action_t next_action; -} jiangtun_gamecube_data_t; - static mutex_t mtx; -static CGamecubeConsole gamecube(PIN_GAMECUBE); -static jiangtun_gamecube_data_t data = {.gamecube = defaultGamecubeData, - .current_reset_state = NTHAKA_BUTTON_RELEASED, - .next_action = JIANGTUN_RESET_NOTHING}; +jiangtun::State state{.gc_data = defaultGamecubeData, + .gc_reset = NTHAKA_BUTTON_RELEASED, + .next_action = jiangtun::ResetAction::Nothing, + .hue = 0, + .color = Adafruit_NeoPixel::ColorHSV(0)}; + +/************************************************************************* + ** ** + ** .oooo. ** + ** d8P'`Y8b ** + ** .ooooo. .ooooo. oooo d8b .ooooo. 888 888 ** + ** d88' `"Y8 d88' `88b `888""8P d88' `88b 888 888 ** + ** 888 888 888 888 888ooo888 888 888 ** + ** 888 .o8 888 888 888 888 .o `88b d88' ** + ** `Y8bod8P' `Y8bod8P' d888b `Y8bod8P' `Y8bd8P' ** + ** ** + ** ** + ** ** + *************************************************************************/ +// figlet -t -f roman core0 static dol_format_handler_t dol; static nxmc2_format_handler_t nxmc2; @@ -110,7 +108,6 @@ static size_t auto_reset_release_idx[] = {1, static size_t auto_reset_release_idx_size = sizeof(auto_reset_release_idx) / sizeof(auto_reset_release_idx[0]); static nthaka_multi_format_handler_t fmt; static nthaka_buffer_t buf; -static nthaka_gamepad_state_t out; static int64_t _turnOffLED(alarm_id_t _0, void *_1) { @@ -118,202 +115,136 @@ static int64_t _turnOffLED(alarm_id_t _0, void *_1) return 0; } -static inline void blinkLEDAsync(uint32_t ms) +static inline void blinkLEDAsync() { - turnOnLED(); - add_alarm_in_ms(ms, _turnOffLED, NULL, false); -} - -static inline void pressReset() -{ - servo.write(65); - pinMode(PIN_RESET, OUTPUT); - digitalWrite(PIN_RESET, LOW); -} - -static inline int64_t releaseReset(alarm_id_t _0, void *_1) -{ - servo.write(90); - pinMode(PIN_RESET, INPUT); - - if (data.current_reset_state != NTHAKA_BUTTON_RELEASED) - { - mutex_enter_blocking(&mtx); - { - data.current_reset_state = NTHAKA_BUTTON_RELEASED; - } - mutex_exit(&mtx); - blinkLEDAsync(100); - } - - return 0; + turnOnLED(state.color); + add_alarm_in_ms(100, _turnOffLED, nullptr, false); } -static void updateData(nthaka_gamepad_state_t *state, size_t idx, size_t auto_reset_release_idx[], size_t auto_reset_release_idx_size, jiangtun_gamecube_data_t *data) +static void updateState(nthaka_gamepad_state_t &gamepad, size_t idx) { // Update the reset state and determine the next reset action. - nthaka_button_state_t next_reset_state = state->home; - if (data->current_reset_state != next_reset_state) + nthaka_button_state_t next_reset_state = gamepad.home; + if (state.gc_reset != next_reset_state) { if (next_reset_state == NTHAKA_BUTTON_PRESSED) { - data->next_action = JIANGTUN_RESET_PRESS; + state.next_action = jiangtun::ResetAction::Press; for (size_t i = 0; i < auto_reset_release_idx_size; i++) { if (auto_reset_release_idx[i] == idx) { - data->next_action = JIANGTUN_RESET_PRESS_RELEASE; + state.next_action = jiangtun::ResetAction::PressRelease; break; } } } else { - data->next_action = JIANGTUN_RESET_RELEASE; + state.next_action = jiangtun::ResetAction::Release; } - data->current_reset_state = next_reset_state; + state.gc_reset = next_reset_state; } else { - data->next_action = JIANGTUN_RESET_NOTHING; + state.next_action = jiangtun::ResetAction::Nothing; } - data->gamecube.report.y = state->y == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.b = state->b == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.a = state->a == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.x = state->x == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.l = state->l == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.r = state->r == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.z = state->zr == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - data->gamecube.report.start = state->plus == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - - switch (state->hat) + // Convert nthaka_gamepad_state_t to Gamecube_Data_t + state.gc_data.report.y = gamepad.y == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.b = gamepad.b == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.a = gamepad.a == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.x = gamepad.x == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.l = gamepad.l == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.r = gamepad.r == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.z = gamepad.zr == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + state.gc_data.report.start = gamepad.plus == NTHAKA_BUTTON_PRESSED ? 1U : 0U; + + switch (gamepad.hat) { case NTHAKA_HAT_UP: - data->gamecube.report.dup = 1U; - data->gamecube.report.dright = 0U; - data->gamecube.report.ddown = 0U; - data->gamecube.report.dleft = 0U; + state.gc_data.report.dup = 1U; + state.gc_data.report.dright = 0U; + state.gc_data.report.ddown = 0U; + state.gc_data.report.dleft = 0U; break; case NTHAKA_HAT_UPRIGHT: - data->gamecube.report.dup = 1U; - data->gamecube.report.dright = 1U; - data->gamecube.report.ddown = 0U; - data->gamecube.report.dleft = 0U; + state.gc_data.report.dup = 1U; + state.gc_data.report.dright = 1U; + state.gc_data.report.ddown = 0U; + state.gc_data.report.dleft = 0U; break; case NTHAKA_HAT_RIGHT: - data->gamecube.report.dup = 0U; - data->gamecube.report.dright = 1U; - data->gamecube.report.ddown = 0U; - data->gamecube.report.dleft = 0U; + state.gc_data.report.dup = 0U; + state.gc_data.report.dright = 1U; + state.gc_data.report.ddown = 0U; + state.gc_data.report.dleft = 0U; break; case NTHAKA_HAT_DOWNRIGHT: - data->gamecube.report.dup = 0U; - data->gamecube.report.dright = 1U; - data->gamecube.report.ddown = 1U; - data->gamecube.report.dleft = 0U; + state.gc_data.report.dup = 0U; + state.gc_data.report.dright = 1U; + state.gc_data.report.ddown = 1U; + state.gc_data.report.dleft = 0U; break; case NTHAKA_HAT_DOWN: - data->gamecube.report.dup = 0U; - data->gamecube.report.dright = 0U; - data->gamecube.report.ddown = 1U; - data->gamecube.report.dleft = 0U; + state.gc_data.report.dup = 0U; + state.gc_data.report.dright = 0U; + state.gc_data.report.ddown = 1U; + state.gc_data.report.dleft = 0U; break; case NTHAKA_HAT_DOWNLEFT: - data->gamecube.report.dup = 0U; - data->gamecube.report.dright = 0U; - data->gamecube.report.ddown = 1U; - data->gamecube.report.dleft = 1U; + state.gc_data.report.dup = 0U; + state.gc_data.report.dright = 0U; + state.gc_data.report.ddown = 1U; + state.gc_data.report.dleft = 1U; break; case NTHAKA_HAT_LEFT: - data->gamecube.report.dup = 0U; - data->gamecube.report.dright = 0U; - data->gamecube.report.ddown = 0U; - data->gamecube.report.dleft = 1U; + state.gc_data.report.dup = 0U; + state.gc_data.report.dright = 0U; + state.gc_data.report.ddown = 0U; + state.gc_data.report.dleft = 1U; break; case NTHAKA_HAT_UPLEFT: - data->gamecube.report.dup = 1U; - data->gamecube.report.dright = 0U; - data->gamecube.report.ddown = 0U; - data->gamecube.report.dleft = 1U; + state.gc_data.report.dup = 1U; + state.gc_data.report.dright = 0U; + state.gc_data.report.ddown = 0U; + state.gc_data.report.dleft = 1U; break; case NTHAKA_HAT_NEUTRAL: default: - data->gamecube.report.dup = 0U; - data->gamecube.report.dright = 0U; - data->gamecube.report.ddown = 0U; - data->gamecube.report.dleft = 0U; + state.gc_data.report.dup = 0U; + state.gc_data.report.dright = 0U; + state.gc_data.report.ddown = 0U; + state.gc_data.report.dleft = 0U; break; } // There are a few games that do not handle yAxis=0 and cyAxis=0 correctly. - data->gamecube.report.xAxis = state->l_stick.x; - uint8_t y_axis = 0xFF - state->l_stick.y; - data->gamecube.report.yAxis = y_axis == 0U ? 1U : y_axis; + state.gc_data.report.xAxis = gamepad.l_stick.x; + uint8_t y_axis = 0xFF - gamepad.l_stick.y; + state.gc_data.report.yAxis = y_axis == 0U ? 1U : y_axis; - data->gamecube.report.cxAxis = state->r_stick.x; - uint8_t cy_axis = 0xFF - state->r_stick.y; - data->gamecube.report.cyAxis = cy_axis == 0U ? 1U : cy_axis; -} - -static void initGamecube(CGamecubeConsole *console, jiangtun_gamecube_data_t *data) -{ - data->gamecube.report.a = 0; - data->gamecube.report.b = 0; - data->gamecube.report.x = 0; - data->gamecube.report.y = 0; - data->gamecube.report.start = 0; - data->gamecube.report.dleft = 0; - data->gamecube.report.dright = 0; - data->gamecube.report.ddown = 0; - data->gamecube.report.dup = 0; - data->gamecube.report.z = 0; - data->gamecube.report.r = 0; - data->gamecube.report.l = 0; - data->gamecube.report.xAxis = 128; - data->gamecube.report.yAxis = 128; - data->gamecube.report.cxAxis = 128; - data->gamecube.report.cyAxis = 128; - data->gamecube.report.left = 0; - data->gamecube.report.right = 0; - - // Magic spell to make the controller be recognized by the Gamecube - data->gamecube.report.start = 1; - console->write(data->gamecube); - data->gamecube.report.start = 0; - console->write(data->gamecube); - - data->current_reset_state = NTHAKA_BUTTON_RELEASED; - - data->next_action = JIANGTUN_RESET_NOTHING; + state.gc_data.report.cxAxis = gamepad.r_stick.x; + uint8_t cy_axis = 0xFF - gamepad.r_stick.y; + state.gc_data.report.cyAxis = cy_axis == 0U ? 1U : cy_axis; } void setup() { mutex_init(&mtx); - mutex_enter_blocking(&mtx); - { - initGamecube(&gamecube, &data); - } - mutex_exit(&mtx); Serial.setTimeout(100); Serial.begin(9600); - servo.attach(PIN_SERVO, 500, 2400); - servo.write(90); - - pinMode(PIN_RESET, INPUT); - initLED(); dol_format_handler_init(&dol); @@ -326,10 +257,12 @@ void setup() void loop() { - uint8_t d; + static nthaka_gamepad_state_t out; + + uint8_t in; nthaka_buffer_state_t s; - if (Serial.readBytes(&d, 1) != 1 || - (s = nthaka_buffer_append(&buf, d, &out)) == NTHAKA_BUFFER_REJECTED) + if (Serial.readBytes(&in, 1) != 1 || + (s = nthaka_buffer_append(&buf, in, &out)) == NTHAKA_BUFFER_REJECTED) { nthaka_buffer_clear(&buf); return; @@ -339,65 +272,140 @@ void loop() return; } - size_t *idx = nthaka_multi_format_handler_get_last_deserialized_index(&fmt); - if (idx == NULL) - { - // Unreachable code - *idx = 0; - } - - blinkLEDAsync(100); + size_t *idx_ = nthaka_multi_format_handler_get_last_deserialized_index(&fmt); + size_t idx = idx_ != nullptr ? *idx_ : 0; mutex_enter_blocking(&mtx); { - updateData(&out, *idx, auto_reset_release_idx, auto_reset_release_idx_size, &data); + blinkLEDAsync(); + updateState(out, idx); } mutex_exit(&mtx); nthaka_buffer_clear(&buf); } +/************************************************************************* + ** ** + ** .o ** + ** o888 ** + ** .ooooo. .ooooo. oooo d8b .ooooo. 888 ** + ** d88' `"Y8 d88' `88b `888""8P d88' `88b 888 ** + ** 888 888 888 888 888ooo888 888 ** + ** 888 .o8 888 888 888 888 .o 888 ** + ** `Y8bod8P' `Y8bod8P' d888b `Y8bod8P' o888o ** + ** ** + ** ** + ** ** + *************************************************************************/ +// figlet -t -f roman core1 + +static CGamecubeConsole gamecube(PIN_GAMECUBE); + +static Servo servo; + +static void initGamecube(CGamecubeConsole &console, jiangtun::State &state) +{ + state.gc_data.report.a = 0; + state.gc_data.report.b = 0; + state.gc_data.report.x = 0; + state.gc_data.report.y = 0; + state.gc_data.report.start = 0; + state.gc_data.report.dleft = 0; + state.gc_data.report.dright = 0; + state.gc_data.report.ddown = 0; + state.gc_data.report.dup = 0; + state.gc_data.report.z = 0; + state.gc_data.report.r = 0; + state.gc_data.report.l = 0; + state.gc_data.report.xAxis = 128; + state.gc_data.report.yAxis = 128; + state.gc_data.report.cxAxis = 128; + state.gc_data.report.cyAxis = 128; + state.gc_data.report.left = 0; + state.gc_data.report.right = 0; + + // Magic spell to make the controller be recognized by the Gamecube + state.gc_data.report.start = 1; + console.write(state.gc_data); + state.gc_data.report.start = 0; + console.write(state.gc_data); +} + +static inline void pressReset() +{ + servo.write(65); + pinMode(PIN_RESET, OUTPUT); + digitalWrite(PIN_RESET, LOW); +} + +static inline int64_t releaseReset(alarm_id_t _0, void *_1) +{ + servo.write(90); + pinMode(PIN_RESET, INPUT); + + if (state.gc_reset != NTHAKA_BUTTON_RELEASED) + { + mutex_enter_blocking(&mtx); + { + state.gc_reset = NTHAKA_BUTTON_RELEASED; + blinkLEDAsync(); + } + mutex_exit(&mtx); + } + + return 0; +} + void setup1() { + // Wait `mutex_init(&mtx);` delay(10); + + mutex_enter_blocking(&mtx); + { + initGamecube(gamecube, state); + } + mutex_exit(&mtx); + + servo.attach(PIN_SERVO, 500, 2400); + pinMode(PIN_RESET, INPUT); + releaseReset(0, nullptr); } void loop1() { - color = Adafruit_NeoPixel::ColorHSV(hue); - hue += 16; - bool ret; mutex_enter_blocking(&mtx); { - ret = gamecube.write(data.gamecube); + // This would be a useless calculation for JIANGTUN_CONFIG_BOARD_PICO, + // but it is intentionally left out to avoid making a difference in processing time. + state.color = Adafruit_NeoPixel::ColorHSV(state.hue); + state.hue += 16; + + ret = gamecube.write(state.gc_data); - switch (data.next_action) + switch (state.next_action) { - case JIANGTUN_RESET_PRESS: + case jiangtun::ResetAction::Press: pressReset(); break; - case JIANGTUN_RESET_RELEASE: - releaseReset(0, NULL); + case jiangtun::ResetAction::Release: + releaseReset(0, nullptr); break; - case JIANGTUN_RESET_PRESS_RELEASE: + case jiangtun::ResetAction::PressRelease: pressReset(); - add_alarm_in_ms(500, releaseReset, NULL, false); + add_alarm_in_ms(500, releaseReset, nullptr, false); break; - case JIANGTUN_RESET_NOTHING: + case jiangtun::ResetAction::Nothing: default: break; } - data.next_action = JIANGTUN_RESET_NOTHING; + state.next_action = jiangtun::ResetAction::Nothing; } mutex_exit(&mtx); - - if (!ret) - { - Serial.println("GC is not powered on or not connected."); - } } \ No newline at end of file From 41d103cd69f2af4839aa3c311e0637f29bab3548 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Wed, 7 Feb 2024 22:43:55 +0900 Subject: [PATCH 10/25] Update Makefile --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 6114444..6aae3e7 100644 --- a/Makefile +++ b/Makefile @@ -12,16 +12,16 @@ else PIO = $(HOME)/.platformio/penv/bin/platformio endif -.pio/build/pico/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h +.pio/build/pico/firmware.uf2: src/main.cpp src/jiangtun.h $(PIO) run --environment pico -.pio/build/dol-pico/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h +.pio/build/dol-pico/firmware.uf2: src/main.cpp src/jiangtun.h $(PIO) run --environment dol-pico -.pio/build/xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h +.pio/build/xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.h $(PIO) run --environment xiao-rp2040 -.pio/build/dol-xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.cpp src/internal.h include/jiangtun.h +.pio/build/dol-xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.h $(PIO) run --environment dol-xiao-rp2040 dist: From fb49ddbb45226a14f6d111a562e2d0971ea5d0eb Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Wed, 7 Feb 2024 22:52:54 +0900 Subject: [PATCH 11/25] Update Makefile --- Makefile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 6aae3e7..37c2ee2 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,8 @@ else PIO = $(HOME)/.platformio/penv/bin/platformio endif +VERSION = v2.0.0-alpha + .pio/build/pico/firmware.uf2: src/main.cpp src/jiangtun.h $(PIO) run --environment pico @@ -27,19 +29,19 @@ endif dist: mkdir dist -dist/jiangtun-pico.uf2: .pio/build/pico/firmware.uf2 dist +dist/jiangtun-$(VERSION)-pico.uf2: .pio/build/pico/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -dist/jiangtun-dol-pico.uf2: .pio/build/dol-pico/firmware.uf2 dist +dist/jiangtun-$(VERSION)-dol-pico.uf2: .pio/build/dol-pico/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -dist/jiangtun-xiao-rp2040.uf2: .pio/build/xiao-rp2040/firmware.uf2 dist +dist/jiangtun-$(VERSION)-xiao-rp2040.uf2: .pio/build/xiao-rp2040/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -dist/jiangtun-dol-xiao-rp2040.uf2: .pio/build/dol-xiao-rp2040/firmware.uf2 dist +dist/jiangtun-$(VERSION)-dol-xiao-rp2040.uf2: .pio/build/dol-xiao-rp2040/firmware.uf2 dist $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) -all: dist/jiangtun-pico.uf2 dist/jiangtun-dol-pico.uf2 dist/jiangtun-xiao-rp2040.uf2 dist/jiangtun-dol-xiao-rp2040.uf2 +all: dist/jiangtun-$(VERSION)-pico.uf2 dist/jiangtun-$(VERSION)-dol-pico.uf2 dist/jiangtun-$(VERSION)-xiao-rp2040.uf2 dist/jiangtun-$(VERSION)-dol-xiao-rp2040.uf2 clean: $(RM) $(call FIXPATH,dist/*) From b17266549a49463a8a8629248c0e869962a5f71a Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Tue, 1 Oct 2024 00:37:21 +0900 Subject: [PATCH 12/25] Introduce new core --- lib/jiangtun-core/.clang-format | 4 + lib/jiangtun-core/.gitignore | 14 + lib/jiangtun-core/CMakeLists.txt | 18 + lib/jiangtun-core/Dockerfile.flex | 12 + lib/jiangtun-core/include/jiangtun.h | 20 + lib/jiangtun-core/include/jiangtun/compat.h | 39 + lib/jiangtun-core/include/jiangtun/error.h | 22 + lib/jiangtun-core/include/jiangtun/lexer.h | 47 + lib/jiangtun-core/include/jiangtun/parse.h | 36 + lib/jiangtun-core/include/jiangtun/report.h | 237 +++ lib/jiangtun-core/library.properties | 10 + lib/jiangtun-core/src/error.c | 23 + lib/jiangtun-core/src/lex.yy.c | 2087 +++++++++++++++++++ lib/jiangtun-core/src/lex.yy.extern.h | 23 + lib/jiangtun-core/src/lex.yy.h | 492 +++++ lib/jiangtun-core/src/lexer.c | 110 + lib/jiangtun-core/src/lexer.l | 96 + lib/jiangtun-core/src/nxmc2.c | 118 ++ lib/jiangtun-core/src/pokecon.c | 228 ++ lib/jiangtun-core/src/report.c | 44 + lib/jiangtun-core/test/lexer.c | 345 +++ 21 files changed, 4025 insertions(+) create mode 100644 lib/jiangtun-core/.clang-format create mode 100644 lib/jiangtun-core/.gitignore create mode 100644 lib/jiangtun-core/CMakeLists.txt create mode 100644 lib/jiangtun-core/Dockerfile.flex create mode 100644 lib/jiangtun-core/include/jiangtun.h create mode 100644 lib/jiangtun-core/include/jiangtun/compat.h create mode 100644 lib/jiangtun-core/include/jiangtun/error.h create mode 100644 lib/jiangtun-core/include/jiangtun/lexer.h create mode 100644 lib/jiangtun-core/include/jiangtun/parse.h create mode 100644 lib/jiangtun-core/include/jiangtun/report.h create mode 100644 lib/jiangtun-core/library.properties create mode 100644 lib/jiangtun-core/src/error.c create mode 100644 lib/jiangtun-core/src/lex.yy.c create mode 100644 lib/jiangtun-core/src/lex.yy.extern.h create mode 100644 lib/jiangtun-core/src/lex.yy.h create mode 100644 lib/jiangtun-core/src/lexer.c create mode 100644 lib/jiangtun-core/src/lexer.l create mode 100644 lib/jiangtun-core/src/nxmc2.c create mode 100644 lib/jiangtun-core/src/pokecon.c create mode 100644 lib/jiangtun-core/src/report.c create mode 100644 lib/jiangtun-core/test/lexer.c diff --git a/lib/jiangtun-core/.clang-format b/lib/jiangtun-core/.clang-format new file mode 100644 index 0000000..38c747e --- /dev/null +++ b/lib/jiangtun-core/.clang-format @@ -0,0 +1,4 @@ +--- +BasedOnStyle: LLVM +IndentWidth: 4 +... diff --git a/lib/jiangtun-core/.gitignore b/lib/jiangtun-core/.gitignore new file mode 100644 index 0000000..287ad21 --- /dev/null +++ b/lib/jiangtun-core/.gitignore @@ -0,0 +1,14 @@ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json +build +.vscode diff --git a/lib/jiangtun-core/CMakeLists.txt b/lib/jiangtun-core/CMakeLists.txt new file mode 100644 index 0000000..bd1b8ff --- /dev/null +++ b/lib/jiangtun-core/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.10) + +set(CMAKE_VERBOSE_MAKEFILE ON) + +project(jiangtun-core VERSION 0.1.0) +set(CMAKE_C_STANDARD 90) + +file(GLOB_RECURSE SRC_FILES src/*.c) +add_library(jiangtun-core STATIC ${SRC_FILES}) +target_include_directories(jiangtun-core PUBLIC include) +target_compile_options(jiangtun-core PRIVATE -Wall -Wextra -Wpedantic -Werror) + +enable_testing() + +add_executable(jiangtun-core_test_lexer test/lexer.c) +target_link_libraries(jiangtun-core_test_lexer jiangtun-core) +target_compile_options(jiangtun-core_test_lexer PRIVATE -Wall -Wextra -Wpedantic -Werror) +add_test(NAME jiangtun-core_test_lexer COMMAND jiangtun-core_test_lexer) diff --git a/lib/jiangtun-core/Dockerfile.flex b/lib/jiangtun-core/Dockerfile.flex new file mode 100644 index 0000000..7b6bfcc --- /dev/null +++ b/lib/jiangtun-core/Dockerfile.flex @@ -0,0 +1,12 @@ +FROM ubuntu:24.04 + +# ``` +# $ docker build --tag flex:2.6.4-8.2build1 --file .\Dockerfile.flex . +# ``` + +RUN apt-get update && apt-get install --yes \ + # apt list -a flex + flex=2.6.4-8.2build1 \ + && rm -rf /var/lib/apt/lists/* + +ENTRYPOINT [ "flex" ] \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun.h b/lib/jiangtun-core/include/jiangtun.h new file mode 100644 index 0000000..8494c0f --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun.h @@ -0,0 +1,20 @@ +#ifndef JIANGTUN_H +#define JIANGTUN_H + +#include "jiangtun/compat.h" +#include "jiangtun/error.h" +#include "jiangtun/lexer.h" +#include "jiangtun/parse.h" +#include "jiangtun/report.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_H */ diff --git a/lib/jiangtun-core/include/jiangtun/compat.h b/lib/jiangtun-core/include/jiangtun/compat.h new file mode 100644 index 0000000..7f7cfe2 --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/compat.h @@ -0,0 +1,39 @@ +#ifndef JIANGTUN_COMPAT_H +#define JIANGTUN_COMPAT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum jiangtun_bool_t { JIANGTUN_FALSE, JIANGTUN_TRUE } jiangtun_bool_t; + +typedef unsigned char jiangtun_uint8_t; + +#if USHRT_MAX == 0xFFFF +typedef unsigned short jiangtun_uint16_t; +#elif UINT_MAX == 0xFFFF +typedef unsigned int jiangtun_uint16_t; +#elif ULONG_MAX == 0xFFFF +typedef unsigned long jiangtun_uint16_t; +#else +#error "No suitable type for jiangtun_uint16_t" +#endif + +#if UINT_MAX == 0xFFFFFFFF +typedef unsigned int jiangtun_uint32_t; +#elif ULONG_MAX == 0xFFFFFFFF +typedef unsigned long jiangtun_uint32_t; +#elif ULLONG_MAX == 0xFFFFFFFF +typedef unsigned long long jiangtun_uint32_t; +#else +#error "No suitable type for jiangtun_uint32_t" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_COMPAT_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/error.h b/lib/jiangtun-core/include/jiangtun/error.h new file mode 100644 index 0000000..efd1cf8 --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/error.h @@ -0,0 +1,22 @@ +#ifndef JIANGTUN_ERROR_H +#define JIANGTUN_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum jiangtun_error_t { + JIANGTUN_SUCCESS, + JIANGTUN_ERROR_NULL_POINTER, + JIANGTUN_ERROR_INVALID_ARGUMENT, + JIANGTUN_ERROR_PARSE_FAILURE, + JIANGTUN_ERROR_INTERNAL +} jiangtun_error_t; + +const char *jiangtun_error_stringify(jiangtun_error_t); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_ERROR_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/lexer.h b/lib/jiangtun-core/include/jiangtun/lexer.h new file mode 100644 index 0000000..91b8898 --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/lexer.h @@ -0,0 +1,47 @@ +#ifndef JIANGTUN_LEXER_H +#define JIANGTUN_LEXER_H + +#include "compat.h" +#include "error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum jiangtun_yy_match_t { + JIANGTUN_YY_NO_MATCH, + JIANGTUN_YY_MATCH_NXMC2, + JIANGTUN_YY_MATCH_POKECON, + JIANGTUN_YY_MATCH_ORCA +} jiangtun_yy_match_t; + +typedef struct jiangtun_yy_extra_t { + jiangtun_bool_t partial; + jiangtun_yy_match_t return_; +} jiangtun_yy_extra_t; + +typedef struct jiangtun_lexer_t { + void *scanner; + jiangtun_yy_extra_t extra; +} jiangtun_lexer_t; + +typedef enum jiangtun_lexer_result_t { + JIANGTUN_LEXER_NO_MATCH, + JIANGTUN_LEXER_MATCH_PARTIAL, + JIANGTUN_LEXER_MATCH_NXMC2, + JIANGTUN_LEXER_MATCH_POKECON, + JIANGTUN_LEXER_MATCH_ORCA +} jiangtun_lexer_result_t; + +const char *jiangtun_lexer_result_stringify(jiangtun_lexer_result_t); + +jiangtun_error_t jiangtun_lexer_init(jiangtun_lexer_t *); +jiangtun_error_t jiangtun_lexer_deinit(jiangtun_lexer_t *); +jiangtun_error_t jiangtun_lex(jiangtun_lexer_t *, const jiangtun_uint8_t *, + size_t, jiangtun_lexer_result_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_LEXER_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/parse.h b/lib/jiangtun-core/include/jiangtun/parse.h new file mode 100644 index 0000000..19dce33 --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/parse.h @@ -0,0 +1,36 @@ +#ifndef JIANGTUN_PARSE_H +#define JIANGTUN_PARSE_H + +#include "compat.h" +#include "error.h" +#include "report.h" + +#ifdef __cplusplus +extern "C" { +#endif + +jiangtun_error_t jiangtun_nxmc2_parse(const jiangtun_uint8_t *, size_t, + jiangtun_report_t *, jiangtun_bool_t *); + +typedef struct jiangtun_pokecon_previous_state_t { + struct { + jiangtun_uint8_t x; + jiangtun_uint8_t y; + } left; + struct { + jiangtun_uint8_t x; + jiangtun_uint8_t y; + } right; +} jiangtun_pokecon_previous_state_t; + +jiangtun_error_t +jiangtun_pokecon_previous_state_init(jiangtun_pokecon_previous_state_t *); +jiangtun_error_t jiangtun_pokecon_parse(const jiangtun_uint8_t *, size_t, + jiangtun_report_t *, jiangtun_bool_t *, + jiangtun_pokecon_previous_state_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_PARSE_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/report.h b/lib/jiangtun-core/include/jiangtun/report.h new file mode 100644 index 0000000..2b3d59b --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/report.h @@ -0,0 +1,237 @@ +#ifndef JIANGTUN_REPORT_H +#define JIANGTUN_REPORT_H + +#include "compat.h" +#include "error.h" + +/* + * These codes actually depend on the PODs defined in `Bluewhale.h`. + */ +#ifdef ARDUINO +#include +#if __cplusplus >= 201103L +#include +static_assert(std::is_trivially_copyable::value, + "Gamecube_Report_t must be a POD type"); +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/** + * Equivalent data structure to `Bluewhale::Gamecube_Report_t` at the source + * code level, for ease of testing from pure C code. Please take a diff and + * update this if Bluewhale is changed. + * + * `$ diff -u --minimal <(sed -n '31,217p' include/jiangtun/report.h) <(sed -n '48,234p' lib/Bluewhale/src/Gamecube.h)` + */ +typedef union jiangtun_report_t { + /* 8 bytes of datareport that we get from the controller */ + jiangtun_uint8_t raw8[8]; + /* jiangtun_uint16_t raw16[0]; - ISO C forbids zero-size array */ + /* jiangtun_uint32_t raw32[0]; - ISO C forbids zero-size array */ + + struct { + jiangtun_uint8_t buttons0; + union { + jiangtun_uint8_t buttons1; + jiangtun_uint8_t dpad/* : 4 - type of bit-field ~ is a GCC extension*/; + } unnamed_0; /* - ISO C90 doesn't support unnamed structs/unions */ + } unnamed_1; + + struct { + /* first data byte (bitfields are sorted in LSB order) */ + jiangtun_uint8_t a/* : 1 */; + jiangtun_uint8_t b/* : 1 */; + jiangtun_uint8_t x/* : 1 */; + jiangtun_uint8_t y/* : 1 */; + jiangtun_uint8_t start/* : 1 */; + jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ + jiangtun_uint8_t errlatch/* : 1 */; + jiangtun_uint8_t errstat/* : 1 */; + + /* second data byte */ + jiangtun_uint8_t dleft/* : 1 */; + jiangtun_uint8_t dright/* : 1 */; + jiangtun_uint8_t ddown/* : 1 */; + jiangtun_uint8_t dup/* : 1 */; + jiangtun_uint8_t z/* : 1 */; + jiangtun_uint8_t r/* : 1 */; + jiangtun_uint8_t l/* : 1 */; + jiangtun_uint8_t high1/* : 1 */; + + /* 3rd-8th data byte */ + jiangtun_uint8_t xAxis; + jiangtun_uint8_t yAxis; + jiangtun_uint8_t cxAxis; + jiangtun_uint8_t cyAxis; + jiangtun_uint8_t left; + jiangtun_uint8_t right; + } mode3; /* mode3 (default reading mode) */ + + struct { + /* first data byte (bitfields are sorted in LSB order) */ + jiangtun_uint8_t a/* : 1 */; + jiangtun_uint8_t b/* : 1 */; + jiangtun_uint8_t x/* : 1 */; + jiangtun_uint8_t y/* : 1 */; + jiangtun_uint8_t start/* : 1 */; + jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ + jiangtun_uint8_t errlatch/* : 1 */; + jiangtun_uint8_t errstat/* : 1 */; + + /* second data byte */ + jiangtun_uint8_t dleft/* : 1 */; + jiangtun_uint8_t dright/* : 1 */; + jiangtun_uint8_t ddown/* : 1 */; + jiangtun_uint8_t dup/* : 1 */; + jiangtun_uint8_t z/* : 1 */; + jiangtun_uint8_t r/* : 1 */; + jiangtun_uint8_t l/* : 1 */; + jiangtun_uint8_t high1/* : 1 */; + + /* 3rd-8th data byte */ + jiangtun_uint8_t xAxis; + jiangtun_uint8_t yAxis; + jiangtun_uint8_t cxAxis; + jiangtun_uint8_t cyAxis; + jiangtun_uint8_t right/* : 4 */; /* note: within bytes, LSB is first */ + jiangtun_uint8_t left/* : 4 */; + jiangtun_uint8_t analogB/* : 4 */; + jiangtun_uint8_t analogA/* : 4 */; + } mode0; + + struct { + /* first data byte (bitfields are sorted in LSB order) */ + jiangtun_uint8_t a/* : 1 */; + jiangtun_uint8_t b/* : 1 */; + jiangtun_uint8_t x/* : 1 */; + jiangtun_uint8_t y/* : 1 */; + jiangtun_uint8_t start/* : 1 */; + jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ + jiangtun_uint8_t errlatch/* : 1 */; + jiangtun_uint8_t errstat/* : 1 */; + + /* second data byte */ + jiangtun_uint8_t dleft/* : 1 */; + jiangtun_uint8_t dright/* : 1 */; + jiangtun_uint8_t ddown/* : 1 */; + jiangtun_uint8_t dup/* : 1 */; + jiangtun_uint8_t z/* : 1 */; + jiangtun_uint8_t r/* : 1 */; + jiangtun_uint8_t l/* : 1 */; + jiangtun_uint8_t high1/* : 1 */; + + /* 3rd-8th data byte */ + jiangtun_uint8_t xAxis; + jiangtun_uint8_t yAxis; + jiangtun_uint8_t cyAxis/* : 4 */; + jiangtun_uint8_t cxAxis/* : 4 */; + jiangtun_uint8_t left; + jiangtun_uint8_t right; + jiangtun_uint8_t analogB/* : 4 */; + jiangtun_uint8_t analogA/* : 4 */; + } mode1; + + struct { + /* first data byte (bitfields are sorted in LSB order) */ + jiangtun_uint8_t a/* : 1 */; + jiangtun_uint8_t b/* : 1 */; + jiangtun_uint8_t x/* : 1 */; + jiangtun_uint8_t y/* : 1 */; + jiangtun_uint8_t start/* : 1 */; + jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ + jiangtun_uint8_t errlatch/* : 1 */; + jiangtun_uint8_t errstat/* : 1 */; + + /* second data byte */ + jiangtun_uint8_t dleft/* : 1 */; + jiangtun_uint8_t dright/* : 1 */; + jiangtun_uint8_t ddown/* : 1 */; + jiangtun_uint8_t dup/* : 1 */; + jiangtun_uint8_t z/* : 1 */; + jiangtun_uint8_t r/* : 1 */; + jiangtun_uint8_t l/* : 1 */; + jiangtun_uint8_t high1/* : 1 */; + + /* 3rd-8th data byte */ + jiangtun_uint8_t xAxis; + jiangtun_uint8_t yAxis; + jiangtun_uint8_t cyAxis/* : 4 */; + jiangtun_uint8_t cxAxis/* : 4 */; + jiangtun_uint8_t right/* : 4 */; + jiangtun_uint8_t left/* : 4 */; + jiangtun_uint8_t analogA; + jiangtun_uint8_t analogB; + } mode2; + + struct { + /* first data byte (bitfields are sorted in LSB order) */ + jiangtun_uint8_t a/* : 1 */; + jiangtun_uint8_t b/* : 1 */; + jiangtun_uint8_t x/* : 1 */; + jiangtun_uint8_t y/* : 1 */; + jiangtun_uint8_t start/* : 1 */; + jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ + jiangtun_uint8_t errlatch/* : 1 */; + jiangtun_uint8_t errstat/* : 1 */; + + /* second data byte */ + jiangtun_uint8_t dleft/* : 1 */; + jiangtun_uint8_t dright/* : 1 */; + jiangtun_uint8_t ddown/* : 1 */; + jiangtun_uint8_t dup/* : 1 */; + jiangtun_uint8_t z/* : 1 */; + jiangtun_uint8_t r/* : 1 */; + jiangtun_uint8_t l/* : 1 */; + jiangtun_uint8_t high1/* : 1 */; + + /* 3rd-8th data byte */ + jiangtun_uint8_t xAxis; + jiangtun_uint8_t yAxis; + jiangtun_uint8_t cxAxis; + jiangtun_uint8_t cyAxis; + jiangtun_uint8_t analogA; + jiangtun_uint8_t analogB; + } mode4; + + struct { + /* first data byte (bitfields are sorted in LSB order) */ + jiangtun_uint8_t unknown_counter1/* : 4 */; + jiangtun_uint8_t unknown1/* : 2 */; + jiangtun_uint8_t errlatch/* : 1 */; + jiangtun_uint8_t errstat/* : 1 */; + + jiangtun_uint16_t unknown2/* : 16 */; + jiangtun_uint8_t unknown3; + + jiangtun_uint8_t keypress[3]; + + jiangtun_uint8_t unknown_counter2/* : 4 */; + jiangtun_uint8_t unknown4/* : 4 */; + } keyboard; + +} jiangtun_report_t; +/* clang-format on */ + +#define JIANGTUN_REPORT_STICK_NEUTRAL 128 + +jiangtun_error_t jiangtun_report_init(jiangtun_report_t *); +/** + * Adjust the axis values to fall within the range of 1 to 254 to ensure proper + * recognition by the games. + * + * The theoretical upper and lower limits (0 and 255) of the GameCube + * controller's axis values do not usually occur in actual input. As a result, + * some games may not handle these values correctly. + */ +jiangtun_error_t jiangtun_report_emend_axis(jiangtun_report_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_REPORT_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/library.properties b/lib/jiangtun-core/library.properties new file mode 100644 index 0000000..4b72d9c --- /dev/null +++ b/lib/jiangtun-core/library.properties @@ -0,0 +1,10 @@ +name=jiangtun-core +version=1.0.0 +author=Koutaro Mukai +maintainer=Koutaro Mukai +sentence=The core library of Jiangtun. +paragraph=The core library of Jiangtun. +category=Other +url=https://github.com/U-1F992/jiangtun +architectures=* +depends=Bluewhale (=1.0.3) diff --git a/lib/jiangtun-core/src/error.c b/lib/jiangtun-core/src/error.c new file mode 100644 index 0000000..2821bb6 --- /dev/null +++ b/lib/jiangtun-core/src/error.c @@ -0,0 +1,23 @@ +#include + +const char *jiangtun_error_stringify(jiangtun_error_t err) { + switch (err) { + case JIANGTUN_SUCCESS: + return "JIANGTUN_SUCCESS"; + + case JIANGTUN_ERROR_NULL_POINTER: + return "JIANGTUN_ERROR_NULL_POINTER"; + + case JIANGTUN_ERROR_INVALID_ARGUMENT: + return "JIANGTUN_ERROR_INVALID_ARGUMENT"; + + case JIANGTUN_ERROR_PARSE_FAILURE: + return "JIANGTUN_ERROR_PARSE_FAILURE"; + + case JIANGTUN_ERROR_INTERNAL: + return "JIANGTUN_ERROR_INTERNAL"; + + default: + return "unknown"; + } +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/lex.yy.c b/lib/jiangtun-core/src/lex.yy.c new file mode 100644 index 0000000..bf869ed --- /dev/null +++ b/lib/jiangtun-core/src/lex.yy.c @@ -0,0 +1,2087 @@ +#line 2 "src/lex.yy.c" + +#line 4 "src/lex.yy.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyg->yytext_ptr -= yyg->yy_more_len; \ + yyleng = (int) (yy_cp - yyg->yytext_ptr); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 24 +#define YY_END_OF_BUFFER 25 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[61] = + { 0, + 0, 0, 25, 23, 4, 4, 22, 4, 20, 1, + 4, 4, 3, 16, 20, 20, 1, 5, 4, 4, + 16, 22, 21, 1, 18, 5, 6, 4, 19, 17, + 1, 8, 8, 1, 8, 8, 7, 1, 10, 10, + 1, 10, 11, 10, 9, 1, 13, 13, 1, 13, + 13, 12, 1, 15, 15, 2, 15, 15, 14, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 1, 1, 1, + 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 7, 7, 9, + + 10, 7, 1, 1, 1, 1, 1, 1, 1, 11, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, + 1, 1, 1, 1, 1, 1, 1, 13, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 15 + } ; + +static const YY_CHAR yy_meta[16] = + { 0, + 1, 2, 2, 3, 4, 4, 4, 1, 4, 4, + 1, 5, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[85] = + { 0, + 0, 0, 161, 162, 12, 13, 162, 149, 144, 0, + 13, 154, 0, 148, 141, 140, 0, 24, 150, 0, + 18, 162, 136, 0, 162, 68, 64, 64, 162, 65, + 0, 18, 19, 0, 61, 61, 0, 0, 30, 52, + 0, 61, 54, 41, 0, 0, 34, 37, 0, 53, + 53, 0, 0, 48, 59, 162, 54, 45, 0, 162, + 71, 74, 79, 84, 87, 51, 91, 96, 99, 103, + 50, 108, 111, 116, 49, 121, 126, 48, 131, 134, + 139, 25, 144, 148 + } ; + +static const flex_int16_t yy_def[85] = + { 0, + 61, 60, 60, 60, 62, 62, 60, 6, 63, 64, + 60, 65, 66, 60, 67, 63, 68, 60, 69, 6, + 60, 60, 67, 70, 60, 60, 71, 60, 60, 60, + 72, 73, 73, 74, 75, 60, 71, 76, 60, 39, + 77, 60, 78, 60, 75, 79, 80, 80, 81, 82, + 60, 78, 83, 84, 84, 60, 60, 60, 82, 0, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60 + } ; + +static const flex_int16_t yy_nxt[178] = + { 0, + 4, 4, 4, 4, 5, 6, 6, 7, 6, 8, + 4, 4, 9, 10, 4, 11, 11, 18, 18, 29, + 30, 35, 35, 13, 60, 25, 26, 27, 55, 37, + 60, 25, 42, 43, 44, 44, 44, 50, 44, 44, + 50, 45, 25, 42, 43, 52, 25, 57, 60, 25, + 57, 48, 40, 33, 20, 25, 50, 54, 47, 59, + 25, 57, 25, 60, 35, 39, 29, 11, 32, 25, + 60, 4, 4, 4, 4, 4, 12, 12, 12, 15, + 15, 15, 15, 15, 17, 17, 17, 17, 17, 19, + 19, 22, 22, 22, 22, 22, 24, 24, 24, 24, + + 24, 28, 28, 31, 31, 31, 31, 31, 34, 34, + 34, 34, 34, 36, 36, 36, 38, 38, 38, 38, + 38, 41, 41, 41, 41, 41, 46, 46, 46, 46, + 46, 49, 49, 49, 49, 49, 51, 51, 51, 53, + 53, 53, 53, 53, 56, 56, 56, 56, 56, 58, + 23, 58, 58, 11, 16, 23, 21, 11, 16, 14, + 60, 3, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60 + } ; + +static const flex_int16_t yy_chk[178] = + { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 5, 6, 11, 11, 21, + 21, 32, 33, 5, 6, 18, 18, 18, 82, 32, + 33, 39, 39, 39, 39, 39, 39, 47, 39, 39, + 48, 39, 44, 44, 44, 47, 58, 58, 48, 54, + 54, 78, 75, 71, 66, 57, 51, 50, 43, 54, + 55, 55, 42, 40, 36, 35, 30, 28, 27, 26, + 55, 61, 61, 61, 61, 61, 62, 62, 62, 63, + 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, + 65, 67, 67, 67, 67, 67, 68, 68, 68, 68, + + 68, 69, 69, 70, 70, 70, 70, 70, 72, 72, + 72, 72, 72, 73, 73, 73, 74, 74, 74, 74, + 74, 76, 76, 76, 76, 76, 77, 77, 77, 77, + 77, 79, 79, 79, 79, 79, 80, 80, 80, 81, + 81, 81, 81, 81, 83, 83, 83, 83, 83, 84, + 23, 84, 84, 19, 16, 15, 14, 12, 9, 8, + 3, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() (yyg->yy_more_flag = 1) +#define YY_MORE_ADJ yyg->yy_more_len +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "src/lexer.l" +#define YY_NO_INPUT 1 +#define YY_NO_UNISTD_H 1 +#line 7 "src/lexer.l" +#include + +#include "lex.yy.extern.h" + +/* nounistd */ +static int isatty(int fd) { + (void)fd; + return 1; +} + +#define SET_PARTIAL(v) \ + do { \ + jiangtun_yy_extra_t *extra = NULL; \ + if ((extra = yyget_extra(yyscanner)) != NULL) \ + extra->partial = (v); \ + } while (0) + +#define SET_RETURN(v) \ + do { \ + jiangtun_yy_extra_t *extra = NULL; \ + if ((extra = yyget_extra(yyscanner)) != NULL) \ + extra->return_ = (v); \ + } while (0) +#line 507 "src/lex.yy.c" +#line 508 "src/lex.yy.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 32 "src/lexer.l" + + +#line 35 "src/lexer.l" + /* + * NX Macro Controller + */ +#line 776 "src/lex.yy.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yyg->yy_more_len = 0; + if ( yyg->yy_more_flag ) + { + yyg->yy_more_len = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + yyg->yy_more_flag = 0; + } + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 61 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 162 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 38 "src/lexer.l" +{ + SET_PARTIAL(1); + yymore(); + } + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 42 "src/lexer.l" +{ + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_MATCH_NXMC2); + } + YY_BREAK +/* + * Poke-Controller + * 正規表現の簡略化のために、ボタン下位ビットで判定できる不正パターンを許容する + */ +case 3: +#line 52 "src/lexer.l" +case 4: +#line 53 "src/lexer.l" +/* [048c] 末尾2bitが0b00 */ +case 5: +#line 55 "src/lexer.l" +/* [1235679abdef] 末尾2bitの少なくとも1つが0b1 */ +case 6: +#line 57 "src/lexer.l" +case 7: +#line 58 "src/lexer.l" +case 8: +#line 59 "src/lexer.l" +case 9: +#line 60 "src/lexer.l" +/* [12569ade] 末尾2bitのいずれかが0b1(ただしバグにより"3"はスティックが1つになる場合がある) */ +case 10: +#line 62 "src/lexer.l" +/* [37bf] 末尾2bitが0b11 */ +case 11: +#line 64 "src/lexer.l" +case 12: +#line 65 "src/lexer.l" +case 13: +#line 66 "src/lexer.l" +case 14: +#line 67 "src/lexer.l" +case 15: +#line 68 "src/lexer.l" +case 16: +#line 69 "src/lexer.l" +case 17: +YY_RULE_SETUP +#line 69 "src/lexer.l" +{ + SET_PARTIAL(1); + yymore(); + } + YY_BREAK +case 18: +/* rule 18 can match eol */ +#line 74 "src/lexer.l" +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +#line 74 "src/lexer.l" +{ + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_MATCH_POKECON); + } + YY_BREAK +/* + * ORCA GC Controller + */ +case 20: +/* rule 20 can match eol */ +#line 83 "src/lexer.l" +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +#line 83 "src/lexer.l" +{ + SET_PARTIAL(1); + yymore(); + } + YY_BREAK +case 22: +/* rule 22 can match eol */ +YY_RULE_SETUP +#line 87 "src/lexer.l" +{ + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_MATCH_ORCA); + } + YY_BREAK +case 23: +/* rule 23 can match eol */ +YY_RULE_SETUP +#line 92 "src/lexer.l" +{ + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_NO_MATCH); + } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 97 "src/lexer.l" +ECHO; + YY_BREAK +#line 952 "src/lex.yy.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 61 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 61 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 60); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 97 "src/lexer.l" + + diff --git a/lib/jiangtun-core/src/lex.yy.extern.h b/lib/jiangtun-core/src/lex.yy.extern.h new file mode 100644 index 0000000..6810115 --- /dev/null +++ b/lib/jiangtun-core/src/lex.yy.extern.h @@ -0,0 +1,23 @@ +#ifndef JIANGTUN_LEXER_EXTERN_H +#define JIANGTUN_LEXER_EXTERN_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef YY_EXTRA_TYPE +#undef YY_EXTRA_TYPE +#endif /* YY_EXTRA_TYPE */ +#define YY_EXTRA_TYPE jiangtun_yy_extra_t * + +#ifndef YY_NO_UNISTD_H +#define YY_NO_UNISTD_H +#endif /* YY_NO_UNISTD_H */ + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_LEXER_EXTERN_H */ diff --git a/lib/jiangtun-core/src/lex.yy.h b/lib/jiangtun-core/src/lex.yy.h new file mode 100644 index 0000000..55a8b33 --- /dev/null +++ b/lib/jiangtun-core/src/lex.yy.h @@ -0,0 +1,492 @@ +#ifndef yyHEADER_H +#define yyHEADER_H 1 +#define yyIN_HEADER 1 + +#line 6 "src/lex.yy.h" + +#line 8 "src/lex.yy.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef yy_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef yy_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef yy_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef yy_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef yy_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef yy_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef yy_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef yy_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef yy_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef yypush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef yypop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef yyensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef yylex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef yyrestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef yylex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef yylex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef yylex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef yyget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef yyset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef yyget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef yyset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef yyget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef yyset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef yyget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef yyset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef yyget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef yyget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef yyget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef yyset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef yyget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef yyset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef yywrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef yyget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef yyset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef yyget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef yyset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef yyalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef yyrealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef yyfree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef yytext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef yyleng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef yyin_ALREADY_DEFINED +#undef yyin +#endif +#ifndef yyout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef yy_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef yylineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef yytables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef yytables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef yyTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#line 97 "src/lexer.l" + + +#line 491 "src/lex.yy.h" +#undef yyIN_HEADER +#endif /* yyHEADER_H */ diff --git a/lib/jiangtun-core/src/lexer.c b/lib/jiangtun-core/src/lexer.c new file mode 100644 index 0000000..4a7c3e3 --- /dev/null +++ b/lib/jiangtun-core/src/lexer.c @@ -0,0 +1,110 @@ +#include + +/* clang-format off */ +#include "lex.yy.extern.h" +#include "lex.yy.h" +/* clang-format on */ + +jiangtun_error_t jiangtun_lexer_init(jiangtun_lexer_t *lexer) { + if (lexer == NULL) { + return JIANGTUN_ERROR_NULL_POINTER; + } + + lexer->extra.partial = JIANGTUN_FALSE; + if (yylex_init_extra(&(lexer->extra), (yyscan_t *)&(lexer->scanner)) != 0) { + return JIANGTUN_ERROR_INTERNAL; + } + + return JIANGTUN_SUCCESS; +} + +jiangtun_error_t jiangtun_lexer_deinit(jiangtun_lexer_t *lexer) { + if (lexer == NULL) { + return JIANGTUN_ERROR_NULL_POINTER; + } + + yylex_destroy((yyscan_t)(lexer->scanner)); + + return JIANGTUN_SUCCESS; +} + +jiangtun_error_t jiangtun_lex(jiangtun_lexer_t *lexer, + const jiangtun_uint8_t *buffer, + size_t buffer_length, + jiangtun_lexer_result_t *out_result) { + jiangtun_error_t err = JIANGTUN_SUCCESS; + jiangtun_lexer_result_t result = JIANGTUN_LEXER_NO_MATCH; + YY_BUFFER_STATE state = NULL; + + if (lexer == NULL) { + return JIANGTUN_ERROR_NULL_POINTER; + } else if (buffer == NULL || buffer_length == 0) { + if (out_result != NULL) { + *out_result = JIANGTUN_LEXER_NO_MATCH; + } + return JIANGTUN_SUCCESS; + } + + state = yy_scan_bytes((char *)buffer, buffer_length, + (yyscan_t)(lexer->scanner)); + if (state == NULL) { + return JIANGTUN_ERROR_INTERNAL; + } + yy_switch_to_buffer(state, (yyscan_t)(lexer->scanner)); + + lexer->extra.partial = JIANGTUN_FALSE; + lexer->extra.return_ = JIANGTUN_YY_NO_MATCH; + yylex((yyscan_t)(lexer->scanner)); + switch (lexer->extra.return_) { + case JIANGTUN_YY_NO_MATCH: + result = lexer->extra.partial ? JIANGTUN_LEXER_MATCH_PARTIAL + : JIANGTUN_LEXER_NO_MATCH; + break; + + case JIANGTUN_YY_MATCH_NXMC2: + result = JIANGTUN_LEXER_MATCH_NXMC2; + break; + + case JIANGTUN_YY_MATCH_POKECON: + result = JIANGTUN_LEXER_MATCH_POKECON; + break; + + case JIANGTUN_YY_MATCH_ORCA: + result = JIANGTUN_LEXER_MATCH_ORCA; + break; + + default: + err = JIANGTUN_ERROR_INTERNAL; + break; + } + + yy_delete_buffer(state, (yyscan_t)(lexer->scanner)); + + if (out_result != NULL) { + *out_result = result; + } + + return err; +} + +const char *jiangtun_lexer_result_stringify(jiangtun_lexer_result_t result) { + switch (result) { + case JIANGTUN_LEXER_NO_MATCH: + return "JIANGTUN_LEXER_NO_MATCH"; + + case JIANGTUN_LEXER_MATCH_PARTIAL: + return "JIANGTUN_LEXER_MATCH_PARTIAL"; + + case JIANGTUN_LEXER_MATCH_NXMC2: + return "JIANGTUN_LEXER_MATCH_NXMC2"; + + case JIANGTUN_LEXER_MATCH_POKECON: + return "JIANGTUN_LEXER_MATCH_POKECON"; + + case JIANGTUN_LEXER_MATCH_ORCA: + return "JIANGTUN_LEXER_MATCH_ORCA"; + + default: + return "unknown"; + } +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/lexer.l b/lib/jiangtun-core/src/lexer.l new file mode 100644 index 0000000..ef24d7f --- /dev/null +++ b/lib/jiangtun-core/src/lexer.l @@ -0,0 +1,96 @@ +%option noyywrap +%option nounput +%option noinput +%option nounistd +%option reentrant +%{ +#include + +#include "lex.yy.extern.h" + +/* nounistd */ +static int isatty(int fd) { + (void)fd; + return 1; +} + +#define SET_PARTIAL(v) \ + do { \ + jiangtun_yy_extra_t *extra = NULL; \ + if ((extra = yyget_extra(yyscanner)) != NULL) \ + extra->partial = (v); \ + } while (0) + +#define SET_RETURN(v) \ + do { \ + jiangtun_yy_extra_t *extra = NULL; \ + if ((extra = yyget_extra(yyscanner)) != NULL) \ + extra->return_ = (v); \ + } while (0) +%} + +%% + + /* + * NX Macro Controller + */ +^\xAB[\x00-\xFF]{0,9} { + SET_PARTIAL(1); + yymore(); + } +^\xAB[\x00-\xFF]{10} { + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_MATCH_NXMC2); + } + + /* + * Poke-Controller + * 正規表現の簡略化のために、ボタン下位ビットで判定できる不正パターンを許容する + */ +^(0x) | +^(0x)?[0-9a-f]{1,4}\x20? | + /* [048c] 末尾2bitが0b00 */ +^(0x)?[0-9a-f]{1,4}\x20[0-8]\r? | + /* [1235679abdef] 末尾2bitの少なくとも1つが0b1 */ +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20? | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x) | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20? | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x) | + /* [12569ade] 末尾2bitのいずれかが0b1(ただしバグにより"3"はスティックが1つになる場合がある) */ +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\r? | + /* [37bf] 末尾2bitが0b11 */ +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20? | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x) | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20? | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x) | +^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\r? | +^end? | +^end\r? { + SET_PARTIAL(1); + yymore(); + } +^(0x)?[0-9a-f]{1,4}\x20[0-8](\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}(\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2})?)?\r?\n | +^end\r?\n { + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_MATCH_POKECON); + } + + /* + * ORCA GC Controller + */ +^\x80\xFF*[\x00-\xFE]? | +^\x80\xFF*[\x00-\xFE]\xFF* { + SET_PARTIAL(1); + yymore(); + } +^(@|\x80\xFF*[\x00-\xFE]\xFF*[\x00-\xFE]) { + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_MATCH_ORCA); + } + +[\x00-\xFF] { + SET_PARTIAL(0); + SET_RETURN(JIANGTUN_YY_NO_MATCH); + } + +%% diff --git a/lib/jiangtun-core/src/nxmc2.c b/lib/jiangtun-core/src/nxmc2.c new file mode 100644 index 0000000..2905b5d --- /dev/null +++ b/lib/jiangtun-core/src/nxmc2.c @@ -0,0 +1,118 @@ +#include + +jiangtun_error_t jiangtun_nxmc2_parse(const jiangtun_uint8_t *buffer, + size_t buffer_length, + jiangtun_report_t *out_report, + jiangtun_bool_t *out_reset) { + jiangtun_uint8_t btns_lsb = 0; + jiangtun_uint8_t btns_msb = 0; + jiangtun_uint8_t hat = 8; + + if (buffer == NULL) { + return JIANGTUN_ERROR_INVALID_ARGUMENT; + } else if (buffer_length != 11 || buffer[0] != 0xAB) { + return JIANGTUN_ERROR_PARSE_FAILURE; + } + + btns_lsb = buffer[1]; + btns_msb = buffer[2]; + hat = buffer[3] % 9; + + if (out_report != NULL) { + if (jiangtun_report_init(out_report) != JIANGTUN_SUCCESS) { + return JIANGTUN_ERROR_INTERNAL; + } + + out_report->mode3.y = (btns_lsb >> 0) & 1; + out_report->mode3.b = (btns_lsb >> 1) & 1; + out_report->mode3.a = (btns_lsb >> 2) & 1; + out_report->mode3.x = (btns_lsb >> 3) & 1; + out_report->mode3.l = (btns_lsb >> 4) & 1; + out_report->mode3.r = (btns_lsb >> 5) & 1; + /* zl = (btns_lsb >> 6) & 1; */ + out_report->mode3.z = (btns_msb >> 7) & 1; + /* minus = (btns_msb >> 0) & 1; */ + out_report->mode3.start = (btns_msb >> 1) & 1; + /* l_click = (btns_msb >> 2) & 1; */ + /* r_click = (btns_msb >> 3) & 1; */ + /* home = (btns_msb >> 4) & 1; --> reset */ + /* capture = (btns_msb >> 5) & 1; */ + + switch (hat) { + case 0: + out_report->mode3.dup = 1; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + case 1: + out_report->mode3.dup = 1; + out_report->mode3.dright = 1; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + case 2: + out_report->mode3.dup = 0; + out_report->mode3.dright = 1; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + case 3: + out_report->mode3.dup = 0; + out_report->mode3.dright = 1; + out_report->mode3.ddown = 1; + out_report->mode3.dleft = 0; + break; + case 4: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 1; + out_report->mode3.dleft = 0; + break; + case 5: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 1; + out_report->mode3.dleft = 1; + break; + case 6: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 1; + break; + case 7: + out_report->mode3.dup = 1; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 1; + break; + case 8: + default: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + } + + out_report->mode3.xAxis = buffer[4]; + out_report->mode3.yAxis = 0xFF - buffer[5]; + + out_report->mode3.cxAxis = buffer[6]; + out_report->mode3.cyAxis = 0xFF - buffer[7]; + + (void)buffer[8]; + (void)buffer[9]; + (void)buffer[10]; + + if (jiangtun_report_emend_axis(out_report) != JIANGTUN_SUCCESS) { + return JIANGTUN_ERROR_INTERNAL; + } + } + if (out_reset != NULL) { + *out_reset = (jiangtun_bool_t)((btns_msb >> 4) & 1); + } + + return JIANGTUN_SUCCESS; +} diff --git a/lib/jiangtun-core/src/pokecon.c b/lib/jiangtun-core/src/pokecon.c new file mode 100644 index 0000000..b7c2098 --- /dev/null +++ b/lib/jiangtun-core/src/pokecon.c @@ -0,0 +1,228 @@ +#include + +#include + +jiangtun_error_t +jiangtun_pokecon_previous_state_init(jiangtun_pokecon_previous_state_t *prev) { + if (prev == NULL) { + return JIANGTUN_ERROR_NULL_POINTER; + } + + prev->left.x = JIANGTUN_REPORT_STICK_NEUTRAL; + prev->left.y = JIANGTUN_REPORT_STICK_NEUTRAL; + prev->right.x = JIANGTUN_REPORT_STICK_NEUTRAL; + prev->right.y = JIANGTUN_REPORT_STICK_NEUTRAL; + + return JIANGTUN_SUCCESS; +} + +static void remove_0x(char *str) { + char *p = str; + while ((p = strstr(p, "0x")) != NULL) { + /* Remove "0x" by moving the rest of the string over it */ + memmove(p, p + 2, strlen(p + 2) + 1); + } +} + +/* + * static const size_t MIN_VALID_LENGTH = sizeof("0 0\n"); + * static const size_t MAX_VALID_LENGTH = sizeof("0x0000 0 0x00 0x00 0x00 + * 0x00\r\n"); + */ +#define MIN_VALID_LENGTH 5 +#define MAX_VALID_LENGTH 31 + +jiangtun_error_t +jiangtun_pokecon_parse(const jiangtun_uint8_t *buffer, size_t buffer_length, + jiangtun_report_t *out_report, + jiangtun_bool_t *out_reset, + jiangtun_pokecon_previous_state_t *prev) { + size_t i = 0; + + char str[MAX_VALID_LENGTH]; + size_t str_length = 0; + int whitespace_count = 0; + + jiangtun_uint16_t btns = 0x0000; + jiangtun_uint16_t hat = 8; + jiangtun_uint16_t x_0 = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t y_0 = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t x_1 = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t y_1 = JIANGTUN_REPORT_STICK_NEUTRAL; + + jiangtun_bool_t update_rs = JIANGTUN_FALSE; + jiangtun_bool_t update_ls = JIANGTUN_FALSE; + + if (buffer == NULL || prev == NULL) { + return JIANGTUN_ERROR_INVALID_ARGUMENT; + } else if (buffer_length < MIN_VALID_LENGTH - 1 || + MAX_VALID_LENGTH - 1 < buffer_length) { + return JIANGTUN_ERROR_PARSE_FAILURE; + } + + if ((buffer_length == 4 || buffer_length == 5) && + (buffer[0] == 'e' && buffer[1] == 'n' && buffer[2] == 'd' && + (buffer[3] == '\n' || (buffer[3] == '\r' && buffer[4] == '\n')))) { + + if (out_report != NULL) { + if (jiangtun_report_init(out_report) != JIANGTUN_SUCCESS) { + return JIANGTUN_ERROR_INTERNAL; + } + } + + prev->left.x = JIANGTUN_REPORT_STICK_NEUTRAL; + prev->left.y = JIANGTUN_REPORT_STICK_NEUTRAL; + prev->right.x = JIANGTUN_REPORT_STICK_NEUTRAL; + prev->right.y = JIANGTUN_REPORT_STICK_NEUTRAL; + + return JIANGTUN_SUCCESS; + } + + /* Copy buffer into a new char[] */ + for (i = 0; i < buffer_length; i++) { + switch (buffer[i]) { + case '\r': + case '\n': + break; + + case ' ': + whitespace_count++; + /* fallthrough */ + default: + str_length++; + str[i] = buffer[i]; + break; + } + } + str[str_length++] = '\0'; + /* 0x" must be removed. Maybe this is another Newlib-nano restriction. */ + remove_0x(str); + + /* + * Use uint16_t and "%hx" instead of uint8_t and "%hhx", + * as Newlib-nano do not support C99 notation. + * https://ja-support.renesas.com/knowledgeBase/20441082 + */ + switch (whitespace_count) { + case 1: + sscanf(str, "%hx %hx", &btns, &hat); + break; + case 3: + sscanf(str, "%hx %hx %hx %hx", &btns, &hat, &x_0, &y_0); + break; + case 5: + sscanf(str, "%hx %hx %hx %hx %hx %hx", &btns, &hat, &x_0, &y_0, &x_1, + &y_1); + break; + default: + return JIANGTUN_ERROR_PARSE_FAILURE; + } + hat = hat % 9; + x_0 = x_0 & 0xFF; + y_0 = 0xFF - (y_0 & 0xFF); + x_1 = x_1 & 0xFF; + y_1 = 0xFF - (y_1 & 0xFF); + + update_rs = (jiangtun_bool_t)((btns >> 0) & 1); + update_ls = (jiangtun_bool_t)((btns >> 1) & 1); + + if (out_report != NULL) { + if (jiangtun_report_init(out_report) != JIANGTUN_SUCCESS) { + return JIANGTUN_ERROR_INTERNAL; + } + + out_report->mode3.y = (btns >> 2) & 1; + out_report->mode3.b = (btns >> 3) & 1; + out_report->mode3.a = (btns >> 4) & 1; + out_report->mode3.x = (btns >> 5) & 1; + out_report->mode3.l = (btns >> 6) & 1; + out_report->mode3.r = (btns >> 7) & 1; + /* zl = (btns >> 8) & 1; */ + out_report->mode3.z = (btns >> 9) & 1; + /* minus = (btns >> 10) & 1; */ + out_report->mode3.start = (btns >> 11) & 1; + /* l_click = (btns >> 12) & 1; */ + /* r_click = (btns >> 13) & 1; */ + /* home = (btns >> 14) & 1; --> reset */ + /* capture = (btns >> 15) & 1; */ + + switch (hat) { + case 0: + out_report->mode3.dup = 1; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + case 1: + out_report->mode3.dup = 1; + out_report->mode3.dright = 1; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + case 2: + out_report->mode3.dup = 0; + out_report->mode3.dright = 1; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + case 3: + out_report->mode3.dup = 0; + out_report->mode3.dright = 1; + out_report->mode3.ddown = 1; + out_report->mode3.dleft = 0; + break; + case 4: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 1; + out_report->mode3.dleft = 0; + break; + case 5: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 1; + out_report->mode3.dleft = 1; + break; + case 6: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 1; + break; + case 7: + out_report->mode3.dup = 1; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 1; + break; + case 8: + default: + out_report->mode3.dup = 0; + out_report->mode3.dright = 0; + out_report->mode3.ddown = 0; + out_report->mode3.dleft = 0; + break; + } + } + + if (update_ls) { + prev->left.x = (jiangtun_uint8_t)x_0; + prev->left.y = (jiangtun_uint8_t)y_0; + } + if (update_rs) { + prev->right.x = (jiangtun_uint8_t)x_1; + prev->right.y = (jiangtun_uint8_t)y_1; + } + if (out_report != NULL) { + out_report->mode3.xAxis = prev->left.x; + out_report->mode3.yAxis = prev->left.y; + out_report->mode3.cxAxis = prev->right.x; + out_report->mode3.cyAxis = prev->right.y; + } + + if (out_reset != NULL) { + *out_reset = (jiangtun_bool_t)((btns >> 14) & 1); + } + + return JIANGTUN_SUCCESS; +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/report.c b/lib/jiangtun-core/src/report.c new file mode 100644 index 0000000..5eff34e --- /dev/null +++ b/lib/jiangtun-core/src/report.c @@ -0,0 +1,44 @@ +#include + +jiangtun_error_t jiangtun_report_init(jiangtun_report_t *report) { + if (report == NULL) { + return JIANGTUN_ERROR_NULL_POINTER; + } + + report->mode3.a = 0; + report->mode3.b = 0; + report->mode3.x = 0; + report->mode3.y = 0; + report->mode3.start = 0; + report->mode3.dleft = 0; + report->mode3.dright = 0; + report->mode3.ddown = 0; + report->mode3.dup = 0; + report->mode3.z = 0; + report->mode3.r = 0; + report->mode3.l = 0; + report->mode3.xAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->mode3.yAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->mode3.cxAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->mode3.cyAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->mode3.left = 0; + report->mode3.right = 0; + + return JIANGTUN_SUCCESS; +} + +#define EMEND_AXIS(axis) \ + ((axis) = (axis) == 0 ? 1 : (axis) == 255 ? 254 : (axis)) + +jiangtun_error_t jiangtun_report_emend_axis(jiangtun_report_t *report) { + if (report == NULL) { + return JIANGTUN_ERROR_NULL_POINTER; + } + + EMEND_AXIS(report->mode3.xAxis); + EMEND_AXIS(report->mode3.yAxis); + EMEND_AXIS(report->mode3.cxAxis); + EMEND_AXIS(report->mode3.cyAxis); + + return JIANGTUN_SUCCESS; +} \ No newline at end of file diff --git a/lib/jiangtun-core/test/lexer.c b/lib/jiangtun-core/test/lexer.c new file mode 100644 index 0000000..6b6475b --- /dev/null +++ b/lib/jiangtun-core/test/lexer.c @@ -0,0 +1,345 @@ +#include + +#include +#include + +typedef struct test_case_t { + jiangtun_uint8_t *buffer; + size_t buffer_length; + jiangtun_error_t expected_err; + jiangtun_lexer_result_t expected_ret; +} test_case_t; + +#define REGISTER_CASE(buffer_, buffer_length_, expexted_err_, expected_ret_) \ + do { \ + test_cases[i].buffer = (buffer_); \ + test_cases[i].buffer_length = (buffer_length_); \ + test_cases[i].expected_err = (expexted_err_); \ + test_cases[i].expected_ret = (expected_ret_); \ + i++; \ + } while (0) + +#define TEST_ASSERT(expr) \ + if (!(expr)) { \ + fprintf(stderr, "Assertion failed: \"%s\", index: %lu\n", #expr, \ + (unsigned long)i); \ + test_failed_count++; \ + continue; \ + } \ + do { \ + } while (0) + +int main() { + size_t i = 0; + + test_case_t test_cases[84]; + size_t test_cases_length = sizeof(test_cases) / sizeof(test_case_t); + size_t test_failed_count = 0; + + /* NULL pointer */ + jiangtun_uint8_t *buffer_0 = NULL; + /* Zero size */ + jiangtun_uint8_t buffer_1[] = {0x00}; + /* No match */ + jiangtun_uint8_t buffer_2[] = {0xFF}; + + /* NX Macro Controller */ + jiangtun_uint8_t buffer_3[] = {0xAB}; + jiangtun_uint8_t buffer_4[] = {0xAB, 0x00}; + jiangtun_uint8_t buffer_5[] = {0xAB, 0x00, 0x00}; + jiangtun_uint8_t buffer_6[] = {0xAB, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_7[] = {0xAB, 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_8[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_9[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_10[] = {0xAB, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_11[] = {0xAB, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_12[] = {0xAB, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_13[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}; + jiangtun_uint8_t buffer_14[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}; + + /* Poke-Controller */ + /* clang-format off */ + jiangtun_uint8_t buffer_15[] = "0"; + jiangtun_uint8_t buffer_16[] = "0 "; + jiangtun_uint8_t buffer_17[] = "0 0"; + jiangtun_uint8_t buffer_18[] = "0 0\r"; + jiangtun_uint8_t buffer_19[] = "0 0 "; + jiangtun_uint8_t buffer_20[] = "0 0 0"; + jiangtun_uint8_t buffer_21[] = "0 0 0 "; + jiangtun_uint8_t buffer_22[] = "0 0 0 0"; + jiangtun_uint8_t buffer_23[] = "0 0 0 0\r"; + jiangtun_uint8_t buffer_24[] = "0 0 0 0 "; + jiangtun_uint8_t buffer_25[] = "0 0 0 0 0"; + jiangtun_uint8_t buffer_26[] = "0 0 0 0 0 "; + jiangtun_uint8_t buffer_27[] = "0 0 0 0 0 0"; + jiangtun_uint8_t buffer_28[] = "0 0 0 0 0 0\r"; + + jiangtun_uint8_t buffer_29[] = "0 0\n"; + jiangtun_uint8_t buffer_30[] = "0 0\r\n"; + jiangtun_uint8_t buffer_31[] = "0 0 0 0\n"; + jiangtun_uint8_t buffer_32[] = "0 0 0 0\r\n"; + jiangtun_uint8_t buffer_33[] = "0 0 0 0 0 0\n"; + jiangtun_uint8_t buffer_34[] = "0 0 0 0 0 0\r\n"; + + jiangtun_uint8_t buffer_35[] = "0x"; + jiangtun_uint8_t buffer_36[] = "0x0"; + jiangtun_uint8_t buffer_37[] = "0x0 "; + jiangtun_uint8_t buffer_38[] = "0x0 0"; + jiangtun_uint8_t buffer_39[] = "0x0 0\r"; + jiangtun_uint8_t buffer_40[] = "0x0 0 "; + jiangtun_uint8_t buffer_41[] = "0x0 0 0"; + jiangtun_uint8_t buffer_42[] = "0x0 0 0x"; + jiangtun_uint8_t buffer_43[] = "0x0 0 0x0"; + jiangtun_uint8_t buffer_44[] = "0x0 0 0x0 "; + jiangtun_uint8_t buffer_45[] = "0x0 0 0x0 0"; + jiangtun_uint8_t buffer_46[] = "0x0 0 0x0 0x"; + jiangtun_uint8_t buffer_47[] = "0x0 0 0x0 0x0"; + jiangtun_uint8_t buffer_48[] = "0x0 0 0x0 0x0\r"; + jiangtun_uint8_t buffer_49[] = "0x0 0 0x0 0x0 "; + jiangtun_uint8_t buffer_50[] = "0x0 0 0x0 0x0 0"; + jiangtun_uint8_t buffer_51[] = "0x0 0 0x0 0x0 0x"; + jiangtun_uint8_t buffer_52[] = "0x0 0 0x0 0x0 0x0"; + jiangtun_uint8_t buffer_53[] = "0x0 0 0x0 0x0 0x0 "; + jiangtun_uint8_t buffer_54[] = "0x0 0 0x0 0x0 0x0 0"; + jiangtun_uint8_t buffer_55[] = "0x0 0 0x0 0x0 0x0 0x"; + jiangtun_uint8_t buffer_56[] = "0x0 0 0x0 0x0 0x0 0x0"; + jiangtun_uint8_t buffer_57[] = "0x0 0 0x0 0x0 0x0 0x0\r"; + + jiangtun_uint8_t buffer_58[] = "0x0 0\n"; + jiangtun_uint8_t buffer_59[] = "0x0 0\r\n"; + jiangtun_uint8_t buffer_60[] = "0x0 0 0x0 0x0\n"; + jiangtun_uint8_t buffer_61[] = "0x0 0 0x0 0x0\r\n"; + jiangtun_uint8_t buffer_62[] = "0x0 0 0x0 0x0 0x0 0x0\n"; + jiangtun_uint8_t buffer_63[] = "0x0 0 0x0 0x0 0x0 0x0\r\n"; + + jiangtun_uint8_t buffer_64[] = "0x0 0 0x0 0x0 0x0 0x0\r\n\xFF"; + + jiangtun_uint8_t buffer_65[] = "e"; + jiangtun_uint8_t buffer_66[] = "en"; + jiangtun_uint8_t buffer_67[] = "end"; + jiangtun_uint8_t buffer_68[] = "end\r"; + jiangtun_uint8_t buffer_69[] = "end\n"; + jiangtun_uint8_t buffer_70[] = "end\r\n"; + jiangtun_uint8_t buffer_71[] = "end\r\n\xFF"; + /* clang-format on */ + + jiangtun_uint8_t buffer_72[] = {0x80}; + jiangtun_uint8_t buffer_73[] = {0x80, 0x00}; + jiangtun_uint8_t buffer_74[] = {0x80, 0x00, 0x00}; + jiangtun_uint8_t buffer_75[] = {0x80, 0x00, 0x00, 0xFF}; + jiangtun_uint8_t buffer_76[] = {0x80, 0xFF}; + jiangtun_uint8_t buffer_77[] = {0x80, 0xFF, 0x00}; + jiangtun_uint8_t buffer_78[] = {0x80, 0xFF, 0xFF}; + jiangtun_uint8_t buffer_79[] = {0x80, 0x00}; + jiangtun_uint8_t buffer_80[] = {0x80, 0x00, 0xFF}; + jiangtun_uint8_t buffer_81[] = {0x80, 0x00, 0xFF, 0xFF}; + jiangtun_uint8_t buffer_82[] = {0x80, 0x00, 0xFF, 0xFF, 0x00}; + jiangtun_uint8_t buffer_83[] = {0x80, 0x00, 0xFF, 0xFF, 0x00, 0xFF}; + jiangtun_uint8_t buffer_84[] = "@"; + + /* NULL pointer */ + REGISTER_CASE(buffer_0, 1, JIANGTUN_SUCCESS, JIANGTUN_LEXER_NO_MATCH); + /* Zero size */ + REGISTER_CASE(buffer_1, 0, JIANGTUN_SUCCESS, JIANGTUN_LEXER_NO_MATCH); + /* No match */ + REGISTER_CASE(buffer_2, sizeof(buffer_2), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_NO_MATCH); + + /* NX Macro Controller */ + REGISTER_CASE(buffer_3, sizeof(buffer_3), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_4, sizeof(buffer_4), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_5, sizeof(buffer_5), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_6, sizeof(buffer_6), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_7, sizeof(buffer_7), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_8, sizeof(buffer_8), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_9, sizeof(buffer_9), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_10, sizeof(buffer_10), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_11, sizeof(buffer_11), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_12, sizeof(buffer_12), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_13, sizeof(buffer_13), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_NXMC2); + REGISTER_CASE(buffer_14, sizeof(buffer_14), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_NO_MATCH); + + /* Poke-Controller */ + REGISTER_CASE(buffer_15, sizeof(buffer_15) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_16, sizeof(buffer_16) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_17, sizeof(buffer_17) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_18, sizeof(buffer_18) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_19, sizeof(buffer_19) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_20, sizeof(buffer_20) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_21, sizeof(buffer_21) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_22, sizeof(buffer_22) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_23, sizeof(buffer_23) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_24, sizeof(buffer_24) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_25, sizeof(buffer_25) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_26, sizeof(buffer_26) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_27, sizeof(buffer_27) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_28, sizeof(buffer_28) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + + REGISTER_CASE(buffer_29, sizeof(buffer_29) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_30, sizeof(buffer_30) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_31, sizeof(buffer_31) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_32, sizeof(buffer_32) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_33, sizeof(buffer_33) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_34, sizeof(buffer_34) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + + REGISTER_CASE(buffer_35, sizeof(buffer_35) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_36, sizeof(buffer_36) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_37, sizeof(buffer_37) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_38, sizeof(buffer_38) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_39, sizeof(buffer_39) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_40, sizeof(buffer_40) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_41, sizeof(buffer_41) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_42, sizeof(buffer_42) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_43, sizeof(buffer_43) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_44, sizeof(buffer_44) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_45, sizeof(buffer_45) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_46, sizeof(buffer_46) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_47, sizeof(buffer_47) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_48, sizeof(buffer_48) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_49, sizeof(buffer_49) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_50, sizeof(buffer_50) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_51, sizeof(buffer_51) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_52, sizeof(buffer_52) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_53, sizeof(buffer_53) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_54, sizeof(buffer_54) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_55, sizeof(buffer_55) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_56, sizeof(buffer_56) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_57, sizeof(buffer_57) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + + REGISTER_CASE(buffer_58, sizeof(buffer_58) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_59, sizeof(buffer_59) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_60, sizeof(buffer_60) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_61, sizeof(buffer_61) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_62, sizeof(buffer_62) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_63, sizeof(buffer_63) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + + REGISTER_CASE(buffer_64, sizeof(buffer_64) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_NO_MATCH); + + REGISTER_CASE(buffer_65, sizeof(buffer_65) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_66, sizeof(buffer_66) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_67, sizeof(buffer_67) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_68, sizeof(buffer_68) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_69, sizeof(buffer_69) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_70, sizeof(buffer_70) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_POKECON); + REGISTER_CASE(buffer_71, sizeof(buffer_71) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_NO_MATCH); + + REGISTER_CASE(buffer_72, sizeof(buffer_72), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_73, sizeof(buffer_73), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_74, sizeof(buffer_74), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_ORCA); + REGISTER_CASE(buffer_75, sizeof(buffer_75), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_NO_MATCH); + REGISTER_CASE(buffer_76, sizeof(buffer_76), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_77, sizeof(buffer_77), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_78, sizeof(buffer_78), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_79, sizeof(buffer_79), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_80, sizeof(buffer_80), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_81, sizeof(buffer_81), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_PARTIAL); + REGISTER_CASE(buffer_82, sizeof(buffer_82), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_ORCA); + REGISTER_CASE(buffer_83, sizeof(buffer_83), JIANGTUN_SUCCESS, + JIANGTUN_LEXER_NO_MATCH); + REGISTER_CASE(buffer_84, sizeof(buffer_84) - 1, JIANGTUN_SUCCESS, + JIANGTUN_LEXER_MATCH_ORCA); + + for (i = 0; i < test_cases_length; i++) { + test_case_t *test_case = &(test_cases[i]); + jiangtun_lexer_t lexer; + jiangtun_error_t actual_err; + jiangtun_lexer_result_t actual_ret; + + TEST_ASSERT(JIANGTUN_SUCCESS == jiangtun_lexer_init(&lexer)); + TEST_ASSERT( + test_case->expected_err == + (actual_err = jiangtun_lex(&lexer, test_case->buffer, + test_case->buffer_length, &actual_ret))); + if (actual_err == JIANGTUN_SUCCESS) { + TEST_ASSERT(test_case->expected_ret == actual_ret); + } + TEST_ASSERT(JIANGTUN_SUCCESS == jiangtun_lexer_deinit(&lexer)); + } + + return 0; +} From 191ac8c337423bdf143e81a39f0ee87850aa3408 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Tue, 1 Oct 2024 00:45:25 +0900 Subject: [PATCH 13/25] Update libraries --- .gitmodules | 3 --- lib/Bluewhale | 1 - platformio.ini | 12 ++++++++---- 3 files changed, 8 insertions(+), 8 deletions(-) delete mode 160000 lib/Bluewhale diff --git a/.gitmodules b/.gitmodules index fc6d215..7c3fb06 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "lib/nthaka"] path = lib/nthaka url = https://github.com/U-1F992/nthaka.git -[submodule "lib/Bluewhale"] - path = lib/Bluewhale - url = https://github.com/mizuyoukanao/Bluewhale.git diff --git a/lib/Bluewhale b/lib/Bluewhale deleted file mode 160000 index eefedb7..0000000 --- a/lib/Bluewhale +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eefedb7bab7cf5675346998281cd0947039e87dd diff --git a/platformio.ini b/platformio.ini index 29a85ec..b6f91d5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,24 +9,26 @@ ; https://docs.platformio.org/page/projectconf.html [env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c board = pico framework = arduino board_build.core = earlephilhower lib_deps = adafruit/Adafruit NeoPixel@^1.12.0 + https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_PICO debug_tool = cmsis-dap [env:dol-pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c board = pico framework = arduino board_build.core = earlephilhower lib_deps = adafruit/Adafruit NeoPixel@^1.12.0 + https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_PICO @@ -34,24 +36,26 @@ build_flags = debug_tool = cmsis-dap [env:xiao-rp2040] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c board = seeed_xiao_rp2040 framework = arduino board_build.core = earlephilhower lib_deps = adafruit/Adafruit NeoPixel@^1.12.0 + https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 debug_tool = cmsis-dap [env:dol-xiao-rp2040] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c board = seeed_xiao_rp2040 framework = arduino board_build.core = earlephilhower lib_deps = adafruit/Adafruit NeoPixel@^1.12.0 + https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 build_flags = -DNDEBUG -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 From 9bd22e427b3ef0d5b3daac175de13444895e7e86 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 6 Oct 2024 23:32:42 +0900 Subject: [PATCH 14/25] Update core library --- lib/jiangtun-core/CMakeLists.txt | 13 +- lib/jiangtun-core/Dockerfile.flex | 12 - lib/jiangtun-core/include/jiangtun.h | 39 +- lib/jiangtun-core/include/jiangtun/board.h | 37 + lib/jiangtun-core/include/jiangtun/command.h | 110 + lib/jiangtun-core/include/jiangtun/compat.h | 13 +- lib/jiangtun-core/include/jiangtun/error.h | 22 - lib/jiangtun-core/include/jiangtun/lexer.h | 47 - lib/jiangtun-core/include/jiangtun/parse.h | 36 - lib/jiangtun-core/include/jiangtun/report.h | 251 +-- lib/jiangtun-core/src/board.c | 40 + lib/jiangtun-core/src/command.c | 87 + lib/jiangtun-core/src/dol.c | 156 ++ lib/jiangtun-core/src/error.c | 23 - lib/jiangtun-core/src/internal.h | 17 + lib/jiangtun-core/src/jiangtun.c | 132 ++ lib/jiangtun-core/src/lex.yy.c | 2087 ------------------ lib/jiangtun-core/src/lex.yy.extern.h | 23 - lib/jiangtun-core/src/lex.yy.h | 492 ----- lib/jiangtun-core/src/lexer.c | 110 - lib/jiangtun-core/src/lexer.l | 96 - lib/jiangtun-core/src/nxmc2.c | 323 ++- lib/jiangtun-core/src/orca.c | 145 ++ lib/jiangtun-core/src/pokecon.c | 823 +++++-- lib/jiangtun-core/src/report.c | 62 +- lib/jiangtun-core/test/arduino.c | 49 + lib/jiangtun-core/test/command.c | 310 +++ lib/jiangtun-core/test/lexer.c | 345 --- 28 files changed, 2047 insertions(+), 3853 deletions(-) delete mode 100644 lib/jiangtun-core/Dockerfile.flex create mode 100644 lib/jiangtun-core/include/jiangtun/board.h create mode 100644 lib/jiangtun-core/include/jiangtun/command.h delete mode 100644 lib/jiangtun-core/include/jiangtun/error.h delete mode 100644 lib/jiangtun-core/include/jiangtun/lexer.h delete mode 100644 lib/jiangtun-core/include/jiangtun/parse.h create mode 100644 lib/jiangtun-core/src/board.c create mode 100644 lib/jiangtun-core/src/command.c create mode 100644 lib/jiangtun-core/src/dol.c delete mode 100644 lib/jiangtun-core/src/error.c create mode 100644 lib/jiangtun-core/src/internal.h create mode 100644 lib/jiangtun-core/src/jiangtun.c delete mode 100644 lib/jiangtun-core/src/lex.yy.c delete mode 100644 lib/jiangtun-core/src/lex.yy.extern.h delete mode 100644 lib/jiangtun-core/src/lex.yy.h delete mode 100644 lib/jiangtun-core/src/lexer.c delete mode 100644 lib/jiangtun-core/src/lexer.l create mode 100644 lib/jiangtun-core/src/orca.c create mode 100644 lib/jiangtun-core/test/arduino.c create mode 100644 lib/jiangtun-core/test/command.c delete mode 100644 lib/jiangtun-core/test/lexer.c diff --git a/lib/jiangtun-core/CMakeLists.txt b/lib/jiangtun-core/CMakeLists.txt index bd1b8ff..dfa336f 100644 --- a/lib/jiangtun-core/CMakeLists.txt +++ b/lib/jiangtun-core/CMakeLists.txt @@ -12,7 +12,12 @@ target_compile_options(jiangtun-core PRIVATE -Wall -Wextra -Wpedantic -Werror) enable_testing() -add_executable(jiangtun-core_test_lexer test/lexer.c) -target_link_libraries(jiangtun-core_test_lexer jiangtun-core) -target_compile_options(jiangtun-core_test_lexer PRIVATE -Wall -Wextra -Wpedantic -Werror) -add_test(NAME jiangtun-core_test_lexer COMMAND jiangtun-core_test_lexer) +add_executable(jiangtun-core_test_command test/command.c) +target_link_libraries(jiangtun-core_test_command jiangtun-core) +target_compile_options(jiangtun-core_test_command PRIVATE -Wall -Wextra -Wpedantic -Werror) +add_test(NAME jiangtun-core_test_command COMMAND jiangtun-core_test_command) + +add_executable(jiangtun-core_test_arduino test/arduino.c) +target_link_libraries(jiangtun-core_test_arduino jiangtun-core) +target_compile_options(jiangtun-core_test_arduino PRIVATE -Wall -Wextra -Wpedantic -Werror) +add_test(NAME jiangtun-core_test_arduino COMMAND jiangtun-core_test_arduino) diff --git a/lib/jiangtun-core/Dockerfile.flex b/lib/jiangtun-core/Dockerfile.flex deleted file mode 100644 index 7b6bfcc..0000000 --- a/lib/jiangtun-core/Dockerfile.flex +++ /dev/null @@ -1,12 +0,0 @@ -FROM ubuntu:24.04 - -# ``` -# $ docker build --tag flex:2.6.4-8.2build1 --file .\Dockerfile.flex . -# ``` - -RUN apt-get update && apt-get install --yes \ - # apt list -a flex - flex=2.6.4-8.2build1 \ - && rm -rf /var/lib/apt/lists/* - -ENTRYPOINT [ "flex" ] \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun.h b/lib/jiangtun-core/include/jiangtun.h index 8494c0f..bc94b61 100644 --- a/lib/jiangtun-core/include/jiangtun.h +++ b/lib/jiangtun-core/include/jiangtun.h @@ -1,17 +1,50 @@ #ifndef JIANGTUN_H #define JIANGTUN_H +#include "jiangtun/board.h" +#include "jiangtun/command.h" #include "jiangtun/compat.h" -#include "jiangtun/error.h" -#include "jiangtun/lexer.h" -#include "jiangtun/parse.h" #include "jiangtun/report.h" #ifdef __cplusplus extern "C" { #endif +#define JIANGTUN_TIMEOUT_5MS 50 +#define JIANGTUN_AT_SIGN_500MS 500 +typedef jiangtun_uint32_t jiangtun_feature_flag_t; +#define JIANGTUN_FEATURE_ENABLE_LED_BLINK ((jiangtun_feature_flag_t)(1 << 4)) +#define JIANGTUN_FEATURE_ENABLE_NXMC2 ((jiangtun_feature_flag_t)(1 << 3)) +#define JIANGTUN_FEATURE_ENABLE_POKECON ((jiangtun_feature_flag_t)(1 << 2)) +#define JIANGTUN_FEATURE_ENABLE_ORCA ((jiangtun_feature_flag_t)(1 << 1)) +#define JIANGTUN_FEATURE_ENABLE_DOL ((jiangtun_feature_flag_t)(1 << 0)) + +typedef struct jiangtun_t { + jiangtun_board_t *board; + + jiangtun_nxmc2_command_t nxmc2; + jiangtun_pokecon_command_t pokecon; + jiangtun_orca_command_t orca; + jiangtun_dol_command_t dol; + + jiangtun_command_t *commands[4]; + jiangtun_report_mode3_t reports[4]; + size_t recently_patched; + + jiangtun_uint8_t stash_carry_over_; + jiangtun_uint8_t *carry_over; + + jiangtun_uint32_t timeout_loop_count; + + jiangtun_bool_t at_sign; + jiangtun_uint32_t at_sign_loop_count; + + jiangtun_feature_flag_t features; +} jiangtun_t; + +void jiangtun_init(jiangtun_t *, jiangtun_board_t *, jiangtun_feature_flag_t); +void jiangtun_loop(jiangtun_t *); #ifdef __cplusplus } diff --git a/lib/jiangtun-core/include/jiangtun/board.h b/lib/jiangtun-core/include/jiangtun/board.h new file mode 100644 index 0000000..384f69d --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/board.h @@ -0,0 +1,37 @@ +#ifndef JIANGTUN_BOARD_H +#define JIANGTUN_BOARD_H + +#include "compat.h" +#include "report.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct jiangtun_board_t { + jiangtun_bool_t (*serial_read)(struct jiangtun_board_t *, + jiangtun_uint8_t *); + void (*gamecube_send)(struct jiangtun_board_t *, jiangtun_report_mode3_t *); + void (*led_blink_async)(struct jiangtun_board_t *, jiangtun_uint32_t); +} jiangtun_board_t; + +typedef jiangtun_bool_t (*jiangtun_serial_read_t)(jiangtun_board_t *, + jiangtun_uint8_t *); +typedef void (*jiangtun_gamecube_send_t)(jiangtun_board_t *, + jiangtun_report_mode3_t *); +typedef void (*jiangtun_led_blink_async_t)(jiangtun_board_t *, + jiangtun_uint32_t); + +jiangtun_bool_t jiangtun_board_serial_read(jiangtun_board_t *, + jiangtun_uint8_t *); +void jiangtun_board_gamecube_send(jiangtun_board_t *, + jiangtun_report_mode3_t *); +void jiangtun_board_led_blink_async(jiangtun_board_t *, jiangtun_uint32_t); +void jiangtun_board_init(jiangtun_board_t *, jiangtun_serial_read_t, + jiangtun_gamecube_send_t, jiangtun_led_blink_async_t); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_BOARD_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/command.h b/lib/jiangtun-core/include/jiangtun/command.h new file mode 100644 index 0000000..31d2f42 --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/command.h @@ -0,0 +1,110 @@ +#ifndef JIANGTUN_STATE_H +#define JIANGTUN_STATE_H + +#include "compat.h" +#include "report.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef jiangtun_bool_t (*jiangtun_action_t)(const jiangtun_uint8_t *, size_t, + void *); + +typedef struct jiangtun_command_t { + jiangtun_uint8_t *buffer; + size_t length; + + void (*transition)(struct jiangtun_command_t *, jiangtun_uint8_t); + jiangtun_action_t action; +} jiangtun_command_t; + +/* + * In C, a struct must be declared before it can be used in a function pointer + * declaration. Therefore, `jiangtun_command_t` is declared first, followed by + * the `jiangtun_transition_t` function pointer type. + */ +typedef void (*jiangtun_transition_t)(jiangtun_command_t *, jiangtun_uint8_t); + +void jiangtun_command_init(jiangtun_command_t *, jiangtun_transition_t, + jiangtun_action_t); +void jiangtun_push(jiangtun_command_t *, jiangtun_uint8_t); +jiangtun_bool_t jiangtun_run(jiangtun_command_t *, void *); + +jiangtun_bool_t jiangtun_pending(jiangtun_command_t *); +jiangtun_bool_t jiangtun_accepted(jiangtun_command_t *); +jiangtun_bool_t jiangtun_rejected(jiangtun_command_t *); + +/** + * NX Macro Controller + * + * - https://blog.bzl-web.com/entry/2020/01/20/165719 + * - https://github.com/608/CH55xSwitchSerialControl + * + * `^\xab[\x00-\xff]{2}[\x00-\x08][\x00-\xff]{7}` + * + * ref: + * https://scrapbox.io/yatsuna827827-12010999/Nintendo_Switch%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%BB%95%E6%A7%98%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B + */ +typedef struct jiangtun_nxmc2_command_t { + jiangtun_command_t base; + jiangtun_uint8_t buffer[11]; +} jiangtun_nxmc2_command_t; + +void jiangtun_nxmc2_init(jiangtun_nxmc2_command_t *); + +/** + * Poke-Controller + * + * - https://github.com/KawaSwitch/Poke-Controller + * - https://github.com/Moi-poke/Poke-Controller-Modified + * - https://github.com/futo030/Poke-Controller-Modified-Extension + * + * `^(((0x)?[0-9a-f]{1,4} [0-8]( (0x)?[0-9a-f]{1,2} (0x)?[0-9a-f]{1,2}( + * (0x)?[0-9a-f]{1,2} (0x)?[0-9a-f]{1,2})?)?)|end)\r?\n` + * + * ref: + * https://github.com/KawaSwitch/Poke-Controller/wiki/%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E4%B8%AD%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 + */ +typedef struct jiangtun_pokecon_command_t { + jiangtun_command_t base; + jiangtun_uint8_t buffer[sizeof("0x0003 0 0x00 0x00 0x00 0x00\r\n") - 1]; +} jiangtun_pokecon_command_t; + +void jiangtun_pokecon_init(jiangtun_pokecon_command_t *); + +/** + * ORCA GC Controller + * + * - https://github.com/yatsuna827/Orca-GC-Controller + * - https://github.com/mizuyoukanao/Bluewhale + * + * `^(\x80\xff*[^\xff]\xff*[^\xff])|@` + */ +typedef struct jiangtun_orca_command_t { + jiangtun_command_t base; + jiangtun_uint8_t buffer[3]; +} jiangtun_orca_command_t; + +void jiangtun_orca_init(jiangtun_orca_command_t *); + +/** + * DOL Macro Controller + * + * - https://katari-na.hatenablog.com/entry/2021/03/08/160937 + * - https://github.com/mizuyoukanao/Bluewhale + * + * `^[a-z0-9@]` + */ +typedef struct jiangtun_dol_command_t { + jiangtun_command_t base; + jiangtun_uint8_t buffer[1]; +} jiangtun_dol_command_t; + +void jiangtun_dol_init(jiangtun_dol_command_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_STATE_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/compat.h b/lib/jiangtun-core/include/jiangtun/compat.h index 7f7cfe2..c5b5def 100644 --- a/lib/jiangtun-core/include/jiangtun/compat.h +++ b/lib/jiangtun-core/include/jiangtun/compat.h @@ -8,30 +8,39 @@ extern "C" { #endif -typedef enum jiangtun_bool_t { JIANGTUN_FALSE, JIANGTUN_TRUE } jiangtun_bool_t; - typedef unsigned char jiangtun_uint8_t; +#define JIANGTUN_UINT8_MAX UCHAR_MAX #if USHRT_MAX == 0xFFFF typedef unsigned short jiangtun_uint16_t; +#define JIANGTUN_UINT16_MAX USHRT_MAX #elif UINT_MAX == 0xFFFF typedef unsigned int jiangtun_uint16_t; +#define JIANGTUN_UINT16_MAX UINT_MAX #elif ULONG_MAX == 0xFFFF typedef unsigned long jiangtun_uint16_t; +#define JIANGTUN_UINT16_MAX ULONG_MAX #else #error "No suitable type for jiangtun_uint16_t" #endif #if UINT_MAX == 0xFFFFFFFF typedef unsigned int jiangtun_uint32_t; +#define JIANGTUN_UINT32_MAX UINT_MAX #elif ULONG_MAX == 0xFFFFFFFF typedef unsigned long jiangtun_uint32_t; +#define JIANGTUN_UINT32_MAX ULONG_MAX #elif ULLONG_MAX == 0xFFFFFFFF typedef unsigned long long jiangtun_uint32_t; +#define JIANGTUN_UINT32_MAX ULLONG_MAX #else #error "No suitable type for jiangtun_uint32_t" #endif +typedef jiangtun_uint8_t jiangtun_bool_t; +#define JIANGTUN_FALSE ((jiangtun_bool_t)0) +#define JIANGTUN_TRUE ((jiangtun_bool_t)1) + #ifdef __cplusplus } #endif diff --git a/lib/jiangtun-core/include/jiangtun/error.h b/lib/jiangtun-core/include/jiangtun/error.h deleted file mode 100644 index efd1cf8..0000000 --- a/lib/jiangtun-core/include/jiangtun/error.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef JIANGTUN_ERROR_H -#define JIANGTUN_ERROR_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum jiangtun_error_t { - JIANGTUN_SUCCESS, - JIANGTUN_ERROR_NULL_POINTER, - JIANGTUN_ERROR_INVALID_ARGUMENT, - JIANGTUN_ERROR_PARSE_FAILURE, - JIANGTUN_ERROR_INTERNAL -} jiangtun_error_t; - -const char *jiangtun_error_stringify(jiangtun_error_t); - -#ifdef __cplusplus -} -#endif - -#endif /* JIANGTUN_ERROR_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/lexer.h b/lib/jiangtun-core/include/jiangtun/lexer.h deleted file mode 100644 index 91b8898..0000000 --- a/lib/jiangtun-core/include/jiangtun/lexer.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef JIANGTUN_LEXER_H -#define JIANGTUN_LEXER_H - -#include "compat.h" -#include "error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum jiangtun_yy_match_t { - JIANGTUN_YY_NO_MATCH, - JIANGTUN_YY_MATCH_NXMC2, - JIANGTUN_YY_MATCH_POKECON, - JIANGTUN_YY_MATCH_ORCA -} jiangtun_yy_match_t; - -typedef struct jiangtun_yy_extra_t { - jiangtun_bool_t partial; - jiangtun_yy_match_t return_; -} jiangtun_yy_extra_t; - -typedef struct jiangtun_lexer_t { - void *scanner; - jiangtun_yy_extra_t extra; -} jiangtun_lexer_t; - -typedef enum jiangtun_lexer_result_t { - JIANGTUN_LEXER_NO_MATCH, - JIANGTUN_LEXER_MATCH_PARTIAL, - JIANGTUN_LEXER_MATCH_NXMC2, - JIANGTUN_LEXER_MATCH_POKECON, - JIANGTUN_LEXER_MATCH_ORCA -} jiangtun_lexer_result_t; - -const char *jiangtun_lexer_result_stringify(jiangtun_lexer_result_t); - -jiangtun_error_t jiangtun_lexer_init(jiangtun_lexer_t *); -jiangtun_error_t jiangtun_lexer_deinit(jiangtun_lexer_t *); -jiangtun_error_t jiangtun_lex(jiangtun_lexer_t *, const jiangtun_uint8_t *, - size_t, jiangtun_lexer_result_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* JIANGTUN_LEXER_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/parse.h b/lib/jiangtun-core/include/jiangtun/parse.h deleted file mode 100644 index 19dce33..0000000 --- a/lib/jiangtun-core/include/jiangtun/parse.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef JIANGTUN_PARSE_H -#define JIANGTUN_PARSE_H - -#include "compat.h" -#include "error.h" -#include "report.h" - -#ifdef __cplusplus -extern "C" { -#endif - -jiangtun_error_t jiangtun_nxmc2_parse(const jiangtun_uint8_t *, size_t, - jiangtun_report_t *, jiangtun_bool_t *); - -typedef struct jiangtun_pokecon_previous_state_t { - struct { - jiangtun_uint8_t x; - jiangtun_uint8_t y; - } left; - struct { - jiangtun_uint8_t x; - jiangtun_uint8_t y; - } right; -} jiangtun_pokecon_previous_state_t; - -jiangtun_error_t -jiangtun_pokecon_previous_state_init(jiangtun_pokecon_previous_state_t *); -jiangtun_error_t jiangtun_pokecon_parse(const jiangtun_uint8_t *, size_t, - jiangtun_report_t *, jiangtun_bool_t *, - jiangtun_pokecon_previous_state_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* JIANGTUN_PARSE_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/report.h b/lib/jiangtun-core/include/jiangtun/report.h index 2b3d59b..9f5329a 100644 --- a/lib/jiangtun-core/include/jiangtun/report.h +++ b/lib/jiangtun-core/include/jiangtun/report.h @@ -2,224 +2,57 @@ #define JIANGTUN_REPORT_H #include "compat.h" -#include "error.h" - -/* - * These codes actually depend on the PODs defined in `Bluewhale.h`. - */ -#ifdef ARDUINO -#include -#if __cplusplus >= 201103L -#include -static_assert(std::is_trivially_copyable::value, - "Gamecube_Report_t must be a POD type"); -#endif -#endif #ifdef __cplusplus extern "C" { #endif -/* clang-format off */ /** - * Equivalent data structure to `Bluewhale::Gamecube_Report_t` at the source - * code level, for ease of testing from pure C code. Please take a diff and - * update this if Bluewhale is changed. - * - * `$ diff -u --minimal <(sed -n '31,217p' include/jiangtun/report.h) <(sed -n '48,234p' lib/Bluewhale/src/Gamecube.h)` + * Equivalent data structure to `Gamecube_Report_t` + * Be careful when updating Bluewhale. + * + * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/src/Gamecube.h#L62-L90 */ -typedef union jiangtun_report_t { - /* 8 bytes of datareport that we get from the controller */ - jiangtun_uint8_t raw8[8]; - /* jiangtun_uint16_t raw16[0]; - ISO C forbids zero-size array */ - /* jiangtun_uint32_t raw32[0]; - ISO C forbids zero-size array */ - - struct { - jiangtun_uint8_t buttons0; - union { - jiangtun_uint8_t buttons1; - jiangtun_uint8_t dpad/* : 4 - type of bit-field ~ is a GCC extension*/; - } unnamed_0; /* - ISO C90 doesn't support unnamed structs/unions */ - } unnamed_1; - - struct { - /* first data byte (bitfields are sorted in LSB order) */ - jiangtun_uint8_t a/* : 1 */; - jiangtun_uint8_t b/* : 1 */; - jiangtun_uint8_t x/* : 1 */; - jiangtun_uint8_t y/* : 1 */; - jiangtun_uint8_t start/* : 1 */; - jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ - jiangtun_uint8_t errlatch/* : 1 */; - jiangtun_uint8_t errstat/* : 1 */; - - /* second data byte */ - jiangtun_uint8_t dleft/* : 1 */; - jiangtun_uint8_t dright/* : 1 */; - jiangtun_uint8_t ddown/* : 1 */; - jiangtun_uint8_t dup/* : 1 */; - jiangtun_uint8_t z/* : 1 */; - jiangtun_uint8_t r/* : 1 */; - jiangtun_uint8_t l/* : 1 */; - jiangtun_uint8_t high1/* : 1 */; - - /* 3rd-8th data byte */ - jiangtun_uint8_t xAxis; - jiangtun_uint8_t yAxis; - jiangtun_uint8_t cxAxis; - jiangtun_uint8_t cyAxis; - jiangtun_uint8_t left; - jiangtun_uint8_t right; - } mode3; /* mode3 (default reading mode) */ - - struct { - /* first data byte (bitfields are sorted in LSB order) */ - jiangtun_uint8_t a/* : 1 */; - jiangtun_uint8_t b/* : 1 */; - jiangtun_uint8_t x/* : 1 */; - jiangtun_uint8_t y/* : 1 */; - jiangtun_uint8_t start/* : 1 */; - jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ - jiangtun_uint8_t errlatch/* : 1 */; - jiangtun_uint8_t errstat/* : 1 */; - - /* second data byte */ - jiangtun_uint8_t dleft/* : 1 */; - jiangtun_uint8_t dright/* : 1 */; - jiangtun_uint8_t ddown/* : 1 */; - jiangtun_uint8_t dup/* : 1 */; - jiangtun_uint8_t z/* : 1 */; - jiangtun_uint8_t r/* : 1 */; - jiangtun_uint8_t l/* : 1 */; - jiangtun_uint8_t high1/* : 1 */; - - /* 3rd-8th data byte */ - jiangtun_uint8_t xAxis; - jiangtun_uint8_t yAxis; - jiangtun_uint8_t cxAxis; - jiangtun_uint8_t cyAxis; - jiangtun_uint8_t right/* : 4 */; /* note: within bytes, LSB is first */ - jiangtun_uint8_t left/* : 4 */; - jiangtun_uint8_t analogB/* : 4 */; - jiangtun_uint8_t analogA/* : 4 */; - } mode0; - - struct { - /* first data byte (bitfields are sorted in LSB order) */ - jiangtun_uint8_t a/* : 1 */; - jiangtun_uint8_t b/* : 1 */; - jiangtun_uint8_t x/* : 1 */; - jiangtun_uint8_t y/* : 1 */; - jiangtun_uint8_t start/* : 1 */; - jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ - jiangtun_uint8_t errlatch/* : 1 */; - jiangtun_uint8_t errstat/* : 1 */; - - /* second data byte */ - jiangtun_uint8_t dleft/* : 1 */; - jiangtun_uint8_t dright/* : 1 */; - jiangtun_uint8_t ddown/* : 1 */; - jiangtun_uint8_t dup/* : 1 */; - jiangtun_uint8_t z/* : 1 */; - jiangtun_uint8_t r/* : 1 */; - jiangtun_uint8_t l/* : 1 */; - jiangtun_uint8_t high1/* : 1 */; - - /* 3rd-8th data byte */ - jiangtun_uint8_t xAxis; - jiangtun_uint8_t yAxis; - jiangtun_uint8_t cyAxis/* : 4 */; - jiangtun_uint8_t cxAxis/* : 4 */; - jiangtun_uint8_t left; - jiangtun_uint8_t right; - jiangtun_uint8_t analogB/* : 4 */; - jiangtun_uint8_t analogA/* : 4 */; - } mode1; - - struct { - /* first data byte (bitfields are sorted in LSB order) */ - jiangtun_uint8_t a/* : 1 */; - jiangtun_uint8_t b/* : 1 */; - jiangtun_uint8_t x/* : 1 */; - jiangtun_uint8_t y/* : 1 */; - jiangtun_uint8_t start/* : 1 */; - jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ - jiangtun_uint8_t errlatch/* : 1 */; - jiangtun_uint8_t errstat/* : 1 */; - - /* second data byte */ - jiangtun_uint8_t dleft/* : 1 */; - jiangtun_uint8_t dright/* : 1 */; - jiangtun_uint8_t ddown/* : 1 */; - jiangtun_uint8_t dup/* : 1 */; - jiangtun_uint8_t z/* : 1 */; - jiangtun_uint8_t r/* : 1 */; - jiangtun_uint8_t l/* : 1 */; - jiangtun_uint8_t high1/* : 1 */; - - /* 3rd-8th data byte */ - jiangtun_uint8_t xAxis; - jiangtun_uint8_t yAxis; - jiangtun_uint8_t cyAxis/* : 4 */; - jiangtun_uint8_t cxAxis/* : 4 */; - jiangtun_uint8_t right/* : 4 */; - jiangtun_uint8_t left/* : 4 */; - jiangtun_uint8_t analogA; - jiangtun_uint8_t analogB; - } mode2; - - struct { - /* first data byte (bitfields are sorted in LSB order) */ - jiangtun_uint8_t a/* : 1 */; - jiangtun_uint8_t b/* : 1 */; - jiangtun_uint8_t x/* : 1 */; - jiangtun_uint8_t y/* : 1 */; - jiangtun_uint8_t start/* : 1 */; - jiangtun_uint8_t origin/* : 1 */; /* Indicates if GetOrigin(0x41) was called (LOW) */ - jiangtun_uint8_t errlatch/* : 1 */; - jiangtun_uint8_t errstat/* : 1 */; - - /* second data byte */ - jiangtun_uint8_t dleft/* : 1 */; - jiangtun_uint8_t dright/* : 1 */; - jiangtun_uint8_t ddown/* : 1 */; - jiangtun_uint8_t dup/* : 1 */; - jiangtun_uint8_t z/* : 1 */; - jiangtun_uint8_t r/* : 1 */; - jiangtun_uint8_t l/* : 1 */; - jiangtun_uint8_t high1/* : 1 */; - - /* 3rd-8th data byte */ - jiangtun_uint8_t xAxis; - jiangtun_uint8_t yAxis; - jiangtun_uint8_t cxAxis; - jiangtun_uint8_t cyAxis; - jiangtun_uint8_t analogA; - jiangtun_uint8_t analogB; - } mode4; - - struct { - /* first data byte (bitfields are sorted in LSB order) */ - jiangtun_uint8_t unknown_counter1/* : 4 */; - jiangtun_uint8_t unknown1/* : 2 */; - jiangtun_uint8_t errlatch/* : 1 */; - jiangtun_uint8_t errstat/* : 1 */; - - jiangtun_uint16_t unknown2/* : 16 */; - jiangtun_uint8_t unknown3; - - jiangtun_uint8_t keypress[3]; - - jiangtun_uint8_t unknown_counter2/* : 4 */; - jiangtun_uint8_t unknown4/* : 4 */; - } keyboard; - -} jiangtun_report_t; -/* clang-format on */ +typedef struct jiangtun_report_mode3_t { + jiangtun_bool_t a; + jiangtun_bool_t b; + jiangtun_bool_t x; + jiangtun_bool_t y; + jiangtun_bool_t start; + jiangtun_bool_t origin; + jiangtun_bool_t errlatch; + jiangtun_bool_t errstat; + + jiangtun_bool_t dleft; + jiangtun_bool_t dright; + jiangtun_bool_t ddown; + jiangtun_bool_t dup; + jiangtun_bool_t z; + jiangtun_bool_t r; + jiangtun_bool_t l; + jiangtun_bool_t high1; + + jiangtun_uint8_t xAxis; + jiangtun_uint8_t yAxis; + jiangtun_uint8_t cxAxis; + jiangtun_uint8_t cyAxis; + jiangtun_uint8_t left; + jiangtun_uint8_t right; + + jiangtun_bool_t reset; +} jiangtun_report_mode3_t; #define JIANGTUN_REPORT_STICK_NEUTRAL 128 +#define JIANGTUN_REPORT_STICK_DOWN 0 +#define JIANGTUN_REPORT_STICK_UP 255 +#define JIANGTUN_REPORT_STICK_LEFT 0 +#define JIANGTUN_REPORT_STICK_RIGHT 255 + +/** + * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/examples/WHALE/WHALE.ino#L17-L34 + */ +void jiangtun_report_init(jiangtun_report_mode3_t *); -jiangtun_error_t jiangtun_report_init(jiangtun_report_t *); /** * Adjust the axis values to fall within the range of 1 to 254 to ensure proper * recognition by the games. @@ -228,7 +61,7 @@ jiangtun_error_t jiangtun_report_init(jiangtun_report_t *); * controller's axis values do not usually occur in actual input. As a result, * some games may not handle these values correctly. */ -jiangtun_error_t jiangtun_report_emend_axis(jiangtun_report_t *); +void jiangtun_emend_axis(jiangtun_report_mode3_t *); #ifdef __cplusplus } diff --git a/lib/jiangtun-core/src/board.c b/lib/jiangtun-core/src/board.c new file mode 100644 index 0000000..02d487d --- /dev/null +++ b/lib/jiangtun-core/src/board.c @@ -0,0 +1,40 @@ +#include + +#include + +jiangtun_bool_t jiangtun_board_serial_read(jiangtun_board_t *board, + jiangtun_uint8_t *c) { + assert(board != NULL); + assert(c != NULL); + + return board->serial_read(board, c); +} + +void jiangtun_board_gamecube_send(jiangtun_board_t *board, + jiangtun_report_mode3_t *report) { + assert(board != NULL); + assert(report != NULL); + + board->gamecube_send(board, report); +} + +void jiangtun_board_led_blink_async(jiangtun_board_t *board, + jiangtun_uint32_t duration) { + assert(board != NULL); + + board->led_blink_async(board, duration); +} + +void jiangtun_board_init(jiangtun_board_t *board, + jiangtun_serial_read_t serial_read, + jiangtun_gamecube_send_t gamecube_send, + jiangtun_led_blink_async_t led_blink_async) { + assert(board != NULL); + assert(serial_read != NULL); + assert(gamecube_send != NULL); + assert(led_blink_async != NULL); + + board->serial_read = serial_read; + board->gamecube_send = gamecube_send; + board->led_blink_async = led_blink_async; +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/command.c b/lib/jiangtun-core/src/command.c new file mode 100644 index 0000000..134e1bb --- /dev/null +++ b/lib/jiangtun-core/src/command.c @@ -0,0 +1,87 @@ +#include + +#include + +static void transition_default(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + (void)c; + jiangtun_command_init(command, NULL, NULL); +} + +static jiangtun_bool_t action_default(const jiangtun_uint8_t *buffer, + size_t length, void *context) { + (void)buffer; + (void)length; + (void)context; + + return JIANGTUN_FALSE; +} + +static jiangtun_bool_t jiangtun_terminal(jiangtun_command_t *command) { + assert(command != NULL); + + return command->transition == transition_default || + /* for safety */ command->transition == NULL; +} + +jiangtun_bool_t jiangtun_pending(jiangtun_command_t *command) { + assert(command != NULL); + + return !jiangtun_terminal(command) && + (command->action == action_default || + /* for safety */ command->action == NULL); +} + +jiangtun_bool_t jiangtun_accepted(jiangtun_command_t *command) { + assert(command != NULL); + + return command->action != action_default && + /* for safety */ command->action != NULL; +} + +jiangtun_bool_t jiangtun_rejected(jiangtun_command_t *command) { + assert(command != NULL); + + return jiangtun_terminal(command) && + (command->action == action_default || + /* for safety */ command->action == NULL); +} + +void jiangtun_command_init(jiangtun_command_t *command, + jiangtun_transition_t transition, + jiangtun_action_t action) { + assert(command != NULL); + + command->transition = transition != NULL ? transition : transition_default; + command->action = action != NULL ? action : action_default; +} + +void append_if_not_rejected(jiangtun_command_t *command, jiangtun_uint8_t c, + jiangtun_transition_t transition, + jiangtun_action_t action) { + assert(command != NULL); + + jiangtun_command_init(command, transition, action); + if (!jiangtun_rejected(command)) { + command->buffer[command->length++] = c; + } +} + +void jiangtun_push(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + if (jiangtun_terminal(command)) { + jiangtun_command_init(command, NULL, NULL); + } + command->transition(command, c); +} + +jiangtun_bool_t jiangtun_run(jiangtun_command_t *command, void *context) { + assert(command != NULL); + + return jiangtun_accepted(command) + ? command->action(command->buffer, command->length, context) + : JIANGTUN_FALSE; +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/dol.c b/lib/jiangtun-core/src/dol.c new file mode 100644 index 0000000..083a303 --- /dev/null +++ b/lib/jiangtun-core/src/dol.c @@ -0,0 +1,156 @@ +#include + +#include "internal.h" + +#include + +static jiangtun_bool_t is_valid_char(jiangtun_uint8_t c) { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || c == '@'; +} + +/** + * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/examples/WHALE/WHALE.ino#L47-L194 + */ +static jiangtun_bool_t patch(const jiangtun_uint8_t *buffer, size_t length, + void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + assert(buffer != NULL); + assert(length == 1); + assert(is_valid_char(buffer[0])); + assert(report != NULL); + + switch (buffer[0]) { + case 'a': + report->a = JIANGTUN_TRUE; + break; + case 'b': + report->b = JIANGTUN_TRUE; + break; + case 'c': + report->x = JIANGTUN_TRUE; + break; + case 'd': + report->y = JIANGTUN_TRUE; + break; + case 'e': + report->l = JIANGTUN_TRUE; + break; + case 'f': + report->r = JIANGTUN_TRUE; + break; + case 'g': + report->z = JIANGTUN_TRUE; + break; + case 'h': + report->start = JIANGTUN_TRUE; + break; + case 'i': + report->dleft = JIANGTUN_TRUE; + break; + case 'j': + report->dright = JIANGTUN_TRUE; + break; + case 'k': + report->ddown = JIANGTUN_TRUE; + break; + case 'l': + report->dup = JIANGTUN_TRUE; + break; + case 'm': + report->a = JIANGTUN_FALSE; + break; + case 'n': + report->b = JIANGTUN_FALSE; + break; + case 'o': + report->x = JIANGTUN_FALSE; + break; + case 'p': + report->y = JIANGTUN_FALSE; + break; + case 'q': + report->l = JIANGTUN_FALSE; + break; + case 'r': + report->r = JIANGTUN_FALSE; + break; + case 's': + report->z = JIANGTUN_FALSE; + break; + case 't': + report->start = JIANGTUN_FALSE; + break; + case 'u': + report->dleft = JIANGTUN_FALSE; + break; + case 'v': + report->dright = JIANGTUN_FALSE; + break; + case 'w': + report->ddown = JIANGTUN_FALSE; + break; + case 'x': + report->dup = JIANGTUN_FALSE; + break; + case 'y': + report->xAxis = JIANGTUN_REPORT_STICK_LEFT; + break; + case 'z': + report->xAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + break; + case '1': + report->xAxis = JIANGTUN_REPORT_STICK_RIGHT; + break; + case '2': + report->yAxis = JIANGTUN_REPORT_STICK_DOWN; + break; + case '3': + report->yAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + break; + case '4': + report->yAxis = JIANGTUN_REPORT_STICK_UP; + break; + case '5': + report->cxAxis = JIANGTUN_REPORT_STICK_LEFT; + break; + case '6': + report->cxAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + break; + case '7': + report->cxAxis = JIANGTUN_REPORT_STICK_RIGHT; + break; + case '8': + report->cyAxis = JIANGTUN_REPORT_STICK_DOWN; + break; + case '9': + report->cyAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + break; + case '0': + report->cyAxis = JIANGTUN_REPORT_STICK_UP; + break; + case '@': + report->reset = JIANGTUN_TRUE; + break; + default: + assert(JIANGTUN_FALSE); + break; + } + + return JIANGTUN_TRUE; +} + +static void transition_initial(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, NULL, is_valid_char(c) ? patch : NULL); +} + +void jiangtun_dol_init(jiangtun_dol_command_t *command) { + assert(command != NULL); + + command->base.buffer = command->buffer; + command->base.length = 0; + + jiangtun_command_init(&(command->base), transition_initial, NULL); +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/error.c b/lib/jiangtun-core/src/error.c deleted file mode 100644 index 2821bb6..0000000 --- a/lib/jiangtun-core/src/error.c +++ /dev/null @@ -1,23 +0,0 @@ -#include - -const char *jiangtun_error_stringify(jiangtun_error_t err) { - switch (err) { - case JIANGTUN_SUCCESS: - return "JIANGTUN_SUCCESS"; - - case JIANGTUN_ERROR_NULL_POINTER: - return "JIANGTUN_ERROR_NULL_POINTER"; - - case JIANGTUN_ERROR_INVALID_ARGUMENT: - return "JIANGTUN_ERROR_INVALID_ARGUMENT"; - - case JIANGTUN_ERROR_PARSE_FAILURE: - return "JIANGTUN_ERROR_PARSE_FAILURE"; - - case JIANGTUN_ERROR_INTERNAL: - return "JIANGTUN_ERROR_INTERNAL"; - - default: - return "unknown"; - } -} \ No newline at end of file diff --git a/lib/jiangtun-core/src/internal.h b/lib/jiangtun-core/src/internal.h new file mode 100644 index 0000000..cf59fb1 --- /dev/null +++ b/lib/jiangtun-core/src/internal.h @@ -0,0 +1,17 @@ +#ifndef JIANGTUN_INTERNAL_H +#define JIANGTUN_INTERNAL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void append_if_not_rejected(jiangtun_command_t *, jiangtun_uint8_t, + jiangtun_transition_t, jiangtun_action_t); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_INTERNAL_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/src/jiangtun.c b/lib/jiangtun-core/src/jiangtun.c new file mode 100644 index 0000000..33a80d6 --- /dev/null +++ b/lib/jiangtun-core/src/jiangtun.c @@ -0,0 +1,132 @@ +#include + +#include + +static void commands_init(jiangtun_t *j) { + assert(j != NULL); + + j->commands[0] = &(j->nxmc2.base); + j->commands[1] = &(j->pokecon.base); + j->commands[2] = &(j->orca.base); + j->commands[3] = &(j->dol.base); + + if (j->features & JIANGTUN_FEATURE_ENABLE_NXMC2) { + jiangtun_nxmc2_init(&(j->nxmc2)); + } else { + jiangtun_command_init(j->commands[0], NULL, NULL); + } + + if (j->features & JIANGTUN_FEATURE_ENABLE_POKECON) { + jiangtun_pokecon_init(&(j->pokecon)); + } else { + jiangtun_command_init(j->commands[1], NULL, NULL); + } + + if (j->features & JIANGTUN_FEATURE_ENABLE_ORCA) { + jiangtun_orca_init(&(j->orca)); + } else { + jiangtun_command_init(j->commands[2], NULL, NULL); + } + + if (j->features & JIANGTUN_FEATURE_ENABLE_DOL) { + jiangtun_dol_init(&(j->dol)); + } else { + jiangtun_command_init(j->commands[3], NULL, NULL); + } +} + +static void reports_init(jiangtun_t *j) { + assert(j != NULL); + + jiangtun_report_init(&(j->reports[0])); + jiangtun_report_init(&(j->reports[1])); + jiangtun_report_init(&(j->reports[2])); + jiangtun_report_init(&(j->reports[3])); +} + +void jiangtun_init(jiangtun_t *j, jiangtun_board_t *board, + jiangtun_feature_flag_t features) { + assert(j != NULL); + assert(board != NULL); + + j->features = features; + + reports_init(j); + commands_init(j); + + j->board = board; + j->recently_patched = 0; + j->stash_carry_over_ = 0; + j->carry_over = NULL; + j->timeout_loop_count = 0; + j->at_sign = JIANGTUN_FALSE; + j->at_sign_loop_count = 0; + + /* + * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/examples/WHALE/WHALE.ino#L36-L41 + */ + j->reports[0].start = JIANGTUN_TRUE; + jiangtun_board_gamecube_send(j->board, &(j->reports[0])); + + j->reports[0].start = JIANGTUN_FALSE; + jiangtun_board_gamecube_send(j->board, &(j->reports[0])); +} + +void jiangtun_loop(jiangtun_t *j) { + size_t i = 0; + jiangtun_uint8_t c = 0; + jiangtun_bool_t at_sign = JIANGTUN_FALSE; + jiangtun_bool_t any_pending = JIANGTUN_FALSE; + jiangtun_report_mode3_t *report = NULL; + assert(j != NULL); + + if (j->at_sign) { + goto gamecube_send; + } + + if (j->carry_over == NULL && !jiangtun_board_serial_read(j->board, &c)) { + if (++(j->timeout_loop_count) > JIANGTUN_TIMEOUT_5MS) { + commands_init(j); + j->timeout_loop_count = 0; + } + goto gamecube_send; + } + + j->timeout_loop_count = 0; + if (j->carry_over != NULL) { + c = *(j->carry_over); + j->carry_over = NULL; + } + + for (i = 0; i < 4; i++) { + jiangtun_push(j->commands[i], c); + if (jiangtun_accepted(j->commands[i])) { + jiangtun_run(j->commands[i], &(j->reports[i])); + commands_init(j); + j->recently_patched = i; + at_sign = c == '@'; + goto gamecube_send; + + } else if (jiangtun_pending(j->commands[i])) { + any_pending = JIANGTUN_TRUE; + } + } + if (!any_pending) { + j->stash_carry_over_ = c; + j->carry_over = &(j->stash_carry_over_); + commands_init(j); + } + +gamecube_send: + report = &(j->reports[j->recently_patched]); + if (j->at_sign && ++(j->at_sign_loop_count) > JIANGTUN_AT_SIGN_500MS) { + report->reset = JIANGTUN_FALSE; + j->at_sign_loop_count = 0; + } + jiangtun_emend_axis(report); + jiangtun_board_gamecube_send(j->board, report); + if (j->features & JIANGTUN_FEATURE_ENABLE_LED_BLINK) { + jiangtun_board_led_blink_async(j->board, 50); + } + j->at_sign = at_sign; +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/lex.yy.c b/lib/jiangtun-core/src/lex.yy.c deleted file mode 100644 index bf869ed..0000000 --- a/lib/jiangtun-core/src/lex.yy.c +++ /dev/null @@ -1,2087 +0,0 @@ -#line 2 "src/lex.yy.c" - -#line 4 "src/lex.yy.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 6 -#define YY_FLEX_SUBMINOR_VERSION 4 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#ifndef SIZE_MAX -#define SIZE_MAX (~(size_t)0) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -/* begin standard C++ headers. */ - -/* TODO: this is always defined, so inline it */ -#define yyconst const - -#if defined(__GNUC__) && __GNUC__ >= 3 -#define yynoreturn __attribute__((__noreturn__)) -#else -#define yynoreturn -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an - * integer in range [0..255] for use as an array index. - */ -#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yyg->yy_start = 1 + 2 * -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yyg->yy_start - 1) / 2) -#define YYSTATE YY_START -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin , yyscanner ) -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k. - * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. - * Ditto for the __ia64__ case accordingly. - */ -#define YY_BUF_SIZE 32768 -#else -#define YY_BUF_SIZE 16384 -#endif /* __ia64__ */ -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - #define YY_LINENO_REWIND_TO(ptr) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = yyg->yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) -#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - int yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ - ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ - : NULL) -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] - -void yyrestart ( FILE *input_file , yyscan_t yyscanner ); -void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); -void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); -void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); -void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); -void yypop_buffer_state ( yyscan_t yyscanner ); - -static void yyensure_buffer_stack ( yyscan_t yyscanner ); -static void yy_load_buffer_state ( yyscan_t yyscanner ); -static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); -#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) - -YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); - -void *yyalloc ( yy_size_t , yyscan_t yyscanner ); -void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); -void yyfree ( void * , yyscan_t yyscanner ); - -#define yy_new_buffer yy_create_buffer -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define yywrap(yyscanner) (/*CONSTCOND*/1) -#define YY_SKIP_YYWRAP -typedef flex_uint8_t YY_CHAR; - -typedef int yy_state_type; - -#define yytext_ptr yytext_r - -static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); -static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); -static int yy_get_next_buffer ( yyscan_t yyscanner ); -static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yyg->yytext_ptr = yy_bp; \ - yyg->yytext_ptr -= yyg->yy_more_len; \ - yyleng = (int) (yy_cp - yyg->yytext_ptr); \ - yyg->yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 24 -#define YY_END_OF_BUFFER 25 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static const flex_int16_t yy_accept[61] = - { 0, - 0, 0, 25, 23, 4, 4, 22, 4, 20, 1, - 4, 4, 3, 16, 20, 20, 1, 5, 4, 4, - 16, 22, 21, 1, 18, 5, 6, 4, 19, 17, - 1, 8, 8, 1, 8, 8, 7, 1, 10, 10, - 1, 10, 11, 10, 9, 1, 13, 13, 1, 13, - 13, 12, 1, 15, 15, 2, 15, 15, 14, 0 - } ; - -static const YY_CHAR yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 5, 6, 6, - 6, 6, 6, 6, 6, 6, 7, 1, 1, 1, - 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 7, 7, 7, 9, - - 10, 7, 1, 1, 1, 1, 1, 1, 1, 11, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, - 1, 1, 1, 1, 1, 1, 1, 13, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 15 - } ; - -static const YY_CHAR yy_meta[16] = - { 0, - 1, 2, 2, 3, 4, 4, 4, 1, 4, 4, - 1, 5, 1, 1, 1 - } ; - -static const flex_int16_t yy_base[85] = - { 0, - 0, 0, 161, 162, 12, 13, 162, 149, 144, 0, - 13, 154, 0, 148, 141, 140, 0, 24, 150, 0, - 18, 162, 136, 0, 162, 68, 64, 64, 162, 65, - 0, 18, 19, 0, 61, 61, 0, 0, 30, 52, - 0, 61, 54, 41, 0, 0, 34, 37, 0, 53, - 53, 0, 0, 48, 59, 162, 54, 45, 0, 162, - 71, 74, 79, 84, 87, 51, 91, 96, 99, 103, - 50, 108, 111, 116, 49, 121, 126, 48, 131, 134, - 139, 25, 144, 148 - } ; - -static const flex_int16_t yy_def[85] = - { 0, - 61, 60, 60, 60, 62, 62, 60, 6, 63, 64, - 60, 65, 66, 60, 67, 63, 68, 60, 69, 6, - 60, 60, 67, 70, 60, 60, 71, 60, 60, 60, - 72, 73, 73, 74, 75, 60, 71, 76, 60, 39, - 77, 60, 78, 60, 75, 79, 80, 80, 81, 82, - 60, 78, 83, 84, 84, 60, 60, 60, 82, 0, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60 - } ; - -static const flex_int16_t yy_nxt[178] = - { 0, - 4, 4, 4, 4, 5, 6, 6, 7, 6, 8, - 4, 4, 9, 10, 4, 11, 11, 18, 18, 29, - 30, 35, 35, 13, 60, 25, 26, 27, 55, 37, - 60, 25, 42, 43, 44, 44, 44, 50, 44, 44, - 50, 45, 25, 42, 43, 52, 25, 57, 60, 25, - 57, 48, 40, 33, 20, 25, 50, 54, 47, 59, - 25, 57, 25, 60, 35, 39, 29, 11, 32, 25, - 60, 4, 4, 4, 4, 4, 12, 12, 12, 15, - 15, 15, 15, 15, 17, 17, 17, 17, 17, 19, - 19, 22, 22, 22, 22, 22, 24, 24, 24, 24, - - 24, 28, 28, 31, 31, 31, 31, 31, 34, 34, - 34, 34, 34, 36, 36, 36, 38, 38, 38, 38, - 38, 41, 41, 41, 41, 41, 46, 46, 46, 46, - 46, 49, 49, 49, 49, 49, 51, 51, 51, 53, - 53, 53, 53, 53, 56, 56, 56, 56, 56, 58, - 23, 58, 58, 11, 16, 23, 21, 11, 16, 14, - 60, 3, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60 - } ; - -static const flex_int16_t yy_chk[178] = - { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 5, 6, 11, 11, 21, - 21, 32, 33, 5, 6, 18, 18, 18, 82, 32, - 33, 39, 39, 39, 39, 39, 39, 47, 39, 39, - 48, 39, 44, 44, 44, 47, 58, 58, 48, 54, - 54, 78, 75, 71, 66, 57, 51, 50, 43, 54, - 55, 55, 42, 40, 36, 35, 30, 28, 27, 26, - 55, 61, 61, 61, 61, 61, 62, 62, 62, 63, - 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, - 65, 67, 67, 67, 67, 67, 68, 68, 68, 68, - - 68, 69, 69, 70, 70, 70, 70, 70, 72, 72, - 72, 72, 72, 73, 73, 73, 74, 74, 74, 74, - 74, 76, 76, 76, 76, 76, 77, 77, 77, 77, - 77, 79, 79, 79, 79, 79, 80, 80, 80, 81, - 81, 81, 81, 81, 83, 83, 83, 83, 83, 84, - 23, 84, 84, 19, 16, 15, 14, 12, 9, 8, - 3, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60 - } ; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() (yyg->yy_more_flag = 1) -#define YY_MORE_ADJ yyg->yy_more_len -#define YY_RESTORE_YY_MORE_OFFSET -#line 1 "src/lexer.l" -#define YY_NO_INPUT 1 -#define YY_NO_UNISTD_H 1 -#line 7 "src/lexer.l" -#include - -#include "lex.yy.extern.h" - -/* nounistd */ -static int isatty(int fd) { - (void)fd; - return 1; -} - -#define SET_PARTIAL(v) \ - do { \ - jiangtun_yy_extra_t *extra = NULL; \ - if ((extra = yyget_extra(yyscanner)) != NULL) \ - extra->partial = (v); \ - } while (0) - -#define SET_RETURN(v) \ - do { \ - jiangtun_yy_extra_t *extra = NULL; \ - if ((extra = yyget_extra(yyscanner)) != NULL) \ - extra->return_ = (v); \ - } while (0) -#line 507 "src/lex.yy.c" -#line 508 "src/lex.yy.c" - -#define INITIAL 0 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -/* Holds the entire state of the reentrant scanner. */ -struct yyguts_t - { - - /* User-defined. Not touched by flex. */ - YY_EXTRA_TYPE yyextra_r; - - /* The rest are the same as the globals declared in the non-reentrant scanner. */ - FILE *yyin_r, *yyout_r; - size_t yy_buffer_stack_top; /**< index of top of stack. */ - size_t yy_buffer_stack_max; /**< capacity of stack. */ - YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ - char yy_hold_char; - int yy_n_chars; - int yyleng_r; - char *yy_c_buf_p; - int yy_init; - int yy_start; - int yy_did_buffer_switch_on_eof; - int yy_start_stack_ptr; - int yy_start_stack_depth; - int *yy_start_stack; - yy_state_type yy_last_accepting_state; - char* yy_last_accepting_cpos; - - int yylineno_r; - int yy_flex_debug_r; - - char *yytext_r; - int yy_more_flag; - int yy_more_len; - - }; /* end struct yyguts_t */ - -static int yy_init_globals ( yyscan_t yyscanner ); - -int yylex_init (yyscan_t* scanner); - -int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int yylex_destroy ( yyscan_t yyscanner ); - -int yyget_debug ( yyscan_t yyscanner ); - -void yyset_debug ( int debug_flag , yyscan_t yyscanner ); - -YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); - -void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); - -FILE *yyget_in ( yyscan_t yyscanner ); - -void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); - -FILE *yyget_out ( yyscan_t yyscanner ); - -void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); - - int yyget_leng ( yyscan_t yyscanner ); - -char *yyget_text ( yyscan_t yyscanner ); - -int yyget_lineno ( yyscan_t yyscanner ); - -void yyset_lineno ( int _line_number , yyscan_t yyscanner ); - -int yyget_column ( yyscan_t yyscanner ); - -void yyset_column ( int _column_no , yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap ( yyscan_t yyscanner ); -#else -extern int yywrap ( yyscan_t yyscanner ); -#endif -#endif - -#ifndef YY_NO_UNPUT - -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen ( const char * , yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput ( yyscan_t yyscanner ); -#else -static int input ( yyscan_t yyscanner ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k */ -#define YY_READ_BUF_SIZE 16384 -#else -#define YY_READ_BUF_SIZE 8192 -#endif /* __ia64__ */ -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - int n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex (yyscan_t yyscanner); - -#define YY_DECL int yylex (yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK /*LINTED*/break; -#endif - -#define YY_RULE_SETUP \ - if ( yyleng > 0 ) \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ - (yytext[yyleng - 1] == '\n'); \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - yy_state_type yy_current_state; - char *yy_cp, *yy_bp; - int yy_act; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( !yyg->yy_init ) - { - yyg->yy_init = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yyg->yy_start ) - yyg->yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); - } - - yy_load_buffer_state( yyscanner ); - } - - { -#line 32 "src/lexer.l" - - -#line 35 "src/lexer.l" - /* - * NX Macro Controller - */ -#line 776 "src/lex.yy.c" - - while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ - { - yyg->yy_more_len = 0; - if ( yyg->yy_more_flag ) - { - yyg->yy_more_len = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); - yyg->yy_more_flag = 0; - } - yy_cp = yyg->yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yyg->yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yyg->yy_start; - yy_current_state += YY_AT_BOL(); -yy_match: - do - { - YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 61 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 162 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yyg->yy_hold_char; - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - goto yy_find_action; - -case 1: -/* rule 1 can match eol */ -YY_RULE_SETUP -#line 38 "src/lexer.l" -{ - SET_PARTIAL(1); - yymore(); - } - YY_BREAK -case 2: -/* rule 2 can match eol */ -YY_RULE_SETUP -#line 42 "src/lexer.l" -{ - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_MATCH_NXMC2); - } - YY_BREAK -/* - * Poke-Controller - * 正規表現の簡略化のために、ボタン下位ビットで判定できる不正パターンを許容する - */ -case 3: -#line 52 "src/lexer.l" -case 4: -#line 53 "src/lexer.l" -/* [048c] 末尾2bitが0b00 */ -case 5: -#line 55 "src/lexer.l" -/* [1235679abdef] 末尾2bitの少なくとも1つが0b1 */ -case 6: -#line 57 "src/lexer.l" -case 7: -#line 58 "src/lexer.l" -case 8: -#line 59 "src/lexer.l" -case 9: -#line 60 "src/lexer.l" -/* [12569ade] 末尾2bitのいずれかが0b1(ただしバグにより"3"はスティックが1つになる場合がある) */ -case 10: -#line 62 "src/lexer.l" -/* [37bf] 末尾2bitが0b11 */ -case 11: -#line 64 "src/lexer.l" -case 12: -#line 65 "src/lexer.l" -case 13: -#line 66 "src/lexer.l" -case 14: -#line 67 "src/lexer.l" -case 15: -#line 68 "src/lexer.l" -case 16: -#line 69 "src/lexer.l" -case 17: -YY_RULE_SETUP -#line 69 "src/lexer.l" -{ - SET_PARTIAL(1); - yymore(); - } - YY_BREAK -case 18: -/* rule 18 can match eol */ -#line 74 "src/lexer.l" -case 19: -/* rule 19 can match eol */ -YY_RULE_SETUP -#line 74 "src/lexer.l" -{ - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_MATCH_POKECON); - } - YY_BREAK -/* - * ORCA GC Controller - */ -case 20: -/* rule 20 can match eol */ -#line 83 "src/lexer.l" -case 21: -/* rule 21 can match eol */ -YY_RULE_SETUP -#line 83 "src/lexer.l" -{ - SET_PARTIAL(1); - yymore(); - } - YY_BREAK -case 22: -/* rule 22 can match eol */ -YY_RULE_SETUP -#line 87 "src/lexer.l" -{ - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_MATCH_ORCA); - } - YY_BREAK -case 23: -/* rule 23 can match eol */ -YY_RULE_SETUP -#line 92 "src/lexer.l" -{ - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_NO_MATCH); - } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 97 "src/lexer.l" -ECHO; - YY_BREAK -#line 952 "src/lex.yy.c" -case YY_STATE_EOF(INITIAL): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yyg->yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); - - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yyg->yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yyg->yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_END_OF_FILE: - { - yyg->yy_did_buffer_switch_on_eof = 0; - - if ( yywrap( yyscanner ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = - yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yyg->yy_c_buf_p = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of user's declarations */ -} /* end of yylex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - char *source = yyg->yytext_ptr; - int number_to_move, i; - int ret_val; - - if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; - - else - { - int num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; - - int yy_c_buf_p_offset = - (int) (yyg->yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yyrealloc( (void *) b->yy_ch_buf, - (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = NULL; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - if ( yyg->yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin , yyscanner); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( - (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - /* "- 2" to take care of EOB's */ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); - } - - yyg->yy_n_chars += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (yyscan_t yyscanner) -{ - yy_state_type yy_current_state; - char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_current_state = yyg->yy_start; - yy_current_state += YY_AT_BOL(); - - for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) - { - YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 61 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) -{ - int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - char *yy_cp = yyg->yy_c_buf_p; - - YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 61 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 60); - - (void)yyg; - return yy_is_jam ? 0 : yy_current_state; -} - -#ifndef YY_NO_UNPUT - -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (yyscan_t yyscanner) -#else - static int input (yyscan_t yyscanner) -#endif - -{ - int c; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - *yyg->yy_c_buf_p = yyg->yy_hold_char; - - if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - /* This was really a NUL. */ - *yyg->yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); - ++yyg->yy_c_buf_p; - - switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin , yyscanner); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap( yyscanner ) ) - return 0; - - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(yyscanner); -#else - return input(yyscanner); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = yyg->yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ - *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ - yyg->yy_hold_char = *++yyg->yy_c_buf_p; - - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * @param yyscanner The scanner object. - * @note This function does not reset the start condition to @c INITIAL . - */ - void yyrestart (FILE * input_file , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! YY_CURRENT_BUFFER ){ - yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); - } - - yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); - yy_load_buffer_state( yyscanner ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * @param yyscanner The scanner object. - */ - void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* TODO. We should be able to replace this entire function body - * with - * yypop_buffer_state(); - * yypush_buffer_state(new_buffer); - */ - yyensure_buffer_stack (yyscanner); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - yy_load_buffer_state( yyscanner ); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yyg->yy_did_buffer_switch_on_eof = 1; -} - -static void yy_load_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - yyg->yy_hold_char = *yyg->yy_c_buf_p; -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * @param yyscanner The scanner object. - * @return the allocated buffer state. - */ - YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file , yyscanner); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with yy_create_buffer() - * @param yyscanner The scanner object. - */ - void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yyfree( (void *) b->yy_ch_buf , yyscanner ); - - yyfree( (void *) b , yyscanner ); -} - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a yyrestart() or at EOF. - */ - static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) - -{ - int oerrno = errno; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_flush_buffer( b , yyscanner); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then yy_init_buffer was _probably_ - * called from yyrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * @param yyscanner The scanner object. - */ - void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - yy_load_buffer_state( yyscanner ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * @param yyscanner The scanner object. - */ -void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (new_buffer == NULL) - return; - - yyensure_buffer_stack(yyscanner); - - /* This block is copied from yy_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - yyg->yy_buffer_stack_top++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from yy_switch_to_buffer. */ - yy_load_buffer_state( yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * @param yyscanner The scanner object. - */ -void yypop_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (!YY_CURRENT_BUFFER) - return; - - yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); - YY_CURRENT_BUFFER_LVALUE = NULL; - if (yyg->yy_buffer_stack_top > 0) - --yyg->yy_buffer_stack_top; - - if (YY_CURRENT_BUFFER) { - yy_load_buffer_state( yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void yyensure_buffer_stack (yyscan_t yyscanner) -{ - yy_size_t num_to_alloc; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (!yyg->yy_buffer_stack) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ - yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - yyg->yy_buffer_stack_max = num_to_alloc; - yyg->yy_buffer_stack_top = 0; - return; - } - - if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - yy_size_t grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = yyg->yy_buffer_stack_max + grow_size; - yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc - (yyg->yy_buffer_stack, - num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); - yyg->yy_buffer_stack_max = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return NULL; - - b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = NULL; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b , yyscanner ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to yylex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * yy_scan_bytes() instead. - */ -YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) -{ - - return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); -} - -/** Setup the input buffer state to scan the given bytes. The next call to yylex() will - * scan from a @e copy of @a bytes. - * @param yybytes the byte buffer to scan - * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = (yy_size_t) (_yybytes_len + 2); - buf = (char *) yyalloc( n , yyscanner ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n , yyscanner); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - (void)yyg; - fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = yyg->yy_hold_char; \ - yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ - yyg->yy_hold_char = *yyg->yy_c_buf_p; \ - *yyg->yy_c_buf_p = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the user-defined data for this scanner. - * @param yyscanner The scanner object. - */ -YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyextra; -} - -/** Get the current line number. - * @param yyscanner The scanner object. - */ -int yyget_lineno (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yylineno; -} - -/** Get the current column number. - * @param yyscanner The scanner object. - */ -int yyget_column (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yycolumn; -} - -/** Get the input stream. - * @param yyscanner The scanner object. - */ -FILE *yyget_in (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyin; -} - -/** Get the output stream. - * @param yyscanner The scanner object. - */ -FILE *yyget_out (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyout; -} - -/** Get the length of the current token. - * @param yyscanner The scanner object. - */ -int yyget_leng (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyleng; -} - -/** Get the current token. - * @param yyscanner The scanner object. - */ - -char *yyget_text (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yytext; -} - -/** Set the user-defined data. This data is never touched by the scanner. - * @param user_defined The data to be associated with this scanner. - * @param yyscanner The scanner object. - */ -void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyextra = user_defined ; -} - -/** Set the current line number. - * @param _line_number line number - * @param yyscanner The scanner object. - */ -void yyset_lineno (int _line_number , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* lineno is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); - - yylineno = _line_number; -} - -/** Set the current column. - * @param _column_no column number - * @param yyscanner The scanner object. - */ -void yyset_column (int _column_no , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* column is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - YY_FATAL_ERROR( "yyset_column called with no buffer" ); - - yycolumn = _column_no; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param _in_str A readable stream. - * @param yyscanner The scanner object. - * @see yy_switch_to_buffer - */ -void yyset_in (FILE * _in_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = _in_str ; -} - -void yyset_out (FILE * _out_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = _out_str ; -} - -int yyget_debug (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yy_flex_debug; -} - -void yyset_debug (int _bdebug , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = _bdebug ; -} - -/* Accessor methods for yylval and yylloc */ - -/* User-visible API */ - -/* yylex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ -int yylex_init(yyscan_t* ptr_yy_globals) -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - -/* yylex_init_extra has the same functionality as yylex_init, but follows the - * convention of taking the scanner as the last argument. Note however, that - * this is a *pointer* to a scanner, as it will be allocated by this call (and - * is the reason, too, why this function also must handle its own declaration). - * The user defined value in the first argument will be available to yyalloc in - * the yyextra field. - */ -int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) -{ - struct yyguts_t dummy_yyguts; - - yyset_extra (yy_user_defined, &dummy_yyguts); - - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in - yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - yyset_extra (yy_user_defined, *ptr_yy_globals); - - return yy_init_globals ( *ptr_yy_globals ); -} - -static int yy_init_globals (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from yylex_destroy(), so don't allocate here. - */ - - yyg->yy_buffer_stack = NULL; - yyg->yy_buffer_stack_top = 0; - yyg->yy_buffer_stack_max = 0; - yyg->yy_c_buf_p = NULL; - yyg->yy_init = 0; - yyg->yy_start = 0; - - yyg->yy_start_stack_ptr = 0; - yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = NULL; - -/* Defined in main.c */ -#ifdef YY_STDINIT - yyin = stdin; - yyout = stdout; -#else - yyin = NULL; - yyout = NULL; -#endif - - /* For future reference: Set errno on error, since we are called by - * yylex_init() - */ - return 0; -} - -/* yylex_destroy is for both reentrant and non-reentrant scanners. */ -int yylex_destroy (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); - YY_CURRENT_BUFFER_LVALUE = NULL; - yypop_buffer_state(yyscanner); - } - - /* Destroy the stack itself. */ - yyfree(yyg->yy_buffer_stack , yyscanner); - yyg->yy_buffer_stack = NULL; - - /* Destroy the start condition stack. */ - yyfree( yyg->yy_start_stack , yyscanner ); - yyg->yy_start_stack = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * yylex() is called, initialization will occur. */ - yy_init_globals( yyscanner); - - /* Destroy the main struct (reentrant only). */ - yyfree ( yyscanner , yyscanner ); - yyscanner = NULL; - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - (void)yyg; - - int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (const char * s , yyscan_t yyscanner) -{ - int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -void *yyalloc (yy_size_t size , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - (void)yyg; - return malloc(size); -} - -void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - (void)yyg; - - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return realloc(ptr, size); -} - -void yyfree (void * ptr , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - (void)yyg; - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -#line 97 "src/lexer.l" - - diff --git a/lib/jiangtun-core/src/lex.yy.extern.h b/lib/jiangtun-core/src/lex.yy.extern.h deleted file mode 100644 index 6810115..0000000 --- a/lib/jiangtun-core/src/lex.yy.extern.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef JIANGTUN_LEXER_EXTERN_H -#define JIANGTUN_LEXER_EXTERN_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef YY_EXTRA_TYPE -#undef YY_EXTRA_TYPE -#endif /* YY_EXTRA_TYPE */ -#define YY_EXTRA_TYPE jiangtun_yy_extra_t * - -#ifndef YY_NO_UNISTD_H -#define YY_NO_UNISTD_H -#endif /* YY_NO_UNISTD_H */ - -#ifdef __cplusplus -} -#endif - -#endif /* JIANGTUN_LEXER_EXTERN_H */ diff --git a/lib/jiangtun-core/src/lex.yy.h b/lib/jiangtun-core/src/lex.yy.h deleted file mode 100644 index 55a8b33..0000000 --- a/lib/jiangtun-core/src/lex.yy.h +++ /dev/null @@ -1,492 +0,0 @@ -#ifndef yyHEADER_H -#define yyHEADER_H 1 -#define yyIN_HEADER 1 - -#line 6 "src/lex.yy.h" - -#line 8 "src/lex.yy.h" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 6 -#define YY_FLEX_SUBMINOR_VERSION 4 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#ifndef SIZE_MAX -#define SIZE_MAX (~(size_t)0) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -/* begin standard C++ headers. */ - -/* TODO: this is always defined, so inline it */ -#define yyconst const - -#if defined(__GNUC__) && __GNUC__ >= 3 -#define yynoreturn __attribute__((__noreturn__)) -#else -#define yynoreturn -#endif - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k. - * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. - * Ditto for the __ia64__ case accordingly. - */ -#define YY_BUF_SIZE 32768 -#else -#define YY_BUF_SIZE 16384 -#endif /* __ia64__ */ -#endif - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - int yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -void yyrestart ( FILE *input_file , yyscan_t yyscanner ); -void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); -void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); -void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); -void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); -void yypop_buffer_state ( yyscan_t yyscanner ); - -YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); - -void *yyalloc ( yy_size_t , yyscan_t yyscanner ); -void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); -void yyfree ( void * , yyscan_t yyscanner ); - -/* Begin user sect3 */ - -#define yywrap(yyscanner) (/*CONSTCOND*/1) -#define YY_SKIP_YYWRAP - -#define yytext_ptr yytext_r - -#ifdef YY_HEADER_EXPORT_START_CONDITIONS -#define INITIAL 0 - -#endif - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -int yylex_init (yyscan_t* scanner); - -int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int yylex_destroy ( yyscan_t yyscanner ); - -int yyget_debug ( yyscan_t yyscanner ); - -void yyset_debug ( int debug_flag , yyscan_t yyscanner ); - -YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); - -void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); - -FILE *yyget_in ( yyscan_t yyscanner ); - -void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); - -FILE *yyget_out ( yyscan_t yyscanner ); - -void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); - - int yyget_leng ( yyscan_t yyscanner ); - -char *yyget_text ( yyscan_t yyscanner ); - -int yyget_lineno ( yyscan_t yyscanner ); - -void yyset_lineno ( int _line_number , yyscan_t yyscanner ); - -int yyget_column ( yyscan_t yyscanner ); - -void yyset_column ( int _column_no , yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap ( yyscan_t yyscanner ); -#else -extern int yywrap ( yyscan_t yyscanner ); -#endif -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen ( const char * , yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k */ -#define YY_READ_BUF_SIZE 16384 -#else -#define YY_READ_BUF_SIZE 8192 -#endif /* __ia64__ */ -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex (yyscan_t yyscanner); - -#define YY_DECL int yylex (yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif - -#ifndef yy_create_buffer_ALREADY_DEFINED -#undef yy_create_buffer -#endif -#ifndef yy_delete_buffer_ALREADY_DEFINED -#undef yy_delete_buffer -#endif -#ifndef yy_scan_buffer_ALREADY_DEFINED -#undef yy_scan_buffer -#endif -#ifndef yy_scan_string_ALREADY_DEFINED -#undef yy_scan_string -#endif -#ifndef yy_scan_bytes_ALREADY_DEFINED -#undef yy_scan_bytes -#endif -#ifndef yy_init_buffer_ALREADY_DEFINED -#undef yy_init_buffer -#endif -#ifndef yy_flush_buffer_ALREADY_DEFINED -#undef yy_flush_buffer -#endif -#ifndef yy_load_buffer_state_ALREADY_DEFINED -#undef yy_load_buffer_state -#endif -#ifndef yy_switch_to_buffer_ALREADY_DEFINED -#undef yy_switch_to_buffer -#endif -#ifndef yypush_buffer_state_ALREADY_DEFINED -#undef yypush_buffer_state -#endif -#ifndef yypop_buffer_state_ALREADY_DEFINED -#undef yypop_buffer_state -#endif -#ifndef yyensure_buffer_stack_ALREADY_DEFINED -#undef yyensure_buffer_stack -#endif -#ifndef yylex_ALREADY_DEFINED -#undef yylex -#endif -#ifndef yyrestart_ALREADY_DEFINED -#undef yyrestart -#endif -#ifndef yylex_init_ALREADY_DEFINED -#undef yylex_init -#endif -#ifndef yylex_init_extra_ALREADY_DEFINED -#undef yylex_init_extra -#endif -#ifndef yylex_destroy_ALREADY_DEFINED -#undef yylex_destroy -#endif -#ifndef yyget_debug_ALREADY_DEFINED -#undef yyget_debug -#endif -#ifndef yyset_debug_ALREADY_DEFINED -#undef yyset_debug -#endif -#ifndef yyget_extra_ALREADY_DEFINED -#undef yyget_extra -#endif -#ifndef yyset_extra_ALREADY_DEFINED -#undef yyset_extra -#endif -#ifndef yyget_in_ALREADY_DEFINED -#undef yyget_in -#endif -#ifndef yyset_in_ALREADY_DEFINED -#undef yyset_in -#endif -#ifndef yyget_out_ALREADY_DEFINED -#undef yyget_out -#endif -#ifndef yyset_out_ALREADY_DEFINED -#undef yyset_out -#endif -#ifndef yyget_leng_ALREADY_DEFINED -#undef yyget_leng -#endif -#ifndef yyget_text_ALREADY_DEFINED -#undef yyget_text -#endif -#ifndef yyget_lineno_ALREADY_DEFINED -#undef yyget_lineno -#endif -#ifndef yyset_lineno_ALREADY_DEFINED -#undef yyset_lineno -#endif -#ifndef yyget_column_ALREADY_DEFINED -#undef yyget_column -#endif -#ifndef yyset_column_ALREADY_DEFINED -#undef yyset_column -#endif -#ifndef yywrap_ALREADY_DEFINED -#undef yywrap -#endif -#ifndef yyget_lval_ALREADY_DEFINED -#undef yyget_lval -#endif -#ifndef yyset_lval_ALREADY_DEFINED -#undef yyset_lval -#endif -#ifndef yyget_lloc_ALREADY_DEFINED -#undef yyget_lloc -#endif -#ifndef yyset_lloc_ALREADY_DEFINED -#undef yyset_lloc -#endif -#ifndef yyalloc_ALREADY_DEFINED -#undef yyalloc -#endif -#ifndef yyrealloc_ALREADY_DEFINED -#undef yyrealloc -#endif -#ifndef yyfree_ALREADY_DEFINED -#undef yyfree -#endif -#ifndef yytext_ALREADY_DEFINED -#undef yytext -#endif -#ifndef yyleng_ALREADY_DEFINED -#undef yyleng -#endif -#ifndef yyin_ALREADY_DEFINED -#undef yyin -#endif -#ifndef yyout_ALREADY_DEFINED -#undef yyout -#endif -#ifndef yy_flex_debug_ALREADY_DEFINED -#undef yy_flex_debug -#endif -#ifndef yylineno_ALREADY_DEFINED -#undef yylineno -#endif -#ifndef yytables_fload_ALREADY_DEFINED -#undef yytables_fload -#endif -#ifndef yytables_destroy_ALREADY_DEFINED -#undef yytables_destroy -#endif -#ifndef yyTABLES_NAME_ALREADY_DEFINED -#undef yyTABLES_NAME -#endif - -#line 97 "src/lexer.l" - - -#line 491 "src/lex.yy.h" -#undef yyIN_HEADER -#endif /* yyHEADER_H */ diff --git a/lib/jiangtun-core/src/lexer.c b/lib/jiangtun-core/src/lexer.c deleted file mode 100644 index 4a7c3e3..0000000 --- a/lib/jiangtun-core/src/lexer.c +++ /dev/null @@ -1,110 +0,0 @@ -#include - -/* clang-format off */ -#include "lex.yy.extern.h" -#include "lex.yy.h" -/* clang-format on */ - -jiangtun_error_t jiangtun_lexer_init(jiangtun_lexer_t *lexer) { - if (lexer == NULL) { - return JIANGTUN_ERROR_NULL_POINTER; - } - - lexer->extra.partial = JIANGTUN_FALSE; - if (yylex_init_extra(&(lexer->extra), (yyscan_t *)&(lexer->scanner)) != 0) { - return JIANGTUN_ERROR_INTERNAL; - } - - return JIANGTUN_SUCCESS; -} - -jiangtun_error_t jiangtun_lexer_deinit(jiangtun_lexer_t *lexer) { - if (lexer == NULL) { - return JIANGTUN_ERROR_NULL_POINTER; - } - - yylex_destroy((yyscan_t)(lexer->scanner)); - - return JIANGTUN_SUCCESS; -} - -jiangtun_error_t jiangtun_lex(jiangtun_lexer_t *lexer, - const jiangtun_uint8_t *buffer, - size_t buffer_length, - jiangtun_lexer_result_t *out_result) { - jiangtun_error_t err = JIANGTUN_SUCCESS; - jiangtun_lexer_result_t result = JIANGTUN_LEXER_NO_MATCH; - YY_BUFFER_STATE state = NULL; - - if (lexer == NULL) { - return JIANGTUN_ERROR_NULL_POINTER; - } else if (buffer == NULL || buffer_length == 0) { - if (out_result != NULL) { - *out_result = JIANGTUN_LEXER_NO_MATCH; - } - return JIANGTUN_SUCCESS; - } - - state = yy_scan_bytes((char *)buffer, buffer_length, - (yyscan_t)(lexer->scanner)); - if (state == NULL) { - return JIANGTUN_ERROR_INTERNAL; - } - yy_switch_to_buffer(state, (yyscan_t)(lexer->scanner)); - - lexer->extra.partial = JIANGTUN_FALSE; - lexer->extra.return_ = JIANGTUN_YY_NO_MATCH; - yylex((yyscan_t)(lexer->scanner)); - switch (lexer->extra.return_) { - case JIANGTUN_YY_NO_MATCH: - result = lexer->extra.partial ? JIANGTUN_LEXER_MATCH_PARTIAL - : JIANGTUN_LEXER_NO_MATCH; - break; - - case JIANGTUN_YY_MATCH_NXMC2: - result = JIANGTUN_LEXER_MATCH_NXMC2; - break; - - case JIANGTUN_YY_MATCH_POKECON: - result = JIANGTUN_LEXER_MATCH_POKECON; - break; - - case JIANGTUN_YY_MATCH_ORCA: - result = JIANGTUN_LEXER_MATCH_ORCA; - break; - - default: - err = JIANGTUN_ERROR_INTERNAL; - break; - } - - yy_delete_buffer(state, (yyscan_t)(lexer->scanner)); - - if (out_result != NULL) { - *out_result = result; - } - - return err; -} - -const char *jiangtun_lexer_result_stringify(jiangtun_lexer_result_t result) { - switch (result) { - case JIANGTUN_LEXER_NO_MATCH: - return "JIANGTUN_LEXER_NO_MATCH"; - - case JIANGTUN_LEXER_MATCH_PARTIAL: - return "JIANGTUN_LEXER_MATCH_PARTIAL"; - - case JIANGTUN_LEXER_MATCH_NXMC2: - return "JIANGTUN_LEXER_MATCH_NXMC2"; - - case JIANGTUN_LEXER_MATCH_POKECON: - return "JIANGTUN_LEXER_MATCH_POKECON"; - - case JIANGTUN_LEXER_MATCH_ORCA: - return "JIANGTUN_LEXER_MATCH_ORCA"; - - default: - return "unknown"; - } -} \ No newline at end of file diff --git a/lib/jiangtun-core/src/lexer.l b/lib/jiangtun-core/src/lexer.l deleted file mode 100644 index ef24d7f..0000000 --- a/lib/jiangtun-core/src/lexer.l +++ /dev/null @@ -1,96 +0,0 @@ -%option noyywrap -%option nounput -%option noinput -%option nounistd -%option reentrant -%{ -#include - -#include "lex.yy.extern.h" - -/* nounistd */ -static int isatty(int fd) { - (void)fd; - return 1; -} - -#define SET_PARTIAL(v) \ - do { \ - jiangtun_yy_extra_t *extra = NULL; \ - if ((extra = yyget_extra(yyscanner)) != NULL) \ - extra->partial = (v); \ - } while (0) - -#define SET_RETURN(v) \ - do { \ - jiangtun_yy_extra_t *extra = NULL; \ - if ((extra = yyget_extra(yyscanner)) != NULL) \ - extra->return_ = (v); \ - } while (0) -%} - -%% - - /* - * NX Macro Controller - */ -^\xAB[\x00-\xFF]{0,9} { - SET_PARTIAL(1); - yymore(); - } -^\xAB[\x00-\xFF]{10} { - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_MATCH_NXMC2); - } - - /* - * Poke-Controller - * 正規表現の簡略化のために、ボタン下位ビットで判定できる不正パターンを許容する - */ -^(0x) | -^(0x)?[0-9a-f]{1,4}\x20? | - /* [048c] 末尾2bitが0b00 */ -^(0x)?[0-9a-f]{1,4}\x20[0-8]\r? | - /* [1235679abdef] 末尾2bitの少なくとも1つが0b1 */ -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20? | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x) | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20? | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x) | - /* [12569ade] 末尾2bitのいずれかが0b1(ただしバグにより"3"はスティックが1つになる場合がある) */ -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\r? | - /* [37bf] 末尾2bitが0b11 */ -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20? | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x) | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20? | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x) | -^(0x)?[0-9a-f]{1,4}\x20[0-8]\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}\r? | -^end? | -^end\r? { - SET_PARTIAL(1); - yymore(); - } -^(0x)?[0-9a-f]{1,4}\x20[0-8](\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2}(\x20(0x)?[0-9a-f]{1,2}\x20(0x)?[0-9a-f]{1,2})?)?\r?\n | -^end\r?\n { - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_MATCH_POKECON); - } - - /* - * ORCA GC Controller - */ -^\x80\xFF*[\x00-\xFE]? | -^\x80\xFF*[\x00-\xFE]\xFF* { - SET_PARTIAL(1); - yymore(); - } -^(@|\x80\xFF*[\x00-\xFE]\xFF*[\x00-\xFE]) { - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_MATCH_ORCA); - } - -[\x00-\xFF] { - SET_PARTIAL(0); - SET_RETURN(JIANGTUN_YY_NO_MATCH); - } - -%% diff --git a/lib/jiangtun-core/src/nxmc2.c b/lib/jiangtun-core/src/nxmc2.c index 2905b5d..44fcfd8 100644 --- a/lib/jiangtun-core/src/nxmc2.c +++ b/lib/jiangtun-core/src/nxmc2.c @@ -1,118 +1,213 @@ -#include - -jiangtun_error_t jiangtun_nxmc2_parse(const jiangtun_uint8_t *buffer, - size_t buffer_length, - jiangtun_report_t *out_report, - jiangtun_bool_t *out_reset) { - jiangtun_uint8_t btns_lsb = 0; - jiangtun_uint8_t btns_msb = 0; - jiangtun_uint8_t hat = 8; - - if (buffer == NULL) { - return JIANGTUN_ERROR_INVALID_ARGUMENT; - } else if (buffer_length != 11 || buffer[0] != 0xAB) { - return JIANGTUN_ERROR_PARSE_FAILURE; - } +#include - btns_lsb = buffer[1]; - btns_msb = buffer[2]; - hat = buffer[3] % 9; - - if (out_report != NULL) { - if (jiangtun_report_init(out_report) != JIANGTUN_SUCCESS) { - return JIANGTUN_ERROR_INTERNAL; - } - - out_report->mode3.y = (btns_lsb >> 0) & 1; - out_report->mode3.b = (btns_lsb >> 1) & 1; - out_report->mode3.a = (btns_lsb >> 2) & 1; - out_report->mode3.x = (btns_lsb >> 3) & 1; - out_report->mode3.l = (btns_lsb >> 4) & 1; - out_report->mode3.r = (btns_lsb >> 5) & 1; - /* zl = (btns_lsb >> 6) & 1; */ - out_report->mode3.z = (btns_msb >> 7) & 1; - /* minus = (btns_msb >> 0) & 1; */ - out_report->mode3.start = (btns_msb >> 1) & 1; - /* l_click = (btns_msb >> 2) & 1; */ - /* r_click = (btns_msb >> 3) & 1; */ - /* home = (btns_msb >> 4) & 1; --> reset */ - /* capture = (btns_msb >> 5) & 1; */ - - switch (hat) { - case 0: - out_report->mode3.dup = 1; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - case 1: - out_report->mode3.dup = 1; - out_report->mode3.dright = 1; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - case 2: - out_report->mode3.dup = 0; - out_report->mode3.dright = 1; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - case 3: - out_report->mode3.dup = 0; - out_report->mode3.dright = 1; - out_report->mode3.ddown = 1; - out_report->mode3.dleft = 0; - break; - case 4: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 1; - out_report->mode3.dleft = 0; - break; - case 5: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 1; - out_report->mode3.dleft = 1; - break; - case 6: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 1; - break; - case 7: - out_report->mode3.dup = 1; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 1; - break; - case 8: - default: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - } - - out_report->mode3.xAxis = buffer[4]; - out_report->mode3.yAxis = 0xFF - buffer[5]; - - out_report->mode3.cxAxis = buffer[6]; - out_report->mode3.cyAxis = 0xFF - buffer[7]; - - (void)buffer[8]; - (void)buffer[9]; - (void)buffer[10]; - - if (jiangtun_report_emend_axis(out_report) != JIANGTUN_SUCCESS) { - return JIANGTUN_ERROR_INTERNAL; - } - } - if (out_reset != NULL) { - *out_reset = (jiangtun_bool_t)((btns_msb >> 4) & 1); +#include "internal.h" + +#include + +#define NXMC2_HEADER 0xAB +#define NXMC2_HAT_UP 0 +#define NXMC2_HAT_UPRIGHT 1 +#define NXMC2_HAT_RIGHT 2 +#define NXMC2_HAT_DOWNRIGHT 3 +#define NXMC2_HAT_DOWN 4 +#define NXMC2_HAT_DOWNLEFT 5 +#define NXMC2_HAT_LEFT 6 +#define NXMC2_HAT_UPLEFT 7 +#define NXMC2_HAT_NEUTRAL 8 + +static jiangtun_bool_t patch(const jiangtun_uint8_t *buffer, size_t length, + void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + jiangtun_uint8_t btn0 = 0; + jiangtun_uint8_t btn1 = 0; + assert(buffer != NULL); + assert(length == 11); + assert(buffer[0] == NXMC2_HEADER); + assert(buffer[3] <= NXMC2_HAT_NEUTRAL); + assert(report != NULL); + + btn0 = buffer[1]; + btn1 = buffer[2]; + + report->y = (btn0 >> 0) & 1; + report->b = (btn0 >> 1) & 1; + report->a = (btn0 >> 2) & 1; + report->x = (btn0 >> 3) & 1; + report->l = (btn0 >> 4) & 1; + report->r = (btn0 >> 5) & 1; + /* zl = (btn0 >> 6) & 1; */ + report->z = (btn1 >> 7) & 1; + /* minus = (btn1 >> 0) & 1; */ + report->start = (btn1 >> 1) & 1; + /* l_click = (btn1 >> 2) & 1; */ + /* r_click = (btn1 >> 3) & 1; */ + report->reset = (btn1 >> 4) & 1; + /* capture = (btn1 >> 5) & 1; */ + + switch (buffer[3]) { + case NXMC2_HAT_UP: + report->dup = JIANGTUN_TRUE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + case NXMC2_HAT_UPRIGHT: + report->dup = JIANGTUN_TRUE; + report->dright = JIANGTUN_TRUE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + case NXMC2_HAT_RIGHT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_TRUE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + case NXMC2_HAT_DOWNRIGHT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_TRUE; + report->ddown = JIANGTUN_TRUE; + report->dleft = JIANGTUN_FALSE; + break; + case NXMC2_HAT_DOWN: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_TRUE; + report->dleft = JIANGTUN_FALSE; + break; + case NXMC2_HAT_DOWNLEFT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_TRUE; + report->dleft = JIANGTUN_TRUE; + break; + case NXMC2_HAT_LEFT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_TRUE; + break; + case NXMC2_HAT_UPLEFT: + report->dup = JIANGTUN_TRUE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_TRUE; + break; + case NXMC2_HAT_NEUTRAL: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + default: + assert(JIANGTUN_FALSE); + break; } - return JIANGTUN_SUCCESS; + report->xAxis = buffer[4]; + report->yAxis = JIANGTUN_UINT8_MAX - buffer[5]; + + report->cxAxis = buffer[6]; + report->cyAxis = JIANGTUN_UINT8_MAX - buffer[7]; + + (void)buffer[8]; + (void)buffer[9]; + (void)buffer[10]; + + return JIANGTUN_TRUE; +} + +static void +transition_0xab_btn0_btn1_hat_lx_ly_rx_ry_0_0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, NULL, patch); +} + +static void +transition_0xab_btn0_btn1_hat_lx_ly_rx_ry_0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + transition_0xab_btn0_btn1_hat_lx_ly_rx_ry_0_0, NULL); +} + +static void +transition_0xab_btn0_btn1_hat_lx_ly_rx_ry(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + transition_0xab_btn0_btn1_hat_lx_ly_rx_ry_0, NULL); +} + +static void transition_0xab_btn0_btn1_hat_lx_ly_rx(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + transition_0xab_btn0_btn1_hat_lx_ly_rx_ry, NULL); } + +static void transition_0xab_btn0_btn1_hat_lx_ly(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, transition_0xab_btn0_btn1_hat_lx_ly_rx, + NULL); +} + +static void transition_0xab_btn0_btn1_hat_lx(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, transition_0xab_btn0_btn1_hat_lx_ly, + NULL); +} + +static void transition_0xab_btn0_btn1_hat(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, transition_0xab_btn0_btn1_hat_lx, NULL); +} + +static void transition_0xab_btn0_btn1(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c <= 8 ? transition_0xab_btn0_btn1_hat : NULL, NULL); +} + +static void transition_0xab_btn0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, transition_0xab_btn0_btn1, NULL); +} + +static void transition_0xab(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, transition_0xab_btn0, NULL); +} + +static void transition_initial(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == NXMC2_HEADER ? transition_0xab : NULL, NULL); +} + +void jiangtun_nxmc2_init(jiangtun_nxmc2_command_t *command) { + assert(command != NULL); + + command->base.buffer = command->buffer; + command->base.length = 0; + + jiangtun_command_init(&(command->base), transition_initial, NULL); +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/orca.c b/lib/jiangtun-core/src/orca.c new file mode 100644 index 0000000..33e7b84 --- /dev/null +++ b/lib/jiangtun-core/src/orca.c @@ -0,0 +1,145 @@ +#include + +#include "internal.h" + +#include + +#define ORCA_HEADER 0x80 +#define ORCA_RELEASE 0x80 +#define ORCA_SKIP 0xFF + +static jiangtun_bool_t patch_at_sign(const jiangtun_uint8_t *buffer, + size_t length, void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + assert(buffer != NULL); + assert(length == 1); + assert(buffer[0] == '@'); + assert(report != NULL); + + report->reset = JIANGTUN_TRUE; + + return JIANGTUN_TRUE; +} + +/** `\xff*([^0xff])\xff*([^0xff])` */ +static jiangtun_bool_t find_btns(const jiangtun_uint8_t *buffer, size_t length, + jiangtun_uint8_t *btn0, + jiangtun_uint8_t *btn1) { + size_t i = 0; + assert(buffer != NULL); + assert(btn0 != NULL); + assert(btn1 != NULL); + + while (i < length && buffer[i] == ORCA_SKIP) { + i++; + } + if (i < length && buffer[i] != ORCA_SKIP) { + *btn0 = buffer[i]; + i++; + } else { + return JIANGTUN_FALSE; + } + + while (i < length - 1 && buffer[i] == ORCA_SKIP) { + i++; + } + if (i == length - 1 && buffer[i] != ORCA_SKIP) { + *btn1 = buffer[i]; + } else { + return JIANGTUN_FALSE; + } + + return JIANGTUN_TRUE; +} + +/** + * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/examples/WHALE/WHALE.ino#L207-L261 + */ +static jiangtun_bool_t patch(const jiangtun_uint8_t *buffer, size_t length, + void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + jiangtun_uint8_t btn0 = 0; + jiangtun_uint8_t btn1 = 0; + assert(buffer != NULL); + assert(length == 3); + assert(buffer[0] == ORCA_HEADER); + assert(report != NULL); + + if (!find_btns(&(buffer[1]), length - 1, &btn0, &btn1)) { + assert(JIANGTUN_FALSE); + return JIANGTUN_FALSE; + } + + if (btn0 == ORCA_RELEASE) { + report->a = JIANGTUN_FALSE; + report->b = JIANGTUN_FALSE; + report->x = JIANGTUN_FALSE; + report->y = JIANGTUN_FALSE; + report->l = JIANGTUN_FALSE; + report->r = JIANGTUN_FALSE; + } else { + report->a = (btn0 >> 0) & 1; + report->b = (btn0 >> 1) & 1; + report->x = (btn0 >> 2) & 1; + report->y = (btn0 >> 3) & 1; + report->l = (btn0 >> 4) & 1; + report->r = (btn0 >> 5) & 1; + } + + if (btn1 == ORCA_RELEASE) { + report->z = JIANGTUN_FALSE; + report->start = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->dup = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + } else { + report->z = (btn1 >> 0) & 1; + report->start = (btn1 >> 1) & 1; + report->dleft = (btn1 >> 2) & 1; + report->dright = (btn1 >> 3) & 1; + report->dup = (btn1 >> 4) & 1; + report->ddown = (btn1 >> 5) & 1; + } + + return JIANGTUN_TRUE; +} + +static void transition_0x80_btn0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + if (c != ORCA_SKIP) { + command->buffer[command->length++] = c; + } + jiangtun_command_init(command, c == ORCA_SKIP ? transition_0x80_btn0 : NULL, + c == ORCA_SKIP ? NULL : patch); +} + +static void transition_0x80(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + if (c != ORCA_SKIP) { + command->buffer[command->length++] = c; + } + jiangtun_command_init( + command, c == ORCA_SKIP ? transition_0x80 : transition_0x80_btn0, NULL); +} + +static void transition_initial(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == ORCA_HEADER ? transition_0x80 : NULL, + c == '@' ? patch_at_sign : NULL); +} + +void jiangtun_orca_init(jiangtun_orca_command_t *command) { + assert(command != NULL); + + command->base.buffer = command->buffer; + command->base.length = 0; + + jiangtun_command_init(&(command->base), transition_initial, NULL); +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/pokecon.c b/lib/jiangtun-core/src/pokecon.c index b7c2098..f92c37a 100644 --- a/lib/jiangtun-core/src/pokecon.c +++ b/lib/jiangtun-core/src/pokecon.c @@ -1,228 +1,661 @@ -#include +#include -#include +#include "internal.h" -jiangtun_error_t -jiangtun_pokecon_previous_state_init(jiangtun_pokecon_previous_state_t *prev) { - if (prev == NULL) { - return JIANGTUN_ERROR_NULL_POINTER; - } +#include +#include + +#define POKECON_HAT_UP 0 +#define POKECON_HAT_UPRIGHT 1 +#define POKECON_HAT_RIGHT 2 +#define POKECON_HAT_DOWNRIGHT 3 +#define POKECON_HAT_DOWN 4 +#define POKECON_HAT_DOWNLEFT 5 +#define POKECON_HAT_LEFT 6 +#define POKECON_HAT_UPLEFT 7 +#define POKECON_HAT_NEUTRAL 8 - prev->left.x = JIANGTUN_REPORT_STICK_NEUTRAL; - prev->left.y = JIANGTUN_REPORT_STICK_NEUTRAL; - prev->right.x = JIANGTUN_REPORT_STICK_NEUTRAL; - prev->right.y = JIANGTUN_REPORT_STICK_NEUTRAL; +static void patch_btns(jiangtun_report_mode3_t *report, + jiangtun_uint16_t btns) { + assert(report != NULL); - return JIANGTUN_SUCCESS; + report->y = (btns >> 2) & 1; + report->b = (btns >> 3) & 1; + report->a = (btns >> 4) & 1; + report->x = (btns >> 5) & 1; + report->l = (btns >> 6) & 1; + report->r = (btns >> 7) & 1; + /* zl = (btns >> 8) & 1; */ + report->z = (btns >> 9) & 1; + /* minus = (btns >> 10) & 1; */ + report->start = (btns >> 11) & 1; + /* l_click = (btns >> 12) & 1; */ + /* r_click = (btns >> 13) & 1; */ + report->reset = (btns >> 14) & 1; + /* capture = (btns >> 15) & 1; */ } -static void remove_0x(char *str) { - char *p = str; - while ((p = strstr(p, "0x")) != NULL) { - /* Remove "0x" by moving the rest of the string over it */ - memmove(p, p + 2, strlen(p + 2) + 1); +static void patch_hat(jiangtun_report_mode3_t *report, jiangtun_uint16_t hat) { + assert(report != NULL); + assert(hat <= POKECON_HAT_NEUTRAL); + + switch (hat) { + case POKECON_HAT_UP: + report->dup = JIANGTUN_TRUE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + case POKECON_HAT_UPRIGHT: + report->dup = JIANGTUN_TRUE; + report->dright = JIANGTUN_TRUE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + case POKECON_HAT_RIGHT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_TRUE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + case POKECON_HAT_DOWNRIGHT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_TRUE; + report->ddown = JIANGTUN_TRUE; + report->dleft = JIANGTUN_FALSE; + break; + case POKECON_HAT_DOWN: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_TRUE; + report->dleft = JIANGTUN_FALSE; + break; + case POKECON_HAT_DOWNLEFT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_TRUE; + report->dleft = JIANGTUN_TRUE; + break; + case POKECON_HAT_LEFT: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_TRUE; + break; + case POKECON_HAT_UPLEFT: + report->dup = JIANGTUN_TRUE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_TRUE; + break; + case POKECON_HAT_NEUTRAL: + report->dup = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + break; + default: + assert(JIANGTUN_FALSE); + break; } } -/* - * static const size_t MIN_VALID_LENGTH = sizeof("0 0\n"); - * static const size_t MAX_VALID_LENGTH = sizeof("0x0000 0 0x00 0x00 0x00 - * 0x00\r\n"); - */ -#define MIN_VALID_LENGTH 5 -#define MAX_VALID_LENGTH 31 +static void patch_ls(jiangtun_report_mode3_t *report, jiangtun_uint16_t lx, + jiangtun_uint16_t ly) { + assert(report != NULL); + assert(lx <= JIANGTUN_UINT8_MAX); + assert(ly <= JIANGTUN_UINT8_MAX); + + report->xAxis = (jiangtun_uint8_t)lx; + report->yAxis = (jiangtun_uint8_t)(JIANGTUN_UINT8_MAX - ly); +} + +static void patch_rs(jiangtun_report_mode3_t *report, jiangtun_uint16_t rx, + jiangtun_uint16_t ry) { + assert(report != NULL); + assert(rx <= JIANGTUN_UINT8_MAX); + assert(ry <= JIANGTUN_UINT8_MAX); -jiangtun_error_t -jiangtun_pokecon_parse(const jiangtun_uint8_t *buffer, size_t buffer_length, - jiangtun_report_t *out_report, - jiangtun_bool_t *out_reset, - jiangtun_pokecon_previous_state_t *prev) { + report->cxAxis = (jiangtun_uint8_t)rx; + report->cyAxis = (jiangtun_uint8_t)(JIANGTUN_UINT8_MAX - ry); +} + +static void copy_buf_to_str(const jiangtun_uint8_t *buffer, size_t length, + char *string) { size_t i = 0; + assert(buffer != NULL); + assert(length != 0); + assert(string != NULL); + /* assert(sizeof(string) >= length); */ - char str[MAX_VALID_LENGTH]; - size_t str_length = 0; - int whitespace_count = 0; - - jiangtun_uint16_t btns = 0x0000; - jiangtun_uint16_t hat = 8; - jiangtun_uint16_t x_0 = JIANGTUN_REPORT_STICK_NEUTRAL; - jiangtun_uint16_t y_0 = JIANGTUN_REPORT_STICK_NEUTRAL; - jiangtun_uint16_t x_1 = JIANGTUN_REPORT_STICK_NEUTRAL; - jiangtun_uint16_t y_1 = JIANGTUN_REPORT_STICK_NEUTRAL; - - jiangtun_bool_t update_rs = JIANGTUN_FALSE; - jiangtun_bool_t update_ls = JIANGTUN_FALSE; - - if (buffer == NULL || prev == NULL) { - return JIANGTUN_ERROR_INVALID_ARGUMENT; - } else if (buffer_length < MIN_VALID_LENGTH - 1 || - MAX_VALID_LENGTH - 1 < buffer_length) { - return JIANGTUN_ERROR_PARSE_FAILURE; + for (i = 0; i < length; i++) { + string[i] = (char)buffer[i]; } + string[i++] = '\0'; +} - if ((buffer_length == 4 || buffer_length == 5) && - (buffer[0] == 'e' && buffer[1] == 'n' && buffer[2] == 'd' && - (buffer[3] == '\n' || (buffer[3] == '\r' && buffer[4] == '\n')))) { +static void remove_0x_cr_lf(char *string) { + char *src = string; + char *dst = string; + assert(string != NULL); - if (out_report != NULL) { - if (jiangtun_report_init(out_report) != JIANGTUN_SUCCESS) { - return JIANGTUN_ERROR_INTERNAL; - } + while (*src != '\0') { + if (*src == '0' && *(src + 1) == 'x') { + src += 2; + } else if (*src == '\r' || *src == '\n') { + src++; + } else { + *dst++ = *src++; } + } + *dst = '\0'; +} - prev->left.x = JIANGTUN_REPORT_STICK_NEUTRAL; - prev->left.y = JIANGTUN_REPORT_STICK_NEUTRAL; - prev->right.x = JIANGTUN_REPORT_STICK_NEUTRAL; - prev->right.y = JIANGTUN_REPORT_STICK_NEUTRAL; +static jiangtun_bool_t patch_endrn(const jiangtun_uint8_t *buffer, + size_t length, void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + assert(buffer != NULL); + assert(length == 4 || (length == 5 && buffer[3] == '\r')); + assert(buffer[0] == 'e' && buffer[1] == 'n' && buffer[2] == 'd' && + buffer[length - 1] == '\n'); + assert(report != NULL); - return JIANGTUN_SUCCESS; - } + jiangtun_report_init(report); - /* Copy buffer into a new char[] */ - for (i = 0; i < buffer_length; i++) { - switch (buffer[i]) { - case '\r': - case '\n': - break; - - case ' ': - whitespace_count++; - /* fallthrough */ - default: - str_length++; - str[i] = buffer[i]; - break; - } - } - str[str_length++] = '\0'; - /* 0x" must be removed. Maybe this is another Newlib-nano restriction. */ - remove_0x(str); + return JIANGTUN_TRUE; +} + +static jiangtun_bool_t patch_0xhhhh_hrn(const jiangtun_uint8_t *buffer, + size_t length, void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + char string[sizeof("0x0000 0\r\n")]; + jiangtun_uint16_t btns = 0; + jiangtun_uint16_t hat = POKECON_HAT_NEUTRAL; + assert(buffer != NULL); + assert(sizeof("0 0\n") - 1 <= length && length <= sizeof(string) - 1); + assert(report != NULL); /* - * Use uint16_t and "%hx" instead of uint8_t and "%hhx", - * as Newlib-nano do not support C99 notation. - * https://ja-support.renesas.com/knowledgeBase/20441082 + * Use uint16_t and "%hx" instead of uint8_t and "%hhx" because Newlib-nano + * does not support C99 notation. + * ref: https://ja-support.renesas.com/knowledgeBase/20441082 + * + * The "0x" prefix must be removed. This might be another limitation of + * Newlib-nano. */ - switch (whitespace_count) { - case 1: - sscanf(str, "%hx %hx", &btns, &hat); - break; - case 3: - sscanf(str, "%hx %hx %hx %hx", &btns, &hat, &x_0, &y_0); - break; - case 5: - sscanf(str, "%hx %hx %hx %hx %hx %hx", &btns, &hat, &x_0, &y_0, &x_1, - &y_1); - break; - default: - return JIANGTUN_ERROR_PARSE_FAILURE; + copy_buf_to_str(buffer, length, string); + remove_0x_cr_lf(string); + sscanf(string, "%hx %hx", &btns, &hat); + if (hat > POKECON_HAT_NEUTRAL) { + assert(hat <= POKECON_HAT_NEUTRAL); + return JIANGTUN_FALSE; } - hat = hat % 9; - x_0 = x_0 & 0xFF; - y_0 = 0xFF - (y_0 & 0xFF); - x_1 = x_1 & 0xFF; - y_1 = 0xFF - (y_1 & 0xFF); - - update_rs = (jiangtun_bool_t)((btns >> 0) & 1); - update_ls = (jiangtun_bool_t)((btns >> 1) & 1); - - if (out_report != NULL) { - if (jiangtun_report_init(out_report) != JIANGTUN_SUCCESS) { - return JIANGTUN_ERROR_INTERNAL; - } - out_report->mode3.y = (btns >> 2) & 1; - out_report->mode3.b = (btns >> 3) & 1; - out_report->mode3.a = (btns >> 4) & 1; - out_report->mode3.x = (btns >> 5) & 1; - out_report->mode3.l = (btns >> 6) & 1; - out_report->mode3.r = (btns >> 7) & 1; - /* zl = (btns >> 8) & 1; */ - out_report->mode3.z = (btns >> 9) & 1; - /* minus = (btns >> 10) & 1; */ - out_report->mode3.start = (btns >> 11) & 1; - /* l_click = (btns >> 12) & 1; */ - /* r_click = (btns >> 13) & 1; */ - /* home = (btns >> 14) & 1; --> reset */ - /* capture = (btns >> 15) & 1; */ - - switch (hat) { - case 0: - out_report->mode3.dup = 1; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - case 1: - out_report->mode3.dup = 1; - out_report->mode3.dright = 1; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - case 2: - out_report->mode3.dup = 0; - out_report->mode3.dright = 1; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - case 3: - out_report->mode3.dup = 0; - out_report->mode3.dright = 1; - out_report->mode3.ddown = 1; - out_report->mode3.dleft = 0; - break; - case 4: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 1; - out_report->mode3.dleft = 0; - break; - case 5: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 1; - out_report->mode3.dleft = 1; - break; - case 6: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 1; - break; - case 7: - out_report->mode3.dup = 1; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 1; - break; - case 8: - default: - out_report->mode3.dup = 0; - out_report->mode3.dright = 0; - out_report->mode3.ddown = 0; - out_report->mode3.dleft = 0; - break; - } + patch_btns(report, btns); + patch_hat(report, hat); + + return JIANGTUN_TRUE; +} + +static jiangtun_bool_t +patch_0xhhhh_h_0xhh_0xhhrn(const jiangtun_uint8_t *buffer, size_t length, + void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + char string[sizeof("0x0001 0 0x00 0x00\r\n")]; + jiangtun_uint16_t btns = 0; + jiangtun_uint16_t hat = POKECON_HAT_NEUTRAL; + jiangtun_uint16_t x = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t y = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_bool_t update_r = JIANGTUN_FALSE; + jiangtun_bool_t update_l = JIANGTUN_FALSE; + assert(buffer != NULL); + assert(sizeof("1 0 0 0\n") - 1 <= length && length <= sizeof(string) - 1); + assert(report != NULL); + + /* Refer to `patch_0xhhhh_hrn` for these restrictions */ + copy_buf_to_str(buffer, length, string); + remove_0x_cr_lf(string); + sscanf(string, "%hx %hx %hx %hx", &btns, &hat, &x, &y); + if (hat > POKECON_HAT_NEUTRAL || x > JIANGTUN_UINT8_MAX || + y > JIANGTUN_UINT8_MAX) { + assert(hat <= POKECON_HAT_NEUTRAL); + assert(x <= JIANGTUN_UINT8_MAX); + assert(y <= JIANGTUN_UINT8_MAX); + return JIANGTUN_FALSE; } - if (update_ls) { - prev->left.x = (jiangtun_uint8_t)x_0; - prev->left.y = (jiangtun_uint8_t)y_0; + update_r = (btns >> 0) & 1; + update_l = (btns >> 1) & 1; + if ((!update_r && !update_l) || + /* When releasing the stick input generated by "Use LStick Mouse", + unexpected input "3 8 80 80\n" occurs. */ + (update_r && update_l && btns != 3)) { + return JIANGTUN_FALSE; } - if (update_rs) { - prev->right.x = (jiangtun_uint8_t)x_1; - prev->right.y = (jiangtun_uint8_t)y_1; + + patch_btns(report, btns); + patch_hat(report, hat); + if (update_r) { + patch_rs(report, x, y); } - if (out_report != NULL) { - out_report->mode3.xAxis = prev->left.x; - out_report->mode3.yAxis = prev->left.y; - out_report->mode3.cxAxis = prev->right.x; - out_report->mode3.cyAxis = prev->right.y; + if (update_l) { + patch_ls(report, x, y); } - if (out_reset != NULL) { - *out_reset = (jiangtun_bool_t)((btns >> 14) & 1); + return JIANGTUN_TRUE; +} + +static jiangtun_bool_t +patch_0xhhhh_h_0xhh_0xhh_0xhh_0xhhrn(const jiangtun_uint8_t *buffer, + size_t length, void *context) { + jiangtun_report_mode3_t *report = (jiangtun_report_mode3_t *)context; + char string[sizeof("0x0003 0 0x00 0x00 0x00 0x00\r\n")]; + jiangtun_uint16_t btns = 0; + jiangtun_uint16_t hat = POKECON_HAT_NEUTRAL; + jiangtun_uint16_t lx = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t ly = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t rx = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_uint16_t ry = JIANGTUN_REPORT_STICK_NEUTRAL; + jiangtun_bool_t update_r = JIANGTUN_FALSE; + jiangtun_bool_t update_l = JIANGTUN_FALSE; + assert(buffer != NULL); + assert(sizeof("3 0 0 0 0 0\n") - 1 <= length && + length <= sizeof(string) - 1); + assert(report != NULL); + + /* Refer to `patch_0xhhhh_hrn` for these restrictions */ + copy_buf_to_str(buffer, length, string); + remove_0x_cr_lf(string); + sscanf(string, "%hx %hx %hx %hx %hx %hx", &btns, &hat, &lx, &ly, &rx, &ry); + if (hat > POKECON_HAT_NEUTRAL || lx > JIANGTUN_UINT8_MAX || + ly > JIANGTUN_UINT8_MAX || rx > JIANGTUN_UINT8_MAX || + ry > JIANGTUN_UINT8_MAX || !(update_r = (btns >> 0) & 1) || + !(update_l = (btns >> 1) & 1)) { + assert(hat <= POKECON_HAT_NEUTRAL); + assert(lx <= JIANGTUN_UINT8_MAX); + assert(ly <= JIANGTUN_UINT8_MAX); + assert(rx <= JIANGTUN_UINT8_MAX); + assert(ry <= JIANGTUN_UINT8_MAX); + return JIANGTUN_FALSE; } - return JIANGTUN_SUCCESS; + patch_btns(report, btns); + patch_hat(report, hat); + patch_rs(report, rx, ry); + patch_ls(report, lx, ly); + + return JIANGTUN_TRUE; +} + +static jiangtun_bool_t is_hex_digit(jiangtun_uint8_t c) { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f'); +} + +static jiangtun_bool_t is_digit_0_to_8(jiangtun_uint8_t c) { + return '0' <= c && c <= '8'; +} + +static void +transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhhr(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhh_0xhh_0xhhrn + : NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, c == '\r' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhhr : NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhh_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xhh_0xh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, + is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhh + : c == '\r' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhhr + : NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhh_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xhh_0x(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, + is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xh : NULL, NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xhh_0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, + c == 'x' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0x + : is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhh + : c == '\r' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xhhr + : NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhh_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xhh_(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == '0' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0 + : is_hex_digit(c) + ? transition_0xhhhh_h_0xhh_0xhh_0xhh_0xh + : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xhh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, c == ' ' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_ : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0xh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh_0xhh + : c == ' ' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_ + : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0x(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh_0xh : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == 'x' ? transition_0xhhhh_h_0xhh_0xhh_0x + : is_hex_digit(c) + ? transition_0xhhhh_h_0xhh_0xhh_0xhh + : c == ' ' ? transition_0xhhhh_h_0xhh_0xhh_0xhh_ + : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh_(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == '0' ? transition_0xhhhh_h_0xhh_0xhh_0 + : is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh_0xh + : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhhr(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_0xhh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == ' ' ? transition_0xhhhh_h_0xhh_0xhh_ + : c == '\r' ? transition_0xhhhh_h_0xhh_0xhhr + : NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_0xh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh + : c == ' ' ? transition_0xhhhh_h_0xhh_0xhh_ + : c == '\r' ? transition_0xhhhh_h_0xhh_0xhhr + : NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_0x(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xh : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh_0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == 'x' ? transition_0xhhhh_h_0xhh_0x + : is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xhh + : c == ' ' ? transition_0xhhhh_h_0xhh_0xhh_ + : c == '\r' ? transition_0xhhhh_h_0xhh_0xhhr + : NULL, + c == '\n' ? patch_0xhhhh_h_0xhh_0xhhrn : NULL); +} + +static void transition_0xhhhh_h_0xhh_(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == '0' ? transition_0xhhhh_h_0xhh_0 + : is_hex_digit(c) ? transition_0xhhhh_h_0xhh_0xh + : NULL, + NULL); +} + +static void transition_0xhhhh_h_0xhh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == ' ' ? transition_0xhhhh_h_0xhh_ : NULL, NULL); +} + +static void transition_0xhhhh_h_0xh(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + is_hex_digit(c) ? transition_0xhhhh_h_0xhh + : c == ' ' ? transition_0xhhhh_h_0xhh_ + : NULL, + NULL); +} + +static void transition_0xhhhh_h_0x(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, is_hex_digit(c) ? transition_0xhhhh_h_0xh : NULL, NULL); +} + +static void transition_0xhhhh_h_0(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == 'x' ? transition_0xhhhh_h_0x + : is_hex_digit(c) ? transition_0xhhhh_h_0xhh + : c == ' ' ? transition_0xhhhh_h_0xhh_ + : NULL, + NULL); +} + +static void transition_0xhhhh_h_(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == '0' ? transition_0xhhhh_h_0 + : is_hex_digit(c) ? transition_0xhhhh_h_0xh + : NULL, + NULL); +} + +static void transition_0xhhhh_hr(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, NULL, + c == '\n' ? patch_0xhhhh_hrn : NULL); +} + +static void transition_0xhhhh_h(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == ' ' ? transition_0xhhhh_h_ + : c == '\r' ? transition_0xhhhh_hr + : NULL, + c == '\n' ? patch_0xhhhh_hrn : NULL); +} + +static void transition_0xhhhh_(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected( + command, c, is_digit_0_to_8(c) ? transition_0xhhhh_h : NULL, NULL); +} + +static void transition_0xhhhh(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, c == ' ' ? transition_0xhhhh_ : NULL, + NULL); +} + +static void transition_0xhhh(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + is_hex_digit(c) ? transition_0xhhhh + : c == ' ' ? transition_0xhhhh_ + : NULL, + NULL); +} + +static void transition_0xhh(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + is_hex_digit(c) ? transition_0xhhh + : c == ' ' ? transition_0xhhhh_ + : NULL, + NULL); +} + +static void transition_0xh(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + is_hex_digit(c) ? transition_0xhh + : c == ' ' ? transition_0xhhhh_ + : NULL, + NULL); +} + +static void transition_0x(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, is_hex_digit(c) ? transition_0xh : NULL, + NULL); +} + +static void transition_0(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == 'x' ? transition_0x + : is_hex_digit(c) ? transition_0xhh + : c == ' ' ? transition_0xhhhh_ + : NULL, + NULL); +} + +static void transition_endr(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, NULL, c == '\n' ? patch_endrn : NULL); +} + +static void transition_end(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, c == '\r' ? transition_endr : NULL, + c == '\n' ? patch_endrn : NULL); +} + +static void transition_en(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, c == 'd' ? transition_end : NULL, NULL); +} + +static void transition_e(jiangtun_command_t *command, jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == 'n' ? transition_en + : is_hex_digit(c) ? transition_0xhh + : c == ' ' ? transition_0xhhhh_ + : NULL, + NULL); +} + +static void transition_initial(jiangtun_command_t *command, + jiangtun_uint8_t c) { + assert(command != NULL); + + append_if_not_rejected(command, c, + c == '0' ? transition_0 + : c == 'e' ? transition_e + : is_hex_digit(c) ? transition_0xh + : NULL, + NULL); +} + +void jiangtun_pokecon_init(jiangtun_pokecon_command_t *command) { + assert(command != NULL); + + command->base.buffer = command->buffer; + command->base.length = 0; + + jiangtun_command_init(&(command->base), transition_initial, NULL); } \ No newline at end of file diff --git a/lib/jiangtun-core/src/report.c b/lib/jiangtun-core/src/report.c index 5eff34e..7c1f3e6 100644 --- a/lib/jiangtun-core/src/report.c +++ b/lib/jiangtun-core/src/report.c @@ -1,44 +1,40 @@ #include -jiangtun_error_t jiangtun_report_init(jiangtun_report_t *report) { - if (report == NULL) { - return JIANGTUN_ERROR_NULL_POINTER; - } +#include - report->mode3.a = 0; - report->mode3.b = 0; - report->mode3.x = 0; - report->mode3.y = 0; - report->mode3.start = 0; - report->mode3.dleft = 0; - report->mode3.dright = 0; - report->mode3.ddown = 0; - report->mode3.dup = 0; - report->mode3.z = 0; - report->mode3.r = 0; - report->mode3.l = 0; - report->mode3.xAxis = JIANGTUN_REPORT_STICK_NEUTRAL; - report->mode3.yAxis = JIANGTUN_REPORT_STICK_NEUTRAL; - report->mode3.cxAxis = JIANGTUN_REPORT_STICK_NEUTRAL; - report->mode3.cyAxis = JIANGTUN_REPORT_STICK_NEUTRAL; - report->mode3.left = 0; - report->mode3.right = 0; +void jiangtun_report_init(jiangtun_report_mode3_t *report) { + assert(report != NULL); - return JIANGTUN_SUCCESS; + report->a = JIANGTUN_FALSE; + report->b = JIANGTUN_FALSE; + report->x = JIANGTUN_FALSE; + report->y = JIANGTUN_FALSE; + report->start = JIANGTUN_FALSE; + report->dleft = JIANGTUN_FALSE; + report->dright = JIANGTUN_FALSE; + report->ddown = JIANGTUN_FALSE; + report->dup = JIANGTUN_FALSE; + report->z = JIANGTUN_FALSE; + report->r = JIANGTUN_FALSE; + report->l = JIANGTUN_FALSE; + report->xAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->yAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->cxAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->cyAxis = JIANGTUN_REPORT_STICK_NEUTRAL; + report->left = 0; + report->right = 0; + + report->reset = JIANGTUN_FALSE; } #define EMEND_AXIS(axis) \ ((axis) = (axis) == 0 ? 1 : (axis) == 255 ? 254 : (axis)) -jiangtun_error_t jiangtun_report_emend_axis(jiangtun_report_t *report) { - if (report == NULL) { - return JIANGTUN_ERROR_NULL_POINTER; - } - - EMEND_AXIS(report->mode3.xAxis); - EMEND_AXIS(report->mode3.yAxis); - EMEND_AXIS(report->mode3.cxAxis); - EMEND_AXIS(report->mode3.cyAxis); +void jiangtun_emend_axis(jiangtun_report_mode3_t *report) { + assert(report != NULL); - return JIANGTUN_SUCCESS; + EMEND_AXIS(report->xAxis); + EMEND_AXIS(report->yAxis); + EMEND_AXIS(report->cxAxis); + EMEND_AXIS(report->cyAxis); } \ No newline at end of file diff --git a/lib/jiangtun-core/test/arduino.c b/lib/jiangtun-core/test/arduino.c new file mode 100644 index 0000000..5fe873c --- /dev/null +++ b/lib/jiangtun-core/test/arduino.c @@ -0,0 +1,49 @@ +#include + +#include +#include + +static jiangtun_bool_t serial_read(jiangtun_board_t *board, + jiangtun_uint8_t *c) { + assert(board != NULL); + assert(c != NULL); + + fprintf(stderr, "serial_read\n"); + /* *c = '@'; */ + return JIANGTUN_FALSE; +} + +static void gamecube_send(jiangtun_board_t *board, + jiangtun_report_mode3_t *report) { + assert(board != NULL); + assert(report != NULL); + + fprintf(stderr, "gamecube_send\n"); +} + +static void led_blink_async(jiangtun_board_t *board, + jiangtun_uint32_t duration) { + assert(board != NULL); + + fprintf(stderr, "led_blink_async: %u\n", duration); +} + +int main(void) { + size_t i = 0; + jiangtun_t j; + jiangtun_board_t board; + jiangtun_feature_flag_t features = + JIANGTUN_FEATURE_ENABLE_LED_BLINK | JIANGTUN_FEATURE_ENABLE_NXMC2 | + JIANGTUN_FEATURE_ENABLE_POKECON | JIANGTUN_FEATURE_ENABLE_ORCA; + + /* setup */ + jiangtun_board_init(&board, serial_read, gamecube_send, led_blink_async); + jiangtun_init(&j, &board, features); + + /* loop */ + for (i = 0; i < 5; i++) { + jiangtun_loop(&j); + } + + return 0; +} diff --git a/lib/jiangtun-core/test/command.c b/lib/jiangtun-core/test/command.c new file mode 100644 index 0000000..64e7e06 --- /dev/null +++ b/lib/jiangtun-core/test/command.c @@ -0,0 +1,310 @@ +#include + +#include +#include +#include +#include + +typedef struct test_case_t { + enum { TEST_NXMC2, TEST_POKECON, TEST_ORCA, TEST_DOL } command; + jiangtun_uint8_t *buffer; + size_t length; + enum { TEST_PENDING, TEST_ACCEPTED, TEST_REJECTED } expected; + jiangtun_report_mode3_t *expected_report; +} test_case_t; + +#define TEST_CASES_APPEND(command_, buffer_, length_, expected_) \ + do { \ + test_cases[test_cases_length].command = (command_); \ + test_cases[test_cases_length].buffer = (jiangtun_uint8_t *)(buffer_); \ + test_cases[test_cases_length].length = (length_); \ + test_cases[test_cases_length].expected = (expected_); \ + test_cases[test_cases_length].expected_report = NULL; \ + test_cases_length++; \ + } while (0) + +#define TEST_ASSERT(expr) \ + if (!(expr)) { \ + fprintf(stderr, "Assertion failed: \"%s\", %s:%d, index: %lu\n", \ + #expr, __FILE__, __LINE__, (unsigned long)i); \ + test_failed_count++; \ + continue; \ + } \ + do { \ + } while (0) + +#define TEST_SET(report_, a_, b_, x_, y_, start_, dleft_, dright_, ddown_, \ + dup_, z_, r_, l_, xAxis_, yAxis_, cxAxis_, cyAxis_, left_, \ + right_, reset_) \ + do { \ + (report_)->a = (a_); \ + (report_)->b = (b_); \ + (report_)->x = (x_); \ + (report_)->y = (y_); \ + (report_)->start = (start_); \ + (report_)->dleft = (dleft_); \ + (report_)->dright = (dright_); \ + (report_)->ddown = (ddown_); \ + (report_)->dup = (dup_); \ + (report_)->z = (z_); \ + (report_)->r = (r_); \ + (report_)->l = (l_); \ + (report_)->xAxis = (xAxis_); \ + (report_)->yAxis = (yAxis_); \ + (report_)->cxAxis = (cxAxis_); \ + (report_)->cyAxis = (cyAxis_); \ + (report_)->left = (left_); \ + (report_)->right = (right_); \ + (report_)->reset = (reset_); \ + } while (0) + +#define TEST_COMPARE(expected_, actual_) \ + do { \ + TEST_ASSERT((expected_)->a == (actual_)->a); \ + TEST_ASSERT((expected_)->b == (actual_)->b); \ + TEST_ASSERT((expected_)->x == (actual_)->x); \ + TEST_ASSERT((expected_)->y == (actual_)->y); \ + TEST_ASSERT((expected_)->start == (actual_)->start); \ + TEST_ASSERT((expected_)->dleft == (actual_)->dleft); \ + TEST_ASSERT((expected_)->dright == (actual_)->dright); \ + TEST_ASSERT((expected_)->ddown == (actual_)->ddown); \ + TEST_ASSERT((expected_)->dup == (actual_)->dup); \ + TEST_ASSERT((expected_)->z == (actual_)->z); \ + TEST_ASSERT((expected_)->r == (actual_)->r); \ + TEST_ASSERT((expected_)->l == (actual_)->l); \ + TEST_ASSERT(abs((int)((expected_)->xAxis) - (actual_)->xAxis) <= 1); \ + TEST_ASSERT(abs((int)((expected_)->yAxis) - (actual_)->yAxis) <= 1); \ + TEST_ASSERT(abs((int)((expected_)->cxAxis) - (actual_)->cxAxis) <= 1); \ + TEST_ASSERT(abs((int)((expected_)->cyAxis) - (actual_)->cyAxis) <= 1); \ + TEST_ASSERT((expected_)->left == (actual_)->left); \ + TEST_ASSERT((expected_)->right == (actual_)->right); \ + TEST_ASSERT((expected_)->reset == (actual_)->reset); \ + } while (0) + +int test(void) { + size_t i = 0; + jiangtun_nxmc2_command_t nxmc2; + jiangtun_pokecon_command_t pokecon; + jiangtun_orca_command_t orca; + jiangtun_dol_command_t dol; + test_case_t test_cases[256]; + size_t test_cases_length = 0; + int test_failed_count = 0; + + jiangtun_report_mode3_t expected_y_reset; + jiangtun_report_mode3_t expected_dup; + jiangtun_report_mode3_t expected_dup_cupleft; + jiangtun_report_mode3_t expected_dup_upleft_cupleft; + jiangtun_report_mode3_t expected_all_bits; + jiangtun_report_mode3_t expected_neutral; + jiangtun_report_mode3_t expected_a; + jiangtun_report_mode3_t expected_cup; + jiangtun_report_mode3_t expected_reset; + + jiangtun_report_init(&expected_y_reset); + TEST_SET(&expected_y_reset, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_TRUE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_TRUE); + jiangtun_report_init(&expected_dup); + TEST_SET(&expected_dup, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_TRUE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE); + jiangtun_report_init(&expected_dup_cupleft); + TEST_SET(&expected_dup_cupleft, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_TRUE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_REPORT_STICK_LEFT, + JIANGTUN_REPORT_STICK_UP, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE); + jiangtun_report_init(&expected_dup_upleft_cupleft); + TEST_SET(&expected_dup_upleft_cupleft, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_TRUE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_LEFT, + JIANGTUN_REPORT_STICK_UP, JIANGTUN_REPORT_STICK_LEFT, + JIANGTUN_REPORT_STICK_UP, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE); + jiangtun_report_init(&expected_all_bits); + TEST_SET(&expected_all_bits, JIANGTUN_TRUE, JIANGTUN_TRUE, JIANGTUN_TRUE, + JIANGTUN_TRUE, JIANGTUN_TRUE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_TRUE, JIANGTUN_TRUE, + JIANGTUN_TRUE, JIANGTUN_REPORT_STICK_RIGHT, + JIANGTUN_REPORT_STICK_DOWN, JIANGTUN_REPORT_STICK_RIGHT, + JIANGTUN_REPORT_STICK_DOWN, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_TRUE); + jiangtun_report_init(&expected_neutral); + jiangtun_report_init(&expected_a); + TEST_SET(&expected_a, JIANGTUN_TRUE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE); + jiangtun_report_init(&expected_cup); + TEST_SET(&expected_cup, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_REPORT_STICK_UP, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE); + jiangtun_report_init(&expected_reset); + TEST_SET(&expected_reset, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_FALSE, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_REPORT_STICK_NEUTRAL, + JIANGTUN_REPORT_STICK_NEUTRAL, JIANGTUN_FALSE, JIANGTUN_FALSE, + JIANGTUN_TRUE); + + /* clang-format off */ + TEST_CASES_APPEND(TEST_NXMC2, "\xab\x01\x10\x08\x80\x80\x80\x80\x00\x01\x02", 11, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_y_reset; + TEST_CASES_APPEND(TEST_NXMC2, "\xab\x00\x00\x00", 4, TEST_PENDING); + TEST_CASES_APPEND(TEST_NXMC2, "\xff", 1, TEST_REJECTED); + + TEST_CASES_APPEND(TEST_POKECON, "0 0\n", 4, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0 0\r\n", 5, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0000 0\n", 7, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0000 0\r\n", 8, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0x0 0\n", 6, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0x0 0\r\n", 7, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0x0000 0\n", 9, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "0x0000 0\r\n", 10, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup; + TEST_CASES_APPEND(TEST_POKECON, "1 0 0 0\n", 8, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 0 0\r\n", 9, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 00 00\n", 10, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 00 00\r\n", 11, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 0x0 0x0\n", 12, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 0x0 0x0\r\n", 13, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 0x00 0x00\n", 14, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "1 0 0x00 0x00\r\n", 15, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 0 0\n", 12, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 0 0\r\n", 13, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 00 00\n", 14, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 00 00\r\n", 15, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 0x0 0x0\n", 16, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 0x0 0x0\r\n", 17, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 0x00 0x00\n", 18, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "3 0 0 0 0x00 0x00\r\n", 19, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_dup_upleft_cupleft; + TEST_CASES_APPEND(TEST_POKECON, "0xffff 8 0xff 0xff 0xff 0xff\r\n",30, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_all_bits; + TEST_CASES_APPEND(TEST_POKECON, "end\n", 4, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_neutral; + TEST_CASES_APPEND(TEST_POKECON, "end\r\n", 5, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_neutral; + TEST_CASES_APPEND(TEST_POKECON, "0 0", 3, TEST_PENDING); + TEST_CASES_APPEND(TEST_POKECON, "h", 1, TEST_REJECTED); + + TEST_CASES_APPEND(TEST_ORCA, "\x80\x00\x00", 3, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_neutral; + TEST_CASES_APPEND(TEST_ORCA, "\x80\xff\x00\x00", 4, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_neutral; + TEST_CASES_APPEND(TEST_ORCA, "\x80\x00\xff\x00", 4, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_neutral; + TEST_CASES_APPEND(TEST_ORCA, "@", 1, TEST_ACCEPTED); + TEST_CASES_APPEND(TEST_ORCA, "\x80\x00", 2, TEST_PENDING); + TEST_CASES_APPEND(TEST_ORCA, "\x79", 2, TEST_REJECTED); + + TEST_CASES_APPEND(TEST_DOL, "a", 1, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_a; + TEST_CASES_APPEND(TEST_DOL, "0", 1, TEST_ACCEPTED); + TEST_CASES_APPEND(TEST_DOL, "@", 1, TEST_ACCEPTED); + test_cases[test_cases_length - 1].expected_report = &expected_reset; + TEST_CASES_APPEND(TEST_DOL, "X", 1, TEST_REJECTED); + /* clang-format on */ + + for (i = 0; i < test_cases_length; i++) { + size_t j = 0; + test_case_t *test_case = &(test_cases[i]); + jiangtun_report_mode3_t report; + jiangtun_command_t *command = NULL; + + jiangtun_report_init(&report); + + switch (test_case->command) { + case TEST_NXMC2: + jiangtun_nxmc2_init(&nxmc2); + command = &(nxmc2.base); + break; + case TEST_POKECON: + jiangtun_pokecon_init(&pokecon); + command = &(pokecon.base); + break; + case TEST_ORCA: + jiangtun_orca_init(&orca); + command = &(orca.base); + break; + case TEST_DOL: + jiangtun_dol_init(&dol); + command = &(dol.base); + break; + default: + assert(0); + break; + } + + for (j = 0; j < test_case->length; j++) { + jiangtun_push(command, test_case->buffer[j]); + } + + switch (test_case->expected) { + case TEST_PENDING: + TEST_ASSERT(jiangtun_pending(command)); + break; + case TEST_ACCEPTED: + TEST_ASSERT(jiangtun_accepted(command)); + TEST_ASSERT(jiangtun_run(command, &report)); + if (test_case->expected_report != NULL) { + TEST_COMPARE(test_case->expected_report, &(report)); + } + break; + case TEST_REJECTED: + TEST_ASSERT(jiangtun_rejected(command)); + break; + default: + assert(0); + } + } + return test_failed_count; +} + +int main(void) { + int test_failed_count = 0; + test_failed_count += test(); + return test_failed_count; +} \ No newline at end of file diff --git a/lib/jiangtun-core/test/lexer.c b/lib/jiangtun-core/test/lexer.c deleted file mode 100644 index 6b6475b..0000000 --- a/lib/jiangtun-core/test/lexer.c +++ /dev/null @@ -1,345 +0,0 @@ -#include - -#include -#include - -typedef struct test_case_t { - jiangtun_uint8_t *buffer; - size_t buffer_length; - jiangtun_error_t expected_err; - jiangtun_lexer_result_t expected_ret; -} test_case_t; - -#define REGISTER_CASE(buffer_, buffer_length_, expexted_err_, expected_ret_) \ - do { \ - test_cases[i].buffer = (buffer_); \ - test_cases[i].buffer_length = (buffer_length_); \ - test_cases[i].expected_err = (expexted_err_); \ - test_cases[i].expected_ret = (expected_ret_); \ - i++; \ - } while (0) - -#define TEST_ASSERT(expr) \ - if (!(expr)) { \ - fprintf(stderr, "Assertion failed: \"%s\", index: %lu\n", #expr, \ - (unsigned long)i); \ - test_failed_count++; \ - continue; \ - } \ - do { \ - } while (0) - -int main() { - size_t i = 0; - - test_case_t test_cases[84]; - size_t test_cases_length = sizeof(test_cases) / sizeof(test_case_t); - size_t test_failed_count = 0; - - /* NULL pointer */ - jiangtun_uint8_t *buffer_0 = NULL; - /* Zero size */ - jiangtun_uint8_t buffer_1[] = {0x00}; - /* No match */ - jiangtun_uint8_t buffer_2[] = {0xFF}; - - /* NX Macro Controller */ - jiangtun_uint8_t buffer_3[] = {0xAB}; - jiangtun_uint8_t buffer_4[] = {0xAB, 0x00}; - jiangtun_uint8_t buffer_5[] = {0xAB, 0x00, 0x00}; - jiangtun_uint8_t buffer_6[] = {0xAB, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_7[] = {0xAB, 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_8[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_9[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_10[] = {0xAB, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_11[] = {0xAB, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_12[] = {0xAB, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_13[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}; - jiangtun_uint8_t buffer_14[] = {0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}; - - /* Poke-Controller */ - /* clang-format off */ - jiangtun_uint8_t buffer_15[] = "0"; - jiangtun_uint8_t buffer_16[] = "0 "; - jiangtun_uint8_t buffer_17[] = "0 0"; - jiangtun_uint8_t buffer_18[] = "0 0\r"; - jiangtun_uint8_t buffer_19[] = "0 0 "; - jiangtun_uint8_t buffer_20[] = "0 0 0"; - jiangtun_uint8_t buffer_21[] = "0 0 0 "; - jiangtun_uint8_t buffer_22[] = "0 0 0 0"; - jiangtun_uint8_t buffer_23[] = "0 0 0 0\r"; - jiangtun_uint8_t buffer_24[] = "0 0 0 0 "; - jiangtun_uint8_t buffer_25[] = "0 0 0 0 0"; - jiangtun_uint8_t buffer_26[] = "0 0 0 0 0 "; - jiangtun_uint8_t buffer_27[] = "0 0 0 0 0 0"; - jiangtun_uint8_t buffer_28[] = "0 0 0 0 0 0\r"; - - jiangtun_uint8_t buffer_29[] = "0 0\n"; - jiangtun_uint8_t buffer_30[] = "0 0\r\n"; - jiangtun_uint8_t buffer_31[] = "0 0 0 0\n"; - jiangtun_uint8_t buffer_32[] = "0 0 0 0\r\n"; - jiangtun_uint8_t buffer_33[] = "0 0 0 0 0 0\n"; - jiangtun_uint8_t buffer_34[] = "0 0 0 0 0 0\r\n"; - - jiangtun_uint8_t buffer_35[] = "0x"; - jiangtun_uint8_t buffer_36[] = "0x0"; - jiangtun_uint8_t buffer_37[] = "0x0 "; - jiangtun_uint8_t buffer_38[] = "0x0 0"; - jiangtun_uint8_t buffer_39[] = "0x0 0\r"; - jiangtun_uint8_t buffer_40[] = "0x0 0 "; - jiangtun_uint8_t buffer_41[] = "0x0 0 0"; - jiangtun_uint8_t buffer_42[] = "0x0 0 0x"; - jiangtun_uint8_t buffer_43[] = "0x0 0 0x0"; - jiangtun_uint8_t buffer_44[] = "0x0 0 0x0 "; - jiangtun_uint8_t buffer_45[] = "0x0 0 0x0 0"; - jiangtun_uint8_t buffer_46[] = "0x0 0 0x0 0x"; - jiangtun_uint8_t buffer_47[] = "0x0 0 0x0 0x0"; - jiangtun_uint8_t buffer_48[] = "0x0 0 0x0 0x0\r"; - jiangtun_uint8_t buffer_49[] = "0x0 0 0x0 0x0 "; - jiangtun_uint8_t buffer_50[] = "0x0 0 0x0 0x0 0"; - jiangtun_uint8_t buffer_51[] = "0x0 0 0x0 0x0 0x"; - jiangtun_uint8_t buffer_52[] = "0x0 0 0x0 0x0 0x0"; - jiangtun_uint8_t buffer_53[] = "0x0 0 0x0 0x0 0x0 "; - jiangtun_uint8_t buffer_54[] = "0x0 0 0x0 0x0 0x0 0"; - jiangtun_uint8_t buffer_55[] = "0x0 0 0x0 0x0 0x0 0x"; - jiangtun_uint8_t buffer_56[] = "0x0 0 0x0 0x0 0x0 0x0"; - jiangtun_uint8_t buffer_57[] = "0x0 0 0x0 0x0 0x0 0x0\r"; - - jiangtun_uint8_t buffer_58[] = "0x0 0\n"; - jiangtun_uint8_t buffer_59[] = "0x0 0\r\n"; - jiangtun_uint8_t buffer_60[] = "0x0 0 0x0 0x0\n"; - jiangtun_uint8_t buffer_61[] = "0x0 0 0x0 0x0\r\n"; - jiangtun_uint8_t buffer_62[] = "0x0 0 0x0 0x0 0x0 0x0\n"; - jiangtun_uint8_t buffer_63[] = "0x0 0 0x0 0x0 0x0 0x0\r\n"; - - jiangtun_uint8_t buffer_64[] = "0x0 0 0x0 0x0 0x0 0x0\r\n\xFF"; - - jiangtun_uint8_t buffer_65[] = "e"; - jiangtun_uint8_t buffer_66[] = "en"; - jiangtun_uint8_t buffer_67[] = "end"; - jiangtun_uint8_t buffer_68[] = "end\r"; - jiangtun_uint8_t buffer_69[] = "end\n"; - jiangtun_uint8_t buffer_70[] = "end\r\n"; - jiangtun_uint8_t buffer_71[] = "end\r\n\xFF"; - /* clang-format on */ - - jiangtun_uint8_t buffer_72[] = {0x80}; - jiangtun_uint8_t buffer_73[] = {0x80, 0x00}; - jiangtun_uint8_t buffer_74[] = {0x80, 0x00, 0x00}; - jiangtun_uint8_t buffer_75[] = {0x80, 0x00, 0x00, 0xFF}; - jiangtun_uint8_t buffer_76[] = {0x80, 0xFF}; - jiangtun_uint8_t buffer_77[] = {0x80, 0xFF, 0x00}; - jiangtun_uint8_t buffer_78[] = {0x80, 0xFF, 0xFF}; - jiangtun_uint8_t buffer_79[] = {0x80, 0x00}; - jiangtun_uint8_t buffer_80[] = {0x80, 0x00, 0xFF}; - jiangtun_uint8_t buffer_81[] = {0x80, 0x00, 0xFF, 0xFF}; - jiangtun_uint8_t buffer_82[] = {0x80, 0x00, 0xFF, 0xFF, 0x00}; - jiangtun_uint8_t buffer_83[] = {0x80, 0x00, 0xFF, 0xFF, 0x00, 0xFF}; - jiangtun_uint8_t buffer_84[] = "@"; - - /* NULL pointer */ - REGISTER_CASE(buffer_0, 1, JIANGTUN_SUCCESS, JIANGTUN_LEXER_NO_MATCH); - /* Zero size */ - REGISTER_CASE(buffer_1, 0, JIANGTUN_SUCCESS, JIANGTUN_LEXER_NO_MATCH); - /* No match */ - REGISTER_CASE(buffer_2, sizeof(buffer_2), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_NO_MATCH); - - /* NX Macro Controller */ - REGISTER_CASE(buffer_3, sizeof(buffer_3), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_4, sizeof(buffer_4), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_5, sizeof(buffer_5), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_6, sizeof(buffer_6), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_7, sizeof(buffer_7), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_8, sizeof(buffer_8), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_9, sizeof(buffer_9), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_10, sizeof(buffer_10), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_11, sizeof(buffer_11), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_12, sizeof(buffer_12), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_13, sizeof(buffer_13), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_NXMC2); - REGISTER_CASE(buffer_14, sizeof(buffer_14), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_NO_MATCH); - - /* Poke-Controller */ - REGISTER_CASE(buffer_15, sizeof(buffer_15) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_16, sizeof(buffer_16) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_17, sizeof(buffer_17) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_18, sizeof(buffer_18) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_19, sizeof(buffer_19) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_20, sizeof(buffer_20) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_21, sizeof(buffer_21) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_22, sizeof(buffer_22) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_23, sizeof(buffer_23) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_24, sizeof(buffer_24) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_25, sizeof(buffer_25) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_26, sizeof(buffer_26) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_27, sizeof(buffer_27) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_28, sizeof(buffer_28) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - - REGISTER_CASE(buffer_29, sizeof(buffer_29) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_30, sizeof(buffer_30) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_31, sizeof(buffer_31) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_32, sizeof(buffer_32) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_33, sizeof(buffer_33) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_34, sizeof(buffer_34) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - - REGISTER_CASE(buffer_35, sizeof(buffer_35) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_36, sizeof(buffer_36) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_37, sizeof(buffer_37) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_38, sizeof(buffer_38) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_39, sizeof(buffer_39) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_40, sizeof(buffer_40) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_41, sizeof(buffer_41) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_42, sizeof(buffer_42) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_43, sizeof(buffer_43) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_44, sizeof(buffer_44) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_45, sizeof(buffer_45) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_46, sizeof(buffer_46) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_47, sizeof(buffer_47) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_48, sizeof(buffer_48) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_49, sizeof(buffer_49) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_50, sizeof(buffer_50) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_51, sizeof(buffer_51) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_52, sizeof(buffer_52) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_53, sizeof(buffer_53) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_54, sizeof(buffer_54) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_55, sizeof(buffer_55) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_56, sizeof(buffer_56) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_57, sizeof(buffer_57) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - - REGISTER_CASE(buffer_58, sizeof(buffer_58) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_59, sizeof(buffer_59) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_60, sizeof(buffer_60) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_61, sizeof(buffer_61) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_62, sizeof(buffer_62) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_63, sizeof(buffer_63) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - - REGISTER_CASE(buffer_64, sizeof(buffer_64) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_NO_MATCH); - - REGISTER_CASE(buffer_65, sizeof(buffer_65) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_66, sizeof(buffer_66) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_67, sizeof(buffer_67) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_68, sizeof(buffer_68) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_69, sizeof(buffer_69) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_70, sizeof(buffer_70) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_POKECON); - REGISTER_CASE(buffer_71, sizeof(buffer_71) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_NO_MATCH); - - REGISTER_CASE(buffer_72, sizeof(buffer_72), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_73, sizeof(buffer_73), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_74, sizeof(buffer_74), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_ORCA); - REGISTER_CASE(buffer_75, sizeof(buffer_75), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_NO_MATCH); - REGISTER_CASE(buffer_76, sizeof(buffer_76), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_77, sizeof(buffer_77), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_78, sizeof(buffer_78), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_79, sizeof(buffer_79), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_80, sizeof(buffer_80), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_81, sizeof(buffer_81), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_PARTIAL); - REGISTER_CASE(buffer_82, sizeof(buffer_82), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_ORCA); - REGISTER_CASE(buffer_83, sizeof(buffer_83), JIANGTUN_SUCCESS, - JIANGTUN_LEXER_NO_MATCH); - REGISTER_CASE(buffer_84, sizeof(buffer_84) - 1, JIANGTUN_SUCCESS, - JIANGTUN_LEXER_MATCH_ORCA); - - for (i = 0; i < test_cases_length; i++) { - test_case_t *test_case = &(test_cases[i]); - jiangtun_lexer_t lexer; - jiangtun_error_t actual_err; - jiangtun_lexer_result_t actual_ret; - - TEST_ASSERT(JIANGTUN_SUCCESS == jiangtun_lexer_init(&lexer)); - TEST_ASSERT( - test_case->expected_err == - (actual_err = jiangtun_lex(&lexer, test_case->buffer, - test_case->buffer_length, &actual_ret))); - if (actual_err == JIANGTUN_SUCCESS) { - TEST_ASSERT(test_case->expected_ret == actual_ret); - } - TEST_ASSERT(JIANGTUN_SUCCESS == jiangtun_lexer_deinit(&lexer)); - } - - return 0; -} From 9a924beb4ec9e625281439eea5e25f988463ce17 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Wed, 9 Oct 2024 23:41:37 +0900 Subject: [PATCH 15/25] wip: main.cpp --- .clang-format | 4 + lib/jiangtun-core/CMakeLists.txt | 2 + .../LoopTimeMeasurement.ino | 30 + lib/jiangtun-core/include/jiangtun.h | 52 +- lib/jiangtun-core/include/jiangtun/board.h | 32 +- lib/jiangtun-core/include/jiangtun/command.h | 15 +- lib/jiangtun-core/include/jiangtun/optional.h | 24 + lib/jiangtun-core/include/jiangtun/report.h | 2 +- lib/jiangtun-core/src/board.c | 37 +- lib/jiangtun-core/src/command.c | 15 +- lib/jiangtun-core/src/jiangtun.c | 198 +++++-- lib/jiangtun-core/src/optional.c | 29 + lib/jiangtun-core/src/report.c | 2 +- lib/jiangtun-core/test/arduino.c | 28 +- lib/jiangtun-core/test/command.c | 10 +- src/jiangtun.h | 35 -- src/main.cpp | 552 +++++------------- 17 files changed, 504 insertions(+), 563 deletions(-) create mode 100644 .clang-format create mode 100644 lib/jiangtun-core/LoopTimeMeasurement/LoopTimeMeasurement.ino create mode 100644 lib/jiangtun-core/include/jiangtun/optional.h create mode 100644 lib/jiangtun-core/src/optional.c delete mode 100644 src/jiangtun.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..38c747e --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +--- +BasedOnStyle: LLVM +IndentWidth: 4 +... diff --git a/lib/jiangtun-core/CMakeLists.txt b/lib/jiangtun-core/CMakeLists.txt index dfa336f..a135811 100644 --- a/lib/jiangtun-core/CMakeLists.txt +++ b/lib/jiangtun-core/CMakeLists.txt @@ -1,9 +1,11 @@ cmake_minimum_required(VERSION 3.10) set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project(jiangtun-core VERSION 0.1.0) set(CMAKE_C_STANDARD 90) +set(CMAKE_C_EXTENSIONS OFF) file(GLOB_RECURSE SRC_FILES src/*.c) add_library(jiangtun-core STATIC ${SRC_FILES}) diff --git a/lib/jiangtun-core/LoopTimeMeasurement/LoopTimeMeasurement.ino b/lib/jiangtun-core/LoopTimeMeasurement/LoopTimeMeasurement.ino new file mode 100644 index 0000000..a34ffe0 --- /dev/null +++ b/lib/jiangtun-core/LoopTimeMeasurement/LoopTimeMeasurement.ino @@ -0,0 +1,30 @@ +#include + +#include + +static unsigned long start_time = 0; +static unsigned int loop_count = 0; + +void setup(void) { + Serial.begin(); + start_time = micros(); +} + +void loop_(void) { +} + +void loop(void) { + loop_(); + + if (loop_count++ >= 1000) { + unsigned long total_time = micros() - start_time; + double average_time = (double)total_time / 1000.0; + char buffer[256]; + + sprintf(buffer, "Average time per loop: %lf\n", average_time); + Serial.print(buffer); + + start_time = micros(); + loop_count = 0; + } +} diff --git a/lib/jiangtun-core/include/jiangtun.h b/lib/jiangtun-core/include/jiangtun.h index bc94b61..6c74c1e 100644 --- a/lib/jiangtun-core/include/jiangtun.h +++ b/lib/jiangtun-core/include/jiangtun.h @@ -4,14 +4,21 @@ #include "jiangtun/board.h" #include "jiangtun/command.h" #include "jiangtun/compat.h" +#include "jiangtun/optional.h" #include "jiangtun/report.h" #ifdef __cplusplus extern "C" { #endif -#define JIANGTUN_TIMEOUT_5MS 50 -#define JIANGTUN_AT_SIGN_500MS 500 +#ifndef JIANGTUN_MICROSECONDS_PER_LOOP +#define JIANGTUN_MICROSECONDS_PER_LOOP 0.54 +#endif /* JIANGTUN_MICROSECONDS_PER_LOOP */ +#define JIANGTUN_LOOPS_FOR_MILLISECONDS(ms) \ + ((jiangtun_uint32_t)((1000 * (ms)) / JIANGTUN_MICROSECONDS_PER_LOOP) + 1) +#define JIANGTUN_LOOPS_FOR_TIMEOUT JIANGTUN_LOOPS_FOR_MILLISECONDS(5) +#define JIANGTUN_LOOPS_FOR_LED JIANGTUN_LOOPS_FOR_MILLISECONDS(100) +#define JIANGTUN_LOOPS_FOR_RESET_BLOCKING JIANGTUN_LOOPS_FOR_MILLISECONDS(500) typedef jiangtun_uint32_t jiangtun_feature_flag_t; #define JIANGTUN_FEATURE_ENABLE_LED_BLINK ((jiangtun_feature_flag_t)(1 << 4)) @@ -20,30 +27,53 @@ typedef jiangtun_uint32_t jiangtun_feature_flag_t; #define JIANGTUN_FEATURE_ENABLE_ORCA ((jiangtun_feature_flag_t)(1 << 1)) #define JIANGTUN_FEATURE_ENABLE_DOL ((jiangtun_feature_flag_t)(1 << 0)) +/** + * Compared to the levels commonly provided by high-functionality logging + * libraries, such as "FATAL, ERROR, WARN, INFO, DEBUG, TRACE," the logging + * levels provided here are limited. + * First, Jiangtun does not have a path that leads to FATAL. More precisely, + * there is no way to detect when such a condition occurs. Even if there were a + * way to detect it, in situations where we would want to output a FATAL or + * ERROR log from the firmware, the system is likely already in a state where + * halting cannot be avoided, and it's hard to imagine that output resources + * could be secured at that point. + * Additionally, this library is small-scale enough that during debugging, we + * always want information equivalent to TRACE. There's no need to differentiate + * between DEBUG and TRACE. + */ +typedef enum jiangtun_log_level_t { + JIANGTUN_LOG_LEVEL_WARN, + JIANGTUN_LOG_LEVEL_INFO, + JIANGTUN_LOG_LEVEL_DEBUG +} jiangtun_log_level_t; + typedef struct jiangtun_t { jiangtun_board_t *board; + jiangtun_feature_flag_t features; jiangtun_nxmc2_command_t nxmc2; jiangtun_pokecon_command_t pokecon; jiangtun_orca_command_t orca; jiangtun_dol_command_t dol; - jiangtun_command_t *commands[4]; + jiangtun_report_mode3_t reports[4]; - size_t recently_patched; + jiangtun_report_mode3_t *recently_patched; - jiangtun_uint8_t stash_carry_over_; - jiangtun_uint8_t *carry_over; + jiangtun_bool_t any_pending; - jiangtun_uint32_t timeout_loop_count; + jiangtun_optional_uint8_t carry_over; - jiangtun_bool_t at_sign; - jiangtun_uint32_t at_sign_loop_count; + jiangtun_uint32_t timeout_loop; + jiangtun_uint32_t led_loop; + jiangtun_uint32_t reset_blocking_loop; - jiangtun_feature_flag_t features; + jiangtun_log_level_t log_level; + char log_buffer[128]; } jiangtun_t; -void jiangtun_init(jiangtun_t *, jiangtun_board_t *, jiangtun_feature_flag_t); +void jiangtun_init(jiangtun_t *, jiangtun_board_t *, jiangtun_feature_flag_t, + jiangtun_log_level_t); void jiangtun_loop(jiangtun_t *); #ifdef __cplusplus diff --git a/lib/jiangtun-core/include/jiangtun/board.h b/lib/jiangtun-core/include/jiangtun/board.h index 384f69d..df8d481 100644 --- a/lib/jiangtun-core/include/jiangtun/board.h +++ b/lib/jiangtun-core/include/jiangtun/board.h @@ -9,26 +9,30 @@ extern "C" { #endif typedef struct jiangtun_board_t { - jiangtun_bool_t (*serial_read)(struct jiangtun_board_t *, + jiangtun_bool_t (*serial_getc)(struct jiangtun_board_t *, jiangtun_uint8_t *); - void (*gamecube_send)(struct jiangtun_board_t *, jiangtun_report_mode3_t *); - void (*led_blink_async)(struct jiangtun_board_t *, jiangtun_uint32_t); + void (*serial_puts)(struct jiangtun_board_t *, const char *); + jiangtun_bool_t (*gamecube_send)(struct jiangtun_board_t *, + jiangtun_report_mode3_t *); + void (*led_set)(struct jiangtun_board_t *, jiangtun_bool_t); } jiangtun_board_t; -typedef jiangtun_bool_t (*jiangtun_serial_read_t)(jiangtun_board_t *, +typedef jiangtun_bool_t (*jiangtun_serial_getc_t)(jiangtun_board_t *, jiangtun_uint8_t *); -typedef void (*jiangtun_gamecube_send_t)(jiangtun_board_t *, - jiangtun_report_mode3_t *); -typedef void (*jiangtun_led_blink_async_t)(jiangtun_board_t *, - jiangtun_uint32_t); +typedef void (*jiangtun_serial_puts_t)(jiangtun_board_t *, const char *); +typedef jiangtun_bool_t (*jiangtun_gamecube_send_t)(jiangtun_board_t *, + jiangtun_report_mode3_t *); +typedef void (*jiangtun_led_set_t)(jiangtun_board_t *, jiangtun_bool_t); -jiangtun_bool_t jiangtun_board_serial_read(jiangtun_board_t *, +jiangtun_bool_t jiangtun_board_serial_getc(jiangtun_board_t *, jiangtun_uint8_t *); -void jiangtun_board_gamecube_send(jiangtun_board_t *, - jiangtun_report_mode3_t *); -void jiangtun_board_led_blink_async(jiangtun_board_t *, jiangtun_uint32_t); -void jiangtun_board_init(jiangtun_board_t *, jiangtun_serial_read_t, - jiangtun_gamecube_send_t, jiangtun_led_blink_async_t); +void jiangtun_board_serial_puts(jiangtun_board_t *, const char *); +jiangtun_bool_t jiangtun_board_gamecube_send(jiangtun_board_t *, + jiangtun_report_mode3_t *); +void jiangtun_board_led_set(jiangtun_board_t *, jiangtun_bool_t); +void jiangtun_board_init(jiangtun_board_t *, jiangtun_serial_getc_t, + jiangtun_serial_puts_t, jiangtun_gamecube_send_t, + jiangtun_led_set_t); #ifdef __cplusplus } diff --git a/lib/jiangtun-core/include/jiangtun/command.h b/lib/jiangtun-core/include/jiangtun/command.h index 31d2f42..538fb1f 100644 --- a/lib/jiangtun-core/include/jiangtun/command.h +++ b/lib/jiangtun-core/include/jiangtun/command.h @@ -19,21 +19,16 @@ typedef struct jiangtun_command_t { jiangtun_action_t action; } jiangtun_command_t; -/* - * In C, a struct must be declared before it can be used in a function pointer - * declaration. Therefore, `jiangtun_command_t` is declared first, followed by - * the `jiangtun_transition_t` function pointer type. - */ typedef void (*jiangtun_transition_t)(jiangtun_command_t *, jiangtun_uint8_t); void jiangtun_command_init(jiangtun_command_t *, jiangtun_transition_t, jiangtun_action_t); -void jiangtun_push(jiangtun_command_t *, jiangtun_uint8_t); -jiangtun_bool_t jiangtun_run(jiangtun_command_t *, void *); +void jiangtun_command_push(jiangtun_command_t *, jiangtun_uint8_t); +jiangtun_bool_t jiangtun_command_run(jiangtun_command_t *, void *); -jiangtun_bool_t jiangtun_pending(jiangtun_command_t *); -jiangtun_bool_t jiangtun_accepted(jiangtun_command_t *); -jiangtun_bool_t jiangtun_rejected(jiangtun_command_t *); +jiangtun_bool_t jiangtun_command_pending(jiangtun_command_t *); +jiangtun_bool_t jiangtun_command_accepted(jiangtun_command_t *); +jiangtun_bool_t jiangtun_command_rejected(jiangtun_command_t *); /** * NX Macro Controller diff --git a/lib/jiangtun-core/include/jiangtun/optional.h b/lib/jiangtun-core/include/jiangtun/optional.h new file mode 100644 index 0000000..1739223 --- /dev/null +++ b/lib/jiangtun-core/include/jiangtun/optional.h @@ -0,0 +1,24 @@ +#ifndef JIANGTUN_OPTIONAL_H +#define JIANGTUN_OPTIONAL_H + +#include "compat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct jiangtun_optional_uint8_t { + jiangtun_uint8_t value; + jiangtun_uint8_t *pointer; +} jiangtun_optional_uint8_t; + +void jiangtun_optional_uint8_set(jiangtun_optional_uint8_t *, jiangtun_uint8_t); +jiangtun_bool_t jiangtun_optional_uint8_get(jiangtun_optional_uint8_t *, + jiangtun_uint8_t *); +void jiangtun_optional_uint8_clear(jiangtun_optional_uint8_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* JIANGTUN_OPTIONAL_H */ \ No newline at end of file diff --git a/lib/jiangtun-core/include/jiangtun/report.h b/lib/jiangtun-core/include/jiangtun/report.h index 9f5329a..86c4854 100644 --- a/lib/jiangtun-core/include/jiangtun/report.h +++ b/lib/jiangtun-core/include/jiangtun/report.h @@ -61,7 +61,7 @@ void jiangtun_report_init(jiangtun_report_mode3_t *); * controller's axis values do not usually occur in actual input. As a result, * some games may not handle these values correctly. */ -void jiangtun_emend_axis(jiangtun_report_mode3_t *); +void jiangtun_report_emend_axis(jiangtun_report_mode3_t *); #ifdef __cplusplus } diff --git a/lib/jiangtun-core/src/board.c b/lib/jiangtun-core/src/board.c index 02d487d..13d3814 100644 --- a/lib/jiangtun-core/src/board.c +++ b/lib/jiangtun-core/src/board.c @@ -2,39 +2,48 @@ #include -jiangtun_bool_t jiangtun_board_serial_read(jiangtun_board_t *board, +jiangtun_bool_t jiangtun_board_serial_getc(jiangtun_board_t *board, jiangtun_uint8_t *c) { assert(board != NULL); assert(c != NULL); - return board->serial_read(board, c); + return board->serial_getc(board, c); } -void jiangtun_board_gamecube_send(jiangtun_board_t *board, - jiangtun_report_mode3_t *report) { +void jiangtun_board_serial_puts(jiangtun_board_t *board, const char *s) { + assert(board != NULL); + assert(s != NULL); + + board->serial_puts(board, s); +} + +jiangtun_bool_t jiangtun_board_gamecube_send(jiangtun_board_t *board, + jiangtun_report_mode3_t *report) { assert(board != NULL); assert(report != NULL); - board->gamecube_send(board, report); + return board->gamecube_send(board, report); } -void jiangtun_board_led_blink_async(jiangtun_board_t *board, - jiangtun_uint32_t duration) { +void jiangtun_board_led_set(jiangtun_board_t *board, jiangtun_bool_t state) { assert(board != NULL); - board->led_blink_async(board, duration); + board->led_set(board, state); } void jiangtun_board_init(jiangtun_board_t *board, - jiangtun_serial_read_t serial_read, + jiangtun_serial_getc_t serial_getc, + jiangtun_serial_puts_t serial_puts, jiangtun_gamecube_send_t gamecube_send, - jiangtun_led_blink_async_t led_blink_async) { + jiangtun_led_set_t led_set) { assert(board != NULL); - assert(serial_read != NULL); + assert(serial_getc != NULL); + assert(serial_puts != NULL); assert(gamecube_send != NULL); - assert(led_blink_async != NULL); + assert(led_set != NULL); - board->serial_read = serial_read; + board->serial_getc = serial_getc; + board->serial_puts = serial_puts; board->gamecube_send = gamecube_send; - board->led_blink_async = led_blink_async; + board->led_set = led_set; } \ No newline at end of file diff --git a/lib/jiangtun-core/src/command.c b/lib/jiangtun-core/src/command.c index 134e1bb..d655ca8 100644 --- a/lib/jiangtun-core/src/command.c +++ b/lib/jiangtun-core/src/command.c @@ -26,7 +26,7 @@ static jiangtun_bool_t jiangtun_terminal(jiangtun_command_t *command) { /* for safety */ command->transition == NULL; } -jiangtun_bool_t jiangtun_pending(jiangtun_command_t *command) { +jiangtun_bool_t jiangtun_command_pending(jiangtun_command_t *command) { assert(command != NULL); return !jiangtun_terminal(command) && @@ -34,14 +34,14 @@ jiangtun_bool_t jiangtun_pending(jiangtun_command_t *command) { /* for safety */ command->action == NULL); } -jiangtun_bool_t jiangtun_accepted(jiangtun_command_t *command) { +jiangtun_bool_t jiangtun_command_accepted(jiangtun_command_t *command) { assert(command != NULL); return command->action != action_default && /* for safety */ command->action != NULL; } -jiangtun_bool_t jiangtun_rejected(jiangtun_command_t *command) { +jiangtun_bool_t jiangtun_command_rejected(jiangtun_command_t *command) { assert(command != NULL); return jiangtun_terminal(command) && @@ -64,12 +64,12 @@ void append_if_not_rejected(jiangtun_command_t *command, jiangtun_uint8_t c, assert(command != NULL); jiangtun_command_init(command, transition, action); - if (!jiangtun_rejected(command)) { + if (!jiangtun_command_rejected(command)) { command->buffer[command->length++] = c; } } -void jiangtun_push(jiangtun_command_t *command, jiangtun_uint8_t c) { +void jiangtun_command_push(jiangtun_command_t *command, jiangtun_uint8_t c) { assert(command != NULL); if (jiangtun_terminal(command)) { @@ -78,10 +78,11 @@ void jiangtun_push(jiangtun_command_t *command, jiangtun_uint8_t c) { command->transition(command, c); } -jiangtun_bool_t jiangtun_run(jiangtun_command_t *command, void *context) { +jiangtun_bool_t jiangtun_command_run(jiangtun_command_t *command, + void *context) { assert(command != NULL); - return jiangtun_accepted(command) + return jiangtun_command_accepted(command) ? command->action(command->buffer, command->length, context) : JIANGTUN_FALSE; } \ No newline at end of file diff --git a/lib/jiangtun-core/src/jiangtun.c b/lib/jiangtun-core/src/jiangtun.c index 33a80d6..c893c6b 100644 --- a/lib/jiangtun-core/src/jiangtun.c +++ b/lib/jiangtun-core/src/jiangtun.c @@ -1,132 +1,214 @@ #include #include +#include -static void commands_init(jiangtun_t *j) { +#define UNIX_EPOCH "1970-01-01T00:00:00Z" + +static void serial_log(jiangtun_t *j, jiangtun_log_level_t level, + const char *s) { + char time_string[sizeof(UNIX_EPOCH)]; + time_t now = time(NULL); + struct tm *tm_info = gmtime(&now); + + if (tm_info != NULL) { + strftime(time_string, sizeof(time_string), "%Y-%m-%dT%H:%M:%SZ", + tm_info); + } else { + sprintf(time_string, UNIX_EPOCH); + } + + sprintf(j->log_buffer, "[%s]\t[%s]\t%s\n", time_string, + level == JIANGTUN_LOG_LEVEL_WARN ? "warn" + : level == JIANGTUN_LOG_LEVEL_INFO ? "info" + : level == JIANGTUN_LOG_LEVEL_DEBUG ? "debug" + : "unknown", + s); + if (j->log_level >= level) { + jiangtun_board_serial_puts(j->board, j->log_buffer); + } +} + +static void init_commands(jiangtun_t *j) { assert(j != NULL); + j->any_pending = JIANGTUN_FALSE; + j->commands[0] = &(j->nxmc2.base); j->commands[1] = &(j->pokecon.base); j->commands[2] = &(j->orca.base); j->commands[3] = &(j->dol.base); if (j->features & JIANGTUN_FEATURE_ENABLE_NXMC2) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, + "initializing NX Macro Controller"); jiangtun_nxmc2_init(&(j->nxmc2)); } else { jiangtun_command_init(j->commands[0], NULL, NULL); } if (j->features & JIANGTUN_FEATURE_ENABLE_POKECON) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "initializing Poke-Controller"); jiangtun_pokecon_init(&(j->pokecon)); } else { jiangtun_command_init(j->commands[1], NULL, NULL); } if (j->features & JIANGTUN_FEATURE_ENABLE_ORCA) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, + "initializing ORCA GC Controller"); jiangtun_orca_init(&(j->orca)); } else { jiangtun_command_init(j->commands[2], NULL, NULL); } if (j->features & JIANGTUN_FEATURE_ENABLE_DOL) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, + "initializing DOL Macro Controller"); jiangtun_dol_init(&(j->dol)); } else { jiangtun_command_init(j->commands[3], NULL, NULL); } } -static void reports_init(jiangtun_t *j) { +static void init_reports(jiangtun_t *j) { assert(j != NULL); jiangtun_report_init(&(j->reports[0])); jiangtun_report_init(&(j->reports[1])); jiangtun_report_init(&(j->reports[2])); jiangtun_report_init(&(j->reports[3])); + + j->recently_patched = &(j->reports[0]); } void jiangtun_init(jiangtun_t *j, jiangtun_board_t *board, - jiangtun_feature_flag_t features) { + jiangtun_feature_flag_t features, + jiangtun_log_level_t log_level) { + jiangtun_bool_t handshake_result = JIANGTUN_FALSE; assert(j != NULL); assert(board != NULL); - j->features = features; - - reports_init(j); - commands_init(j); - j->board = board; - j->recently_patched = 0; - j->stash_carry_over_ = 0; - j->carry_over = NULL; - j->timeout_loop_count = 0; - j->at_sign = JIANGTUN_FALSE; - j->at_sign_loop_count = 0; + j->features = features; + init_commands(j); + init_reports(j); + j->any_pending = JIANGTUN_FALSE; + jiangtun_optional_uint8_clear(&(j->carry_over)); + j->timeout_loop = JIANGTUN_LOOPS_FOR_TIMEOUT; + j->led_loop = 0; + j->reset_blocking_loop = 0; + j->log_level = log_level; /* * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/examples/WHALE/WHALE.ino#L36-L41 */ j->reports[0].start = JIANGTUN_TRUE; - jiangtun_board_gamecube_send(j->board, &(j->reports[0])); - + handshake_result = jiangtun_board_gamecube_send(j->board, &(j->reports[0])); j->reports[0].start = JIANGTUN_FALSE; - jiangtun_board_gamecube_send(j->board, &(j->reports[0])); + handshake_result = + jiangtun_board_gamecube_send(j->board, &(j->reports[0])) && + handshake_result; + if (!handshake_result) { + serial_log(j, JIANGTUN_LOG_LEVEL_WARN, + "handshake failed during initial communications"); + } } -void jiangtun_loop(jiangtun_t *j) { +static void process_input(jiangtun_t *j) { size_t i = 0; jiangtun_uint8_t c = 0; - jiangtun_bool_t at_sign = JIANGTUN_FALSE; - jiangtun_bool_t any_pending = JIANGTUN_FALSE; - jiangtun_report_mode3_t *report = NULL; + jiangtun_bool_t all_rejected = JIANGTUN_TRUE; assert(j != NULL); - if (j->at_sign) { - goto gamecube_send; + if (j->reset_blocking_loop > 0) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking_loop active"); + return; } - if (j->carry_over == NULL && !jiangtun_board_serial_read(j->board, &c)) { - if (++(j->timeout_loop_count) > JIANGTUN_TIMEOUT_5MS) { - commands_init(j); - j->timeout_loop_count = 0; - } - goto gamecube_send; - } + if (jiangtun_optional_uint8_get(&(j->carry_over), &c)) { + sprintf(j->log_buffer, "carry_over value used: %u", c); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); - j->timeout_loop_count = 0; - if (j->carry_over != NULL) { - c = *(j->carry_over); - j->carry_over = NULL; + } else if (jiangtun_board_serial_getc(j->board, &c)) { + sprintf(j->log_buffer, "received input: %u", c); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + + } else { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "no input received"); + if (j->any_pending && --(j->timeout_loop) == 0) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "input timeout"); + init_commands(j); + j->timeout_loop = JIANGTUN_LOOPS_FOR_TIMEOUT; + } + return; } + j->timeout_loop = JIANGTUN_LOOPS_FOR_TIMEOUT; + jiangtun_optional_uint8_clear(&(j->carry_over)); for (i = 0; i < 4; i++) { - jiangtun_push(j->commands[i], c); - if (jiangtun_accepted(j->commands[i])) { - jiangtun_run(j->commands[i], &(j->reports[i])); - commands_init(j); - j->recently_patched = i; - at_sign = c == '@'; - goto gamecube_send; - - } else if (jiangtun_pending(j->commands[i])) { - any_pending = JIANGTUN_TRUE; + jiangtun_command_push(j->commands[i], c); + if (jiangtun_command_accepted(j->commands[i])) { + sprintf(j->log_buffer, "command #%lu accepted", (unsigned long)i); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + + if (!jiangtun_command_run(j->commands[i], &(j->reports[i]))) { + serial_log(j, JIANGTUN_LOG_LEVEL_WARN, + "something went wrong during jiangtun_command_run"); + /* as rejected */ + continue; + } + sprintf(j->log_buffer, "command #%lu executed successfully", + (unsigned long)i); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + j->recently_patched = &(j->reports[i]); + + jiangtun_board_led_set( + j->board, j->features & JIANGTUN_FEATURE_ENABLE_LED_BLINK); + j->led_loop += JIANGTUN_LOOPS_FOR_LED; + + if (!j->any_pending && c == '@') { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, + "'@' received, initiating reset_blocking_loop"); + j->reset_blocking_loop = JIANGTUN_LOOPS_FOR_RESET_BLOCKING; + } + init_commands(j); + return; + } else if (jiangtun_command_pending(j->commands[i])) { + all_rejected = JIANGTUN_FALSE; } } - if (!any_pending) { - j->stash_carry_over_ = c; - j->carry_over = &(j->stash_carry_over_); - commands_init(j); + if (j->any_pending && all_rejected) { + sprintf(j->log_buffer, "all commands rejected, carry_over set: %u", c); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + jiangtun_optional_uint8_set(&(j->carry_over), c); + init_commands(j); + return; } + j->any_pending = JIANGTUN_TRUE; +} -gamecube_send: - report = &(j->reports[j->recently_patched]); - if (j->at_sign && ++(j->at_sign_loop_count) > JIANGTUN_AT_SIGN_500MS) { - report->reset = JIANGTUN_FALSE; - j->at_sign_loop_count = 0; +void jiangtun_loop(jiangtun_t *j) { + assert(j != NULL); + + process_input(j); + + if (j->reset_blocking_loop > 0 && --(j->reset_blocking_loop) == 0) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, + "reset_blocking_loop completed, reset flag cleared"); + j->recently_patched->reset = JIANGTUN_FALSE; } - jiangtun_emend_axis(report); - jiangtun_board_gamecube_send(j->board, report); - if (j->features & JIANGTUN_FEATURE_ENABLE_LED_BLINK) { - jiangtun_board_led_blink_async(j->board, 50); + jiangtun_report_emend_axis(j->recently_patched); + + if (!jiangtun_board_gamecube_send(j->board, j->recently_patched)) { + serial_log(j, JIANGTUN_LOG_LEVEL_WARN, + "failed to send report: gamecube is either not powered on " + "or not connected"); + } + + if (j->led_loop > 0 && --(j->led_loop) == 0) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, + "led_loop completed, turning off"); + jiangtun_board_led_set(j->board, JIANGTUN_FALSE); } - j->at_sign = at_sign; } \ No newline at end of file diff --git a/lib/jiangtun-core/src/optional.c b/lib/jiangtun-core/src/optional.c new file mode 100644 index 0000000..9d11ce0 --- /dev/null +++ b/lib/jiangtun-core/src/optional.c @@ -0,0 +1,29 @@ +#include + +#include + +void jiangtun_optional_uint8_set(jiangtun_optional_uint8_t *optional, + jiangtun_uint8_t value) { + assert(optional != NULL); + + optional->value = value; + optional->pointer = &(optional->value); +} + +jiangtun_bool_t jiangtun_optional_uint8_get(jiangtun_optional_uint8_t *optional, + jiangtun_uint8_t *value) { + assert(optional != NULL); + assert(value != NULL); + + if (optional->pointer == NULL) { + return JIANGTUN_FALSE; + } + *value = optional->value; + return JIANGTUN_TRUE; +} + +void jiangtun_optional_uint8_clear(jiangtun_optional_uint8_t *optional) { + assert(optional != NULL); + + optional->pointer = NULL; +} \ No newline at end of file diff --git a/lib/jiangtun-core/src/report.c b/lib/jiangtun-core/src/report.c index 7c1f3e6..9b85dbe 100644 --- a/lib/jiangtun-core/src/report.c +++ b/lib/jiangtun-core/src/report.c @@ -30,7 +30,7 @@ void jiangtun_report_init(jiangtun_report_mode3_t *report) { #define EMEND_AXIS(axis) \ ((axis) = (axis) == 0 ? 1 : (axis) == 255 ? 254 : (axis)) -void jiangtun_emend_axis(jiangtun_report_mode3_t *report) { +void jiangtun_report_emend_axis(jiangtun_report_mode3_t *report) { assert(report != NULL); EMEND_AXIS(report->xAxis); diff --git a/lib/jiangtun-core/test/arduino.c b/lib/jiangtun-core/test/arduino.c index 5fe873c..4392ab1 100644 --- a/lib/jiangtun-core/test/arduino.c +++ b/lib/jiangtun-core/test/arduino.c @@ -3,29 +3,36 @@ #include #include -static jiangtun_bool_t serial_read(jiangtun_board_t *board, +static jiangtun_bool_t serial_getc(jiangtun_board_t *board, jiangtun_uint8_t *c) { assert(board != NULL); assert(c != NULL); - fprintf(stderr, "serial_read\n"); + fprintf(stderr, "serial_getc\n"); /* *c = '@'; */ return JIANGTUN_FALSE; } -static void gamecube_send(jiangtun_board_t *board, - jiangtun_report_mode3_t *report) { +static void serial_puts(jiangtun_board_t *board, const char *s) { + assert(board != NULL); + assert(s != NULL); + + fputs(s, stderr); +} + +static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, + jiangtun_report_mode3_t *report) { assert(board != NULL); assert(report != NULL); fprintf(stderr, "gamecube_send\n"); + return JIANGTUN_FALSE; } -static void led_blink_async(jiangtun_board_t *board, - jiangtun_uint32_t duration) { +static void led_set(jiangtun_board_t *board, jiangtun_bool_t state) { assert(board != NULL); - fprintf(stderr, "led_blink_async: %u\n", duration); + fprintf(stderr, "led_set: %u\n", state); } int main(void) { @@ -36,11 +43,10 @@ int main(void) { JIANGTUN_FEATURE_ENABLE_LED_BLINK | JIANGTUN_FEATURE_ENABLE_NXMC2 | JIANGTUN_FEATURE_ENABLE_POKECON | JIANGTUN_FEATURE_ENABLE_ORCA; - /* setup */ - jiangtun_board_init(&board, serial_read, gamecube_send, led_blink_async); - jiangtun_init(&j, &board, features); + jiangtun_board_init(&board, serial_getc, serial_puts, gamecube_send, + led_set); + jiangtun_init(&j, &board, features, JIANGTUN_LOG_LEVEL_DEBUG); - /* loop */ for (i = 0; i < 5; i++) { jiangtun_loop(&j); } diff --git a/lib/jiangtun-core/test/command.c b/lib/jiangtun-core/test/command.c index 64e7e06..d6e0278 100644 --- a/lib/jiangtun-core/test/command.c +++ b/lib/jiangtun-core/test/command.c @@ -279,22 +279,22 @@ int test(void) { } for (j = 0; j < test_case->length; j++) { - jiangtun_push(command, test_case->buffer[j]); + jiangtun_command_push(command, test_case->buffer[j]); } switch (test_case->expected) { case TEST_PENDING: - TEST_ASSERT(jiangtun_pending(command)); + TEST_ASSERT(jiangtun_command_pending(command)); break; case TEST_ACCEPTED: - TEST_ASSERT(jiangtun_accepted(command)); - TEST_ASSERT(jiangtun_run(command, &report)); + TEST_ASSERT(jiangtun_command_accepted(command)); + TEST_ASSERT(jiangtun_command_run(command, &report)); if (test_case->expected_report != NULL) { TEST_COMPARE(test_case->expected_report, &(report)); } break; case TEST_REJECTED: - TEST_ASSERT(jiangtun_rejected(command)); + TEST_ASSERT(jiangtun_command_rejected(command)); break; default: assert(0); diff --git a/src/jiangtun.h b/src/jiangtun.h deleted file mode 100644 index d9d0034..0000000 --- a/src/jiangtun.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef JIANGTUN_H_ -#define JIANGTUN_H_ - -#include - -#include - -#include "Bluewhale.h" -#include "nthaka.h" - -namespace jiangtun -{ - - enum class ResetAction - { - Press, - Release, - PressRelease, - Nothing - }; - - struct State - { - Gamecube_Data_t gc_data; - nthaka_button_state_t gc_reset; - - ResetAction next_action; - - uint16_t hue; - uint32_t color; - }; - -} - -#endif // JIANGTUN_H_ \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b8c021e..b9d3685 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,409 +3,169 @@ #include -#include "pico/mutex.h" -#include "hardware/timer.h" - -#include "Bluewhale.h" - -#include "nthaka.h" -#include "nthaka/dol.h" -#include "nthaka/nxmc2.h" -#include "nthaka/orca.h" -#include "nthaka/pokecon.h" - -#include "jiangtun.h" - -#ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 - -#define PIN_RESET D10 -#define PIN_SERVO D6 -#define PIN_GAMECUBE D5 - -static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); -#define initLED() \ - do \ - { \ - pinMode(PIN_LED_R, OUTPUT); \ - pinMode(PIN_LED_G, OUTPUT); \ - pinMode(PIN_LED_B, OUTPUT); \ - digitalWrite(PIN_LED_R, HIGH); \ - digitalWrite(PIN_LED_G, HIGH); \ - digitalWrite(PIN_LED_B, HIGH); \ - pixels.begin(); \ - pinMode(NEOPIXEL_POWER, OUTPUT); \ - digitalWrite(NEOPIXEL_POWER, HIGH); \ - } while (0) -#define turnOnLED(color) \ - do \ - { \ - pixels.setPixelColor(0, (color)); \ - pixels.show(); \ - } while (0) -#define turnOffLED() \ - do \ - { \ - pixels.clear(); \ - pixels.show(); \ - } while (0) - -#else // JIANGTUN_CONFIG_BOARD_PICO - -#define PIN_RESET 3 -#define PIN_SERVO 6 -#define PIN_GAMECUBE 5 - -#define initLED() \ - do \ - { \ - pinMode(LED_BUILTIN, OUTPUT); \ - digitalWrite(LED_BUILTIN, LOW); \ - } while (0) -#define turnOnLED(_) (digitalWrite(LED_BUILTIN, HIGH)) -#define turnOffLED() (digitalWrite(LED_BUILTIN, LOW)) - -#endif - -static mutex_t mtx; -jiangtun::State state{.gc_data = defaultGamecubeData, - .gc_reset = NTHAKA_BUTTON_RELEASED, - .next_action = jiangtun::ResetAction::Nothing, - .hue = 0, - .color = Adafruit_NeoPixel::ColorHSV(0)}; - -/************************************************************************* - ** ** - ** .oooo. ** - ** d8P'`Y8b ** - ** .ooooo. .ooooo. oooo d8b .ooooo. 888 888 ** - ** d88' `"Y8 d88' `88b `888""8P d88' `88b 888 888 ** - ** 888 888 888 888 888ooo888 888 888 ** - ** 888 .o8 888 888 888 888 .o `88b d88' ** - ** `Y8bod8P' `Y8bod8P' d888b `Y8bod8P' `Y8bd8P' ** - ** ** - ** ** - ** ** - *************************************************************************/ -// figlet -t -f roman core0 - -static dol_format_handler_t dol; -static nxmc2_format_handler_t nxmc2; -static orca_format_handler_t orca; -static pokecon_format_handler_t pokecon; -static nthaka_format_handler_t *fmts[] = {(nthaka_format_handler_t *)&nxmc2, - (nthaka_format_handler_t *)&orca, -#ifdef JIANGTUN_CONFIG_ENABLE_DOL - (nthaka_format_handler_t *)&dol -#else - (nthaka_format_handler_t *)&pokecon -#endif // JIANGTUN_CONFIG_ENABLE_DOL -}; -static size_t auto_reset_release_idx[] = {1, -#ifdef JIANGTUN_CONFIG_ENABLE_DOL - 2 -#endif // JIANGTUN_CONFIG_ENABLE_DOL -}; -static size_t auto_reset_release_idx_size = sizeof(auto_reset_release_idx) / sizeof(auto_reset_release_idx[0]); -static nthaka_multi_format_handler_t fmt; -static nthaka_buffer_t buf; - -static int64_t _turnOffLED(alarm_id_t _0, void *_1) -{ - turnOffLED(); - return 0; -} - -static inline void blinkLEDAsync() -{ - turnOnLED(state.color); - add_alarm_in_ms(100, _turnOffLED, nullptr, false); -} - -static void updateState(nthaka_gamepad_state_t &gamepad, size_t idx) -{ - // Update the reset state and determine the next reset action. - nthaka_button_state_t next_reset_state = gamepad.home; - if (state.gc_reset != next_reset_state) - { - if (next_reset_state == NTHAKA_BUTTON_PRESSED) - { - state.next_action = jiangtun::ResetAction::Press; - - for (size_t i = 0; i < auto_reset_release_idx_size; i++) - { - if (auto_reset_release_idx[i] == idx) - { - state.next_action = jiangtun::ResetAction::PressRelease; - break; - } +#include +#include + +// #ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 + +// #define PIN_RESET D10 +// #define PIN_SERVO D6 +// #define PIN_GAMECUBE D5 + +// static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); +// #define initLED() \ +// do { \ +// pinMode(PIN_LED_R, OUTPUT); \ +// pinMode(PIN_LED_G, OUTPUT); \ +// pinMode(PIN_LED_B, OUTPUT); \ +// digitalWrite(PIN_LED_R, HIGH); \ +// digitalWrite(PIN_LED_G, HIGH); \ +// digitalWrite(PIN_LED_B, HIGH); \ +// pixels.begin(); \ +// pinMode(NEOPIXEL_POWER, OUTPUT); \ +// digitalWrite(NEOPIXEL_POWER, HIGH); \ +// } while (0) +// #define turnOnLED(color) \ +// do { \ +// pixels.setPixelColor(0, (color)); \ +// pixels.show(); \ +// } while (0) +// #define turnOffLED() \ +// do { \ +// pixels.clear(); \ +// pixels.show(); \ +// } while (0) + +// #else // JIANGTUN_CONFIG_BOARD_PICO + +// #define PIN_RESET 3 +// #define PIN_SERVO 6 +// #define PIN_GAMECUBE 5 + +typedef struct jiangtun_board_rp2040_t { + jiangtun_board_t base; + + Stream *serial; + CGamecubeConsole *gamecube; + Gamecube_Data_t gamecube_data; + Servo servo; + pin_size_t reset; + bool reset_data; +} jiangtun_board_rp2040_t; + +static void jiangtun_board_rp2040_init(jiangtun_board_rp2040_t *board, + Stream *serial, + CGamecubeConsole *gamecube, + pin_size_t servo, pin_size_t reset) { + assert(board != NULL); + assert(serial != NULL); + assert(gamecube != NULL); + + board->serial = serial; + board->gamecube = gamecube; + board->gamecube_data = defaultGamecubeData; + board->servo.attach(servo, 500, 2400); + board->reset = reset; + board->reset_data = true; // to ensure initial releasing + + jiangtun_board_init( + &(board->base), + [](jiangtun_board_t *base, unsigned char *c) -> jiangtun_bool_t { + jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; + int c_ = 0; + assert(board != NULL); + assert(c != NULL); + + if (board->serial->available() <= 0) { + return JIANGTUN_FALSE; + } + c_ = board->serial->read(); + if (c_ < 0 || 255 < c_) { + return JIANGTUN_FALSE; + } + *c = c_ & 0xFF; + return JIANGTUN_TRUE; + }, + [](jiangtun_board_t *base, const char *s) { + jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; + assert(board != NULL); + assert(s != NULL); + + board->serial->print(s); + }, + [](jiangtun_board_t *base, + jiangtun_report_mode3_t *report) -> jiangtun_bool_t { + jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; + assert(board != NULL); + assert(report != NULL); + + board->gamecube_data.report.a = report->a ? 1 : 0; + board->gamecube_data.report.b = report->b ? 1 : 0; + board->gamecube_data.report.x = report->x ? 1 : 0; + board->gamecube_data.report.y = report->y ? 1 : 0; + board->gamecube_data.report.start = report->start ? 1 : 0; + board->gamecube_data.report.dleft = report->dleft ? 1 : 0; + board->gamecube_data.report.dright = report->dright ? 1 : 0; + board->gamecube_data.report.ddown = report->ddown ? 1 : 0; + board->gamecube_data.report.dup = report->dup ? 1 : 0; + board->gamecube_data.report.z = report->z ? 1 : 0; + board->gamecube_data.report.r = report->r ? 1 : 0; + board->gamecube_data.report.l = report->l ? 1 : 0; + board->gamecube_data.report.xAxis = (uint8_t)report->xAxis; + board->gamecube_data.report.yAxis = (uint8_t)report->yAxis; + board->gamecube_data.report.cxAxis = (uint8_t)report->cxAxis; + board->gamecube_data.report.cyAxis = (uint8_t)report->cyAxis; + board->gamecube_data.report.left = (uint8_t)report->left; + board->gamecube_data.report.right = (uint8_t)report->right; + + if (!(board->reset_data) && report->reset) { + board->servo.write(65); + pinMode(board->reset, OUTPUT); + digitalWrite(board->reset, LOW); + board->reset_data = true; + + } else if (board->reset_data && !(report->reset)) { + board->servo.write(90); + pinMode(board->reset, INPUT); + board->reset_data = false; } - } - else - { - state.next_action = jiangtun::ResetAction::Release; - } - state.gc_reset = next_reset_state; - } - else - { - state.next_action = jiangtun::ResetAction::Nothing; - } - - // Convert nthaka_gamepad_state_t to Gamecube_Data_t - state.gc_data.report.y = gamepad.y == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.b = gamepad.b == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.a = gamepad.a == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.x = gamepad.x == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.l = gamepad.l == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.r = gamepad.r == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.z = gamepad.zr == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - state.gc_data.report.start = gamepad.plus == NTHAKA_BUTTON_PRESSED ? 1U : 0U; - - switch (gamepad.hat) - { - case NTHAKA_HAT_UP: - state.gc_data.report.dup = 1U; - state.gc_data.report.dright = 0U; - state.gc_data.report.ddown = 0U; - state.gc_data.report.dleft = 0U; - break; - - case NTHAKA_HAT_UPRIGHT: - state.gc_data.report.dup = 1U; - state.gc_data.report.dright = 1U; - state.gc_data.report.ddown = 0U; - state.gc_data.report.dleft = 0U; - break; - - case NTHAKA_HAT_RIGHT: - state.gc_data.report.dup = 0U; - state.gc_data.report.dright = 1U; - state.gc_data.report.ddown = 0U; - state.gc_data.report.dleft = 0U; - break; - - case NTHAKA_HAT_DOWNRIGHT: - state.gc_data.report.dup = 0U; - state.gc_data.report.dright = 1U; - state.gc_data.report.ddown = 1U; - state.gc_data.report.dleft = 0U; - break; - - case NTHAKA_HAT_DOWN: - state.gc_data.report.dup = 0U; - state.gc_data.report.dright = 0U; - state.gc_data.report.ddown = 1U; - state.gc_data.report.dleft = 0U; - break; - - case NTHAKA_HAT_DOWNLEFT: - state.gc_data.report.dup = 0U; - state.gc_data.report.dright = 0U; - state.gc_data.report.ddown = 1U; - state.gc_data.report.dleft = 1U; - break; - - case NTHAKA_HAT_LEFT: - state.gc_data.report.dup = 0U; - state.gc_data.report.dright = 0U; - state.gc_data.report.ddown = 0U; - state.gc_data.report.dleft = 1U; - break; - - case NTHAKA_HAT_UPLEFT: - state.gc_data.report.dup = 1U; - state.gc_data.report.dright = 0U; - state.gc_data.report.ddown = 0U; - state.gc_data.report.dleft = 1U; - break; - - case NTHAKA_HAT_NEUTRAL: - default: - state.gc_data.report.dup = 0U; - state.gc_data.report.dright = 0U; - state.gc_data.report.ddown = 0U; - state.gc_data.report.dleft = 0U; - break; - } - - // There are a few games that do not handle yAxis=0 and cyAxis=0 correctly. - state.gc_data.report.xAxis = gamepad.l_stick.x; - uint8_t y_axis = 0xFF - gamepad.l_stick.y; - state.gc_data.report.yAxis = y_axis == 0U ? 1U : y_axis; - - state.gc_data.report.cxAxis = gamepad.r_stick.x; - uint8_t cy_axis = 0xFF - gamepad.r_stick.y; - state.gc_data.report.cyAxis = cy_axis == 0U ? 1U : cy_axis; -} - -void setup() -{ - mutex_init(&mtx); - - Serial.setTimeout(100); - Serial.begin(9600); - - initLED(); - dol_format_handler_init(&dol); - nxmc2_format_handler_init(&nxmc2); - orca_format_handler_init(&orca); - pokecon_format_handler_init(&pokecon); - nthaka_multi_format_handler_init(&fmt, fmts, 3); - nthaka_buffer_init(&buf, (nthaka_format_handler_t *)&fmt); + return board->gamecube->write(board->gamecube_data) + ? JIANGTUN_TRUE + : JIANGTUN_FALSE; + }, + [](jiangtun_board_t *base, jiangtun_bool_t state) { + jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; + assert(board != NULL); + }); } -void loop() -{ - static nthaka_gamepad_state_t out; - - uint8_t in; - nthaka_buffer_state_t s; - if (Serial.readBytes(&in, 1) != 1 || - (s = nthaka_buffer_append(&buf, in, &out)) == NTHAKA_BUFFER_REJECTED) - { - nthaka_buffer_clear(&buf); - return; - } - else if (s == NTHAKA_BUFFER_PENDING) - { - return; - } +static const pin_size_t PIN_GAMECUBE = 7; // D5 (SCL) +static const pin_size_t PIN_SERVO = 0; // D6 (TX) +static const pin_size_t PIN_RESET = 3; // D10 (MOSI) - size_t *idx_ = nthaka_multi_format_handler_get_last_deserialized_index(&fmt); - size_t idx = idx_ != nullptr ? *idx_ : 0; +static const pin_size_t PIN_NEOPIXEL = 12; +static const pin_size_t PIN_NEOPIXEL_POWER = 11; +static const pin_size_t PIN_LED_R = 17; +static const pin_size_t PIN_LED_G = 16; +static const pin_size_t PIN_LED_B = 25; - mutex_enter_blocking(&mtx); - { - blinkLEDAsync(); - updateState(out, idx); - } - mutex_exit(&mtx); - - nthaka_buffer_clear(&buf); -} - -/************************************************************************* - ** ** - ** .o ** - ** o888 ** - ** .ooooo. .ooooo. oooo d8b .ooooo. 888 ** - ** d88' `"Y8 d88' `88b `888""8P d88' `88b 888 ** - ** 888 888 888 888 888ooo888 888 ** - ** 888 .o8 888 888 888 888 .o 888 ** - ** `Y8bod8P' `Y8bod8P' d888b `Y8bod8P' o888o ** - ** ** - ** ** - ** ** - *************************************************************************/ -// figlet -t -f roman core1 +static const pin_size_t PIN_LED_BUILTIN = 25; static CGamecubeConsole gamecube(PIN_GAMECUBE); - -static Servo servo; - -static void initGamecube(CGamecubeConsole &console, jiangtun::State &state) -{ - state.gc_data.report.a = 0; - state.gc_data.report.b = 0; - state.gc_data.report.x = 0; - state.gc_data.report.y = 0; - state.gc_data.report.start = 0; - state.gc_data.report.dleft = 0; - state.gc_data.report.dright = 0; - state.gc_data.report.ddown = 0; - state.gc_data.report.dup = 0; - state.gc_data.report.z = 0; - state.gc_data.report.r = 0; - state.gc_data.report.l = 0; - state.gc_data.report.xAxis = 128; - state.gc_data.report.yAxis = 128; - state.gc_data.report.cxAxis = 128; - state.gc_data.report.cyAxis = 128; - state.gc_data.report.left = 0; - state.gc_data.report.right = 0; - - // Magic spell to make the controller be recognized by the Gamecube - state.gc_data.report.start = 1; - console.write(state.gc_data); - state.gc_data.report.start = 0; - console.write(state.gc_data); -} - -static inline void pressReset() -{ - servo.write(65); - pinMode(PIN_RESET, OUTPUT); - digitalWrite(PIN_RESET, LOW); -} - -static inline int64_t releaseReset(alarm_id_t _0, void *_1) -{ - servo.write(90); - pinMode(PIN_RESET, INPUT); - - if (state.gc_reset != NTHAKA_BUTTON_RELEASED) - { - mutex_enter_blocking(&mtx); - { - state.gc_reset = NTHAKA_BUTTON_RELEASED; - blinkLEDAsync(); - } - mutex_exit(&mtx); - } - - return 0; +static jiangtun_board_rp2040_t board; + +static jiangtun_t j; + +void setup() { + Serial.begin(115200); + jiangtun_board_rp2040_init(&board, &Serial, &gamecube, PIN_SERVO, + PIN_RESET); + jiangtun_init( + &j, &(board.base), + JIANGTUN_FEATURE_ENABLE_LED_BLINK | JIANGTUN_FEATURE_ENABLE_NXMC2 | + JIANGTUN_FEATURE_ENABLE_POKECON | JIANGTUN_FEATURE_ENABLE_ORCA, + JIANGTUN_LOG_LEVEL_DEBUG); } -void setup1() -{ - // Wait `mutex_init(&mtx);` - delay(10); - - mutex_enter_blocking(&mtx); - { - initGamecube(gamecube, state); - } - mutex_exit(&mtx); - - servo.attach(PIN_SERVO, 500, 2400); - pinMode(PIN_RESET, INPUT); - releaseReset(0, nullptr); -} - -void loop1() -{ - bool ret; - - mutex_enter_blocking(&mtx); - { - // This would be a useless calculation for JIANGTUN_CONFIG_BOARD_PICO, - // but it is intentionally left out to avoid making a difference in processing time. - state.color = Adafruit_NeoPixel::ColorHSV(state.hue); - state.hue += 16; - - ret = gamecube.write(state.gc_data); - - switch (state.next_action) - { - case jiangtun::ResetAction::Press: - pressReset(); - break; - - case jiangtun::ResetAction::Release: - releaseReset(0, nullptr); - break; - - case jiangtun::ResetAction::PressRelease: - pressReset(); - add_alarm_in_ms(500, releaseReset, nullptr, false); - break; - - case jiangtun::ResetAction::Nothing: - default: - break; - } - state.next_action = jiangtun::ResetAction::Nothing; - } - mutex_exit(&mtx); -} \ No newline at end of file +void loop() { jiangtun_loop(&j); } From 50684a41ab2a738ed7a07139cbee40bcbde64649 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sun, 13 Oct 2024 17:15:43 +0900 Subject: [PATCH 16/25] wip: main.cpp --- lib/jiangtun-core/include/jiangtun.h | 8 +- lib/jiangtun-core/library.properties | 3 +- lib/jiangtun-core/src/jiangtun.c | 52 ++--- platformio.ini | 52 +---- src/main.cpp | 290 ++++++++++++++------------- 5 files changed, 176 insertions(+), 229 deletions(-) diff --git a/lib/jiangtun-core/include/jiangtun.h b/lib/jiangtun-core/include/jiangtun.h index 6c74c1e..b22b24f 100644 --- a/lib/jiangtun-core/include/jiangtun.h +++ b/lib/jiangtun-core/include/jiangtun.h @@ -12,10 +12,10 @@ extern "C" { #endif #ifndef JIANGTUN_MICROSECONDS_PER_LOOP -#define JIANGTUN_MICROSECONDS_PER_LOOP 0.54 -#endif /* JIANGTUN_MICROSECONDS_PER_LOOP */ +#define JIANGTUN_MICROSECONDS_PER_LOOP 2500 +#endif #define JIANGTUN_LOOPS_FOR_MILLISECONDS(ms) \ - ((jiangtun_uint32_t)((1000 * (ms)) / JIANGTUN_MICROSECONDS_PER_LOOP) + 1) + ((jiangtun_uint32_t)((ms) * 1000 / JIANGTUN_MICROSECONDS_PER_LOOP) + 1) #define JIANGTUN_LOOPS_FOR_TIMEOUT JIANGTUN_LOOPS_FOR_MILLISECONDS(5) #define JIANGTUN_LOOPS_FOR_LED JIANGTUN_LOOPS_FOR_MILLISECONDS(100) #define JIANGTUN_LOOPS_FOR_RESET_BLOCKING JIANGTUN_LOOPS_FOR_MILLISECONDS(500) @@ -69,6 +69,8 @@ typedef struct jiangtun_t { jiangtun_uint32_t reset_blocking_loop; jiangtun_log_level_t log_level; + + char buffer[128]; char log_buffer[128]; } jiangtun_t; diff --git a/lib/jiangtun-core/library.properties b/lib/jiangtun-core/library.properties index 4b72d9c..2ef39ff 100644 --- a/lib/jiangtun-core/library.properties +++ b/lib/jiangtun-core/library.properties @@ -5,6 +5,5 @@ maintainer=Koutaro Mukai sentence=The core library of Jiangtun. paragraph=The core library of Jiangtun. category=Other -url=https://github.com/U-1F992/jiangtun +url=https://github.com/u1f992/jiangtun architectures=* -depends=Bluewhale (=1.0.3) diff --git a/lib/jiangtun-core/src/jiangtun.c b/lib/jiangtun-core/src/jiangtun.c index c893c6b..4c9cdfd 100644 --- a/lib/jiangtun-core/src/jiangtun.c +++ b/lib/jiangtun-core/src/jiangtun.c @@ -3,30 +3,16 @@ #include #include -#define UNIX_EPOCH "1970-01-01T00:00:00Z" - static void serial_log(jiangtun_t *j, jiangtun_log_level_t level, const char *s) { - char time_string[sizeof(UNIX_EPOCH)]; - time_t now = time(NULL); - struct tm *tm_info = gmtime(&now); - - if (tm_info != NULL) { - strftime(time_string, sizeof(time_string), "%Y-%m-%dT%H:%M:%SZ", - tm_info); - } else { - sprintf(time_string, UNIX_EPOCH); - } - - sprintf(j->log_buffer, "[%s]\t[%s]\t%s\n", time_string, + sprintf(j->log_buffer, "[%s]\t%s\n", level == JIANGTUN_LOG_LEVEL_WARN ? "warn" : level == JIANGTUN_LOG_LEVEL_INFO ? "info" : level == JIANGTUN_LOG_LEVEL_DEBUG ? "debug" : "unknown", s); - if (j->log_level >= level) { - jiangtun_board_serial_puts(j->board, j->log_buffer); - } + jiangtun_board_serial_puts(j->board, + j->log_level >= level ? j->log_buffer : ""); } static void init_commands(jiangtun_t *j) { @@ -122,20 +108,19 @@ static void process_input(jiangtun_t *j) { assert(j != NULL); if (j->reset_blocking_loop > 0) { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking_loop active"); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking_loop"); return; } if (jiangtun_optional_uint8_get(&(j->carry_over), &c)) { - sprintf(j->log_buffer, "carry_over value used: %u", c); - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + sprintf(j->buffer, "carry_over value used: %u", c); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->buffer); } else if (jiangtun_board_serial_getc(j->board, &c)) { - sprintf(j->log_buffer, "received input: %u", c); - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + sprintf(j->buffer, "received input: %u", c); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->buffer); } else { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "no input received"); if (j->any_pending && --(j->timeout_loop) == 0) { serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "input timeout"); init_commands(j); @@ -149,8 +134,8 @@ static void process_input(jiangtun_t *j) { for (i = 0; i < 4; i++) { jiangtun_command_push(j->commands[i], c); if (jiangtun_command_accepted(j->commands[i])) { - sprintf(j->log_buffer, "command #%lu accepted", (unsigned long)i); - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + sprintf(j->buffer, "command #%lu accepted", (unsigned long)i); + serial_log(j, JIANGTUN_LOG_LEVEL_INFO, j->buffer); if (!jiangtun_command_run(j->commands[i], &(j->reports[i]))) { serial_log(j, JIANGTUN_LOG_LEVEL_WARN, @@ -158,9 +143,9 @@ static void process_input(jiangtun_t *j) { /* as rejected */ continue; } - sprintf(j->log_buffer, "command #%lu executed successfully", + sprintf(j->buffer, "command #%lu executed successfully", (unsigned long)i); - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + serial_log(j, JIANGTUN_LOG_LEVEL_INFO, j->buffer); j->recently_patched = &(j->reports[i]); jiangtun_board_led_set( @@ -179,8 +164,8 @@ static void process_input(jiangtun_t *j) { } } if (j->any_pending && all_rejected) { - sprintf(j->log_buffer, "all commands rejected, carry_over set: %u", c); - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->log_buffer); + sprintf(j->buffer, "all commands rejected, carry_over set: %u", c); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->buffer); jiangtun_optional_uint8_set(&(j->carry_over), c); init_commands(j); return; @@ -195,20 +180,17 @@ void jiangtun_loop(jiangtun_t *j) { if (j->reset_blocking_loop > 0 && --(j->reset_blocking_loop) == 0) { serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, - "reset_blocking_loop completed, reset flag cleared"); + "reset_blocking_loop completed"); j->recently_patched->reset = JIANGTUN_FALSE; } jiangtun_report_emend_axis(j->recently_patched); if (!jiangtun_board_gamecube_send(j->board, j->recently_patched)) { - serial_log(j, JIANGTUN_LOG_LEVEL_WARN, - "failed to send report: gamecube is either not powered on " - "or not connected"); + serial_log(j, JIANGTUN_LOG_LEVEL_WARN, "failed to send report"); } if (j->led_loop > 0 && --(j->led_loop) == 0) { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, - "led_loop completed, turning off"); + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "led_loop completed"); jiangtun_board_led_set(j->board, JIANGTUN_FALSE); } } \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index b6f91d5..aa2cddf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,56 +8,16 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c -board = pico +[env:rp2040] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5b72058658ebaf98045755662bc8b28479bd288b +board = generic framework = arduino board_build.core = earlephilhower lib_deps = - adafruit/Adafruit NeoPixel@^1.12.0 - https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 -build_flags = - -DNDEBUG - -DJIANGTUN_CONFIG_BOARD_PICO -debug_tool = cmsis-dap - -[env:dol-pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c -board = pico -framework = arduino -board_build.core = earlephilhower -lib_deps = - adafruit/Adafruit NeoPixel@^1.12.0 - https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 -build_flags = - -DNDEBUG - -DJIANGTUN_CONFIG_BOARD_PICO - -DJIANGTUN_CONFIG_ENABLE_DOL + adafruit/Adafruit NeoPixel@^1.12.3 + https://github.com/mizuyoukanao/Bluewhale.git#1.0.4 debug_tool = cmsis-dap -[env:xiao-rp2040] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c -board = seeed_xiao_rp2040 -framework = arduino -board_build.core = earlephilhower -lib_deps = - adafruit/Adafruit NeoPixel@^1.12.0 - https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 -build_flags = - -DNDEBUG - -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 -debug_tool = cmsis-dap - -[env:dol-xiao-rp2040] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c -board = seeed_xiao_rp2040 -framework = arduino -board_build.core = earlephilhower -lib_deps = - adafruit/Adafruit NeoPixel@^1.12.0 - https://github.com/mizuyoukanao/Bluewhale.git#1.0.3 +[env:rp2040-release] build_flags = -DNDEBUG - -DJIANGTUN_CONFIG_BOARD_XIAO_RP2040 - -DJIANGTUN_CONFIG_ENABLE_DOL -debug_tool = cmsis-dap \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b9d3685..fdbe387 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,140 +6,6 @@ #include #include -// #ifdef JIANGTUN_CONFIG_BOARD_XIAO_RP2040 - -// #define PIN_RESET D10 -// #define PIN_SERVO D6 -// #define PIN_GAMECUBE D5 - -// static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); -// #define initLED() \ -// do { \ -// pinMode(PIN_LED_R, OUTPUT); \ -// pinMode(PIN_LED_G, OUTPUT); \ -// pinMode(PIN_LED_B, OUTPUT); \ -// digitalWrite(PIN_LED_R, HIGH); \ -// digitalWrite(PIN_LED_G, HIGH); \ -// digitalWrite(PIN_LED_B, HIGH); \ -// pixels.begin(); \ -// pinMode(NEOPIXEL_POWER, OUTPUT); \ -// digitalWrite(NEOPIXEL_POWER, HIGH); \ -// } while (0) -// #define turnOnLED(color) \ -// do { \ -// pixels.setPixelColor(0, (color)); \ -// pixels.show(); \ -// } while (0) -// #define turnOffLED() \ -// do { \ -// pixels.clear(); \ -// pixels.show(); \ -// } while (0) - -// #else // JIANGTUN_CONFIG_BOARD_PICO - -// #define PIN_RESET 3 -// #define PIN_SERVO 6 -// #define PIN_GAMECUBE 5 - -typedef struct jiangtun_board_rp2040_t { - jiangtun_board_t base; - - Stream *serial; - CGamecubeConsole *gamecube; - Gamecube_Data_t gamecube_data; - Servo servo; - pin_size_t reset; - bool reset_data; -} jiangtun_board_rp2040_t; - -static void jiangtun_board_rp2040_init(jiangtun_board_rp2040_t *board, - Stream *serial, - CGamecubeConsole *gamecube, - pin_size_t servo, pin_size_t reset) { - assert(board != NULL); - assert(serial != NULL); - assert(gamecube != NULL); - - board->serial = serial; - board->gamecube = gamecube; - board->gamecube_data = defaultGamecubeData; - board->servo.attach(servo, 500, 2400); - board->reset = reset; - board->reset_data = true; // to ensure initial releasing - - jiangtun_board_init( - &(board->base), - [](jiangtun_board_t *base, unsigned char *c) -> jiangtun_bool_t { - jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; - int c_ = 0; - assert(board != NULL); - assert(c != NULL); - - if (board->serial->available() <= 0) { - return JIANGTUN_FALSE; - } - c_ = board->serial->read(); - if (c_ < 0 || 255 < c_) { - return JIANGTUN_FALSE; - } - *c = c_ & 0xFF; - return JIANGTUN_TRUE; - }, - [](jiangtun_board_t *base, const char *s) { - jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; - assert(board != NULL); - assert(s != NULL); - - board->serial->print(s); - }, - [](jiangtun_board_t *base, - jiangtun_report_mode3_t *report) -> jiangtun_bool_t { - jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; - assert(board != NULL); - assert(report != NULL); - - board->gamecube_data.report.a = report->a ? 1 : 0; - board->gamecube_data.report.b = report->b ? 1 : 0; - board->gamecube_data.report.x = report->x ? 1 : 0; - board->gamecube_data.report.y = report->y ? 1 : 0; - board->gamecube_data.report.start = report->start ? 1 : 0; - board->gamecube_data.report.dleft = report->dleft ? 1 : 0; - board->gamecube_data.report.dright = report->dright ? 1 : 0; - board->gamecube_data.report.ddown = report->ddown ? 1 : 0; - board->gamecube_data.report.dup = report->dup ? 1 : 0; - board->gamecube_data.report.z = report->z ? 1 : 0; - board->gamecube_data.report.r = report->r ? 1 : 0; - board->gamecube_data.report.l = report->l ? 1 : 0; - board->gamecube_data.report.xAxis = (uint8_t)report->xAxis; - board->gamecube_data.report.yAxis = (uint8_t)report->yAxis; - board->gamecube_data.report.cxAxis = (uint8_t)report->cxAxis; - board->gamecube_data.report.cyAxis = (uint8_t)report->cyAxis; - board->gamecube_data.report.left = (uint8_t)report->left; - board->gamecube_data.report.right = (uint8_t)report->right; - - if (!(board->reset_data) && report->reset) { - board->servo.write(65); - pinMode(board->reset, OUTPUT); - digitalWrite(board->reset, LOW); - board->reset_data = true; - - } else if (board->reset_data && !(report->reset)) { - board->servo.write(90); - pinMode(board->reset, INPUT); - board->reset_data = false; - } - - return board->gamecube->write(board->gamecube_data) - ? JIANGTUN_TRUE - : JIANGTUN_FALSE; - }, - [](jiangtun_board_t *base, jiangtun_bool_t state) { - jiangtun_board_rp2040_t *board = (jiangtun_board_rp2040_t *)base; - assert(board != NULL); - }); -} - static const pin_size_t PIN_GAMECUBE = 7; // D5 (SCL) static const pin_size_t PIN_SERVO = 0; // D6 (TX) static const pin_size_t PIN_RESET = 3; // D10 (MOSI) @@ -148,24 +14,162 @@ static const pin_size_t PIN_NEOPIXEL = 12; static const pin_size_t PIN_NEOPIXEL_POWER = 11; static const pin_size_t PIN_LED_R = 17; static const pin_size_t PIN_LED_G = 16; -static const pin_size_t PIN_LED_B = 25; - -static const pin_size_t PIN_LED_BUILTIN = 25; +static const pin_size_t PIN_LED_B_BUILTIN = 25; static CGamecubeConsole gamecube(PIN_GAMECUBE); -static jiangtun_board_rp2040_t board; - +static Servo servo; +static Gamecube_Data_t gamecube_data = defaultGamecubeData; +static bool gamecube_data_reset = false; +static mutex_t gamecube_data_mtx; +static bool current_reset_state = true; // to ensure initial releasing + +static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); +static jiangtun_board_t board; static jiangtun_t j; +static jiangtun_bool_t +jiangtun_board_rp2040_serial_getc(jiangtun_board_t *board, unsigned char *c) { + int c_ = 0; + assert(board != NULL); + assert(c != NULL); + + if (Serial.available() <= 0) { + return JIANGTUN_FALSE; + } + c_ = Serial.read(); + if (c_ < 0 || 255 < c_) { + return JIANGTUN_FALSE; + } + *c = c_ & 0xFF; + return JIANGTUN_TRUE; +} + +static void jiangtun_board_rp2040_serial_puts(jiangtun_board_t *board, + const char *s) { + assert(board != NULL); + assert(s != NULL); + + Serial.print(s); +} + +static jiangtun_bool_t +jiangtun_board_rp2040_gamecube_send(jiangtun_board_t *board, + jiangtun_report_mode3_t *report) { + assert(board != NULL); + assert(report != NULL); + + mutex_enter_blocking(&gamecube_data_mtx); + gamecube_data.report.a = report->a ? 1 : 0; + gamecube_data.report.b = report->b ? 1 : 0; + gamecube_data.report.x = report->x ? 1 : 0; + gamecube_data.report.y = report->y ? 1 : 0; + gamecube_data.report.start = report->start ? 1 : 0; + gamecube_data.report.dleft = report->dleft ? 1 : 0; + gamecube_data.report.dright = report->dright ? 1 : 0; + gamecube_data.report.ddown = report->ddown ? 1 : 0; + gamecube_data.report.dup = report->dup ? 1 : 0; + gamecube_data.report.z = report->z ? 1 : 0; + gamecube_data.report.r = report->r ? 1 : 0; + gamecube_data.report.l = report->l ? 1 : 0; + gamecube_data.report.xAxis = (uint8_t)report->xAxis; + gamecube_data.report.yAxis = (uint8_t)report->yAxis; + gamecube_data.report.cxAxis = (uint8_t)report->cxAxis; + gamecube_data.report.cyAxis = (uint8_t)report->cyAxis; + gamecube_data.report.left = (uint8_t)report->left; + gamecube_data.report.right = (uint8_t)report->right; + + gamecube_data_reset = report->reset ? true : false; + mutex_exit(&gamecube_data_mtx); + + return JIANGTUN_TRUE; +} + +static void jiangtun_board_rp2040_led_set(jiangtun_board_t *board, + jiangtun_bool_t state) { + assert(board != NULL); + + digitalWrite(PIN_LED_B_BUILTIN, state ? HIGH : LOW); + if (state) { + uint16_t hue = (millis() % 2000) * (65535 / 2000); + pixels.setPixelColor(0, Adafruit_NeoPixel::ColorHSV(hue)); + } else { + pixels.clear(); + } + pixels.show(); + +#ifndef NDEBUG + // Calibrate `JIANGTUN_MICROSECONDS_PER_LOOP` + // to make this duration approximately 100 ms. + static unsigned long led_on = 0; + if (state) { + led_on = micros(); + } else { + char buffer[128]; + sprintf(buffer, "led_on duration: %lu\n", micros() - led_on); + Serial.print(buffer); + } +#endif +} + void setup() { Serial.begin(115200); - jiangtun_board_rp2040_init(&board, &Serial, &gamecube, PIN_SERVO, - PIN_RESET); + + pinMode(PIN_LED_R, OUTPUT); + pinMode(PIN_LED_G, OUTPUT); + // pinMode(PIN_LED_B_BUILTIN, OUTPUT); + digitalWrite(PIN_LED_R, HIGH); + digitalWrite(PIN_LED_G, HIGH); + // digitalWrite(PIN_LED_B_BUILTIN, HIGH); + + pinMode(PIN_NEOPIXEL_POWER, OUTPUT); + digitalWrite(PIN_NEOPIXEL_POWER, HIGH); + pixels.begin(); + + pinMode(PIN_LED_B_BUILTIN, OUTPUT); + digitalWrite(PIN_LED_B_BUILTIN, LOW); + + jiangtun_board_init(&board, jiangtun_board_rp2040_serial_getc, + jiangtun_board_rp2040_serial_puts, + jiangtun_board_rp2040_gamecube_send, + jiangtun_board_rp2040_led_set); + mutex_init(&gamecube_data_mtx); jiangtun_init( - &j, &(board.base), + &j, &board, JIANGTUN_FEATURE_ENABLE_LED_BLINK | JIANGTUN_FEATURE_ENABLE_NXMC2 | JIANGTUN_FEATURE_ENABLE_POKECON | JIANGTUN_FEATURE_ENABLE_ORCA, - JIANGTUN_LOG_LEVEL_DEBUG); +#ifndef NDEBUG + JIANGTUN_LOG_LEVEL_DEBUG +#else + JIANGTUN_LOG_LEVEL_INFO +#endif + ); } void loop() { jiangtun_loop(&j); } + +void setup1() { + servo.attach(PIN_SERVO, 500, 2400); + while (!mutex_is_initialized(&gamecube_data_mtx)) + ; +} + +void loop1() { + mutex_enter_blocking(&gamecube_data_mtx); + bool ret = gamecube.write(gamecube_data); + bool reset = gamecube_data_reset; + mutex_exit(&gamecube_data_mtx); + if (!ret) { + Serial.println("[core2]\tfailed to send report"); + } + if (!(current_reset_state) && reset) { + servo.write(65); + pinMode(PIN_RESET, OUTPUT); + digitalWrite(PIN_RESET, LOW); + current_reset_state = true; + + } else if (current_reset_state && !reset) { + servo.write(90); + pinMode(PIN_RESET, INPUT); + current_reset_state = true; + } +} \ No newline at end of file From 4764bed0e8cf1df71764150dc652d721a6976884 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 15:16:06 +0900 Subject: [PATCH 17/25] wip: main.cpp --- lib/jiangtun-core/include/jiangtun.h | 2 +- platformio.ini | 8 +++ src/main.cpp | 78 +++++++++++++++------------- 3 files changed, 52 insertions(+), 36 deletions(-) diff --git a/lib/jiangtun-core/include/jiangtun.h b/lib/jiangtun-core/include/jiangtun.h index b22b24f..33e45eb 100644 --- a/lib/jiangtun-core/include/jiangtun.h +++ b/lib/jiangtun-core/include/jiangtun.h @@ -12,7 +12,7 @@ extern "C" { #endif #ifndef JIANGTUN_MICROSECONDS_PER_LOOP -#define JIANGTUN_MICROSECONDS_PER_LOOP 2500 +#define JIANGTUN_MICROSECONDS_PER_LOOP 925 #endif #define JIANGTUN_LOOPS_FOR_MILLISECONDS(ms) \ ((jiangtun_uint32_t)((ms) * 1000 / JIANGTUN_MICROSECONDS_PER_LOOP) + 1) diff --git a/platformio.ini b/platformio.ini index aa2cddf..8f4e80b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,5 +19,13 @@ lib_deps = debug_tool = cmsis-dap [env:rp2040-release] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5b72058658ebaf98045755662bc8b28479bd288b +board = generic +framework = arduino +board_build.core = earlephilhower +lib_deps = + adafruit/Adafruit NeoPixel@^1.12.3 + https://github.com/mizuyoukanao/Bluewhale.git#1.0.4 +debug_tool = cmsis-dap build_flags = -DNDEBUG diff --git a/src/main.cpp b/src/main.cpp index fdbe387..eac6ad7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,11 +10,20 @@ static const pin_size_t PIN_GAMECUBE = 7; // D5 (SCL) static const pin_size_t PIN_SERVO = 0; // D6 (TX) static const pin_size_t PIN_RESET = 3; // D10 (MOSI) -static const pin_size_t PIN_NEOPIXEL = 12; -static const pin_size_t PIN_NEOPIXEL_POWER = 11; -static const pin_size_t PIN_LED_R = 17; -static const pin_size_t PIN_LED_G = 16; -static const pin_size_t PIN_LED_B_BUILTIN = 25; +static const pin_size_t PIN_XIAO_NEOPIXEL = 12; +static const pin_size_t PIN_XIAO_NEOPIXEL_POWER = 11; +static const pin_size_t PIN_XIAO_LED_R = 17; +static const pin_size_t PIN_XIAO_LED_G = 16; +/** + * GPIO25 is connected to the anode of the built-in LED on the Pico (lit + * when HIGH), and to the cathode of the blue channel of the RGB LED on the + * XIAO RP2040 (lit when LOW). + * This firmware prioritizes blinking the LED on the Pico, so on the XIAO + * RP2040, the blue LED will remain on and turn off when input is accepted. + * As a replacement on the XIAO RP2040, the NeoPixel, which is brighter than + * the RGB LED, will light up. + */ +static const pin_size_t PIN_XIAO_LED_B_PICO_LED_BUILTIN = 25; static CGamecubeConsole gamecube(PIN_GAMECUBE); static Servo servo; @@ -23,20 +32,19 @@ static bool gamecube_data_reset = false; static mutex_t gamecube_data_mtx; static bool current_reset_state = true; // to ensure initial releasing -static Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); +static Adafruit_NeoPixel pixels(1, PIN_XIAO_NEOPIXEL, NEO_GRB + NEO_KHZ800); static jiangtun_board_t board; static jiangtun_t j; static jiangtun_bool_t jiangtun_board_rp2040_serial_getc(jiangtun_board_t *board, unsigned char *c) { - int c_ = 0; assert(board != NULL); assert(c != NULL); if (Serial.available() <= 0) { return JIANGTUN_FALSE; } - c_ = Serial.read(); + int c_ = Serial.read(); if (c_ < 0 || 255 < c_) { return JIANGTUN_FALSE; } @@ -88,7 +96,7 @@ static void jiangtun_board_rp2040_led_set(jiangtun_board_t *board, jiangtun_bool_t state) { assert(board != NULL); - digitalWrite(PIN_LED_B_BUILTIN, state ? HIGH : LOW); + digitalWrite(PIN_XIAO_LED_B_PICO_LED_BUILTIN, state ? HIGH : LOW); if (state) { uint16_t hue = (millis() % 2000) * (65535 / 2000); pixels.setPixelColor(0, Adafruit_NeoPixel::ColorHSV(hue)); @@ -97,36 +105,38 @@ static void jiangtun_board_rp2040_led_set(jiangtun_board_t *board, } pixels.show(); -#ifndef NDEBUG - // Calibrate `JIANGTUN_MICROSECONDS_PER_LOOP` - // to make this duration approximately 100 ms. - static unsigned long led_on = 0; - if (state) { - led_on = micros(); - } else { - char buffer[128]; - sprintf(buffer, "led_on duration: %lu\n", micros() - led_on); - Serial.print(buffer); - } -#endif + /** + * Calibrate `JIANGTUN_MICROSECONDS_PER_LOOP` + * to make this duration approximately 100 ms. + */ + // static unsigned long led_on = 0; + // if (state) { + // led_on = micros(); + // } else { + // char buffer[128]; + // sprintf(buffer, "led_on duration: %lu\n", micros() - led_on); + // Serial.print(buffer); + // } } void setup() { Serial.begin(115200); - pinMode(PIN_LED_R, OUTPUT); - pinMode(PIN_LED_G, OUTPUT); - // pinMode(PIN_LED_B_BUILTIN, OUTPUT); - digitalWrite(PIN_LED_R, HIGH); - digitalWrite(PIN_LED_G, HIGH); - // digitalWrite(PIN_LED_B_BUILTIN, HIGH); + pinMode(PIN_XIAO_LED_R, OUTPUT); + pinMode(PIN_XIAO_LED_G, OUTPUT); + // pinMode(PIN_XIAO_LED_B_PICO_LED_BUILTIN, OUTPUT); + digitalWrite(PIN_XIAO_LED_R, HIGH); + digitalWrite(PIN_XIAO_LED_G, HIGH); + // digitalWrite(PIN_XIAO_LED_B_PICO_LED_BUILTIN, HIGH); - pinMode(PIN_NEOPIXEL_POWER, OUTPUT); - digitalWrite(PIN_NEOPIXEL_POWER, HIGH); - pixels.begin(); + pinMode(PIN_XIAO_LED_B_PICO_LED_BUILTIN, OUTPUT); + digitalWrite(PIN_XIAO_LED_B_PICO_LED_BUILTIN, LOW); - pinMode(PIN_LED_B_BUILTIN, OUTPUT); - digitalWrite(PIN_LED_B_BUILTIN, LOW); + pinMode(PIN_XIAO_NEOPIXEL_POWER, OUTPUT); + digitalWrite(PIN_XIAO_NEOPIXEL_POWER, HIGH); + pixels.begin(); + pixels.clear(); + pixels.show(); jiangtun_board_init(&board, jiangtun_board_rp2040_serial_getc, jiangtun_board_rp2040_serial_puts, @@ -165,11 +175,9 @@ void loop1() { servo.write(65); pinMode(PIN_RESET, OUTPUT); digitalWrite(PIN_RESET, LOW); - current_reset_state = true; - } else if (current_reset_state && !reset) { servo.write(90); pinMode(PIN_RESET, INPUT); - current_reset_state = true; } + current_reset_state = reset; } \ No newline at end of file From b2f4cfb182606ae57606852e4ec6fabb1cc2fd9c Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 19:10:16 +0900 Subject: [PATCH 18/25] chores --- src/main.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index eac6ad7..76a0819 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,7 +16,7 @@ static const pin_size_t PIN_XIAO_LED_R = 17; static const pin_size_t PIN_XIAO_LED_G = 16; /** * GPIO25 is connected to the anode of the built-in LED on the Pico (lit - * when HIGH), and to the cathode of the blue channel of the RGB LED on the + * when HIGH), and to the cathode of the blue channel of the RGB LED on the * XIAO RP2040 (lit when LOW). * This firmware prioritizes blinking the LED on the Pico, so on the XIAO * RP2040, the blue LED will remain on and turn off when input is accepted. @@ -124,10 +124,8 @@ void setup() { pinMode(PIN_XIAO_LED_R, OUTPUT); pinMode(PIN_XIAO_LED_G, OUTPUT); - // pinMode(PIN_XIAO_LED_B_PICO_LED_BUILTIN, OUTPUT); digitalWrite(PIN_XIAO_LED_R, HIGH); digitalWrite(PIN_XIAO_LED_G, HIGH); - // digitalWrite(PIN_XIAO_LED_B_PICO_LED_BUILTIN, HIGH); pinMode(PIN_XIAO_LED_B_PICO_LED_BUILTIN, OUTPUT); digitalWrite(PIN_XIAO_LED_B_PICO_LED_BUILTIN, LOW); From 80db2b05054f15e9e376c6b1431a0299740a32d0 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 19:24:47 +0900 Subject: [PATCH 19/25] Add argument to track report changes in gamecube_send function --- lib/jiangtun-core/include/jiangtun/board.h | 4 +++- lib/jiangtun-core/src/board.c | 3 ++- lib/jiangtun-core/src/jiangtun.c | 26 +++++++++++++--------- lib/jiangtun-core/test/arduino.c | 2 ++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/jiangtun-core/include/jiangtun/board.h b/lib/jiangtun-core/include/jiangtun/board.h index df8d481..c05e304 100644 --- a/lib/jiangtun-core/include/jiangtun/board.h +++ b/lib/jiangtun-core/include/jiangtun/board.h @@ -12,7 +12,7 @@ typedef struct jiangtun_board_t { jiangtun_bool_t (*serial_getc)(struct jiangtun_board_t *, jiangtun_uint8_t *); void (*serial_puts)(struct jiangtun_board_t *, const char *); - jiangtun_bool_t (*gamecube_send)(struct jiangtun_board_t *, + jiangtun_bool_t (*gamecube_send)(struct jiangtun_board_t *, jiangtun_bool_t, jiangtun_report_mode3_t *); void (*led_set)(struct jiangtun_board_t *, jiangtun_bool_t); } jiangtun_board_t; @@ -21,6 +21,7 @@ typedef jiangtun_bool_t (*jiangtun_serial_getc_t)(jiangtun_board_t *, jiangtun_uint8_t *); typedef void (*jiangtun_serial_puts_t)(jiangtun_board_t *, const char *); typedef jiangtun_bool_t (*jiangtun_gamecube_send_t)(jiangtun_board_t *, + jiangtun_bool_t, jiangtun_report_mode3_t *); typedef void (*jiangtun_led_set_t)(jiangtun_board_t *, jiangtun_bool_t); @@ -28,6 +29,7 @@ jiangtun_bool_t jiangtun_board_serial_getc(jiangtun_board_t *, jiangtun_uint8_t *); void jiangtun_board_serial_puts(jiangtun_board_t *, const char *); jiangtun_bool_t jiangtun_board_gamecube_send(jiangtun_board_t *, + jiangtun_bool_t, jiangtun_report_mode3_t *); void jiangtun_board_led_set(jiangtun_board_t *, jiangtun_bool_t); void jiangtun_board_init(jiangtun_board_t *, jiangtun_serial_getc_t, diff --git a/lib/jiangtun-core/src/board.c b/lib/jiangtun-core/src/board.c index 13d3814..7da017a 100644 --- a/lib/jiangtun-core/src/board.c +++ b/lib/jiangtun-core/src/board.c @@ -18,11 +18,12 @@ void jiangtun_board_serial_puts(jiangtun_board_t *board, const char *s) { } jiangtun_bool_t jiangtun_board_gamecube_send(jiangtun_board_t *board, + jiangtun_bool_t changed, jiangtun_report_mode3_t *report) { assert(board != NULL); assert(report != NULL); - return board->gamecube_send(board, report); + return board->gamecube_send(board, changed, report); } void jiangtun_board_led_set(jiangtun_board_t *board, jiangtun_bool_t state) { diff --git a/lib/jiangtun-core/src/jiangtun.c b/lib/jiangtun-core/src/jiangtun.c index 4c9cdfd..72dd644 100644 --- a/lib/jiangtun-core/src/jiangtun.c +++ b/lib/jiangtun-core/src/jiangtun.c @@ -90,18 +90,19 @@ void jiangtun_init(jiangtun_t *j, jiangtun_board_t *board, * https://github.com/mizuyoukanao/Bluewhale/blob/c8413b9aab7248089c9144295796d97794a10c64/examples/WHALE/WHALE.ino#L36-L41 */ j->reports[0].start = JIANGTUN_TRUE; - handshake_result = jiangtun_board_gamecube_send(j->board, &(j->reports[0])); - j->reports[0].start = JIANGTUN_FALSE; handshake_result = - jiangtun_board_gamecube_send(j->board, &(j->reports[0])) && - handshake_result; + jiangtun_board_gamecube_send(j->board, JIANGTUN_TRUE, &(j->reports[0])); + j->reports[0].start = JIANGTUN_FALSE; + handshake_result = jiangtun_board_gamecube_send(j->board, JIANGTUN_TRUE, + &(j->reports[0])) && + handshake_result; if (!handshake_result) { serial_log(j, JIANGTUN_LOG_LEVEL_WARN, "handshake failed during initial communications"); } } -static void process_input(jiangtun_t *j) { +static jiangtun_bool_t process_input(jiangtun_t *j) { size_t i = 0; jiangtun_uint8_t c = 0; jiangtun_bool_t all_rejected = JIANGTUN_TRUE; @@ -109,7 +110,7 @@ static void process_input(jiangtun_t *j) { if (j->reset_blocking_loop > 0) { serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking_loop"); - return; + return JIANGTUN_FALSE; } if (jiangtun_optional_uint8_get(&(j->carry_over), &c)) { @@ -126,7 +127,7 @@ static void process_input(jiangtun_t *j) { init_commands(j); j->timeout_loop = JIANGTUN_LOOPS_FOR_TIMEOUT; } - return; + return JIANGTUN_FALSE; } j->timeout_loop = JIANGTUN_LOOPS_FOR_TIMEOUT; jiangtun_optional_uint8_clear(&(j->carry_over)); @@ -158,7 +159,8 @@ static void process_input(jiangtun_t *j) { j->reset_blocking_loop = JIANGTUN_LOOPS_FOR_RESET_BLOCKING; } init_commands(j); - return; + return JIANGTUN_TRUE; + } else if (jiangtun_command_pending(j->commands[i])) { all_rejected = JIANGTUN_FALSE; } @@ -168,15 +170,17 @@ static void process_input(jiangtun_t *j) { serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, j->buffer); jiangtun_optional_uint8_set(&(j->carry_over), c); init_commands(j); - return; + return JIANGTUN_FALSE; } j->any_pending = JIANGTUN_TRUE; + return JIANGTUN_FALSE; } void jiangtun_loop(jiangtun_t *j) { + jiangtun_bool_t changed = JIANGTUN_FALSE; assert(j != NULL); - process_input(j); + changed = process_input(j); if (j->reset_blocking_loop > 0 && --(j->reset_blocking_loop) == 0) { serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, @@ -185,7 +189,7 @@ void jiangtun_loop(jiangtun_t *j) { } jiangtun_report_emend_axis(j->recently_patched); - if (!jiangtun_board_gamecube_send(j->board, j->recently_patched)) { + if (!jiangtun_board_gamecube_send(j->board, changed, j->recently_patched)) { serial_log(j, JIANGTUN_LOG_LEVEL_WARN, "failed to send report"); } diff --git a/lib/jiangtun-core/test/arduino.c b/lib/jiangtun-core/test/arduino.c index 4392ab1..79d5dac 100644 --- a/lib/jiangtun-core/test/arduino.c +++ b/lib/jiangtun-core/test/arduino.c @@ -21,9 +21,11 @@ static void serial_puts(jiangtun_board_t *board, const char *s) { } static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, + jiangtun_bool_t changed, jiangtun_report_mode3_t *report) { assert(board != NULL); assert(report != NULL); + (void)changed; fprintf(stderr, "gamecube_send\n"); return JIANGTUN_FALSE; From ac8ad89cee1ce65db50ecdcfa9fd0ca0cbe307f8 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 19:26:12 +0900 Subject: [PATCH 20/25] Update main.cpp --- src/main.cpp | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 76a0819..e7d9217 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,32 +62,35 @@ static void jiangtun_board_rp2040_serial_puts(jiangtun_board_t *board, static jiangtun_bool_t jiangtun_board_rp2040_gamecube_send(jiangtun_board_t *board, + jiangtun_bool_t changed, jiangtun_report_mode3_t *report) { assert(board != NULL); assert(report != NULL); - mutex_enter_blocking(&gamecube_data_mtx); - gamecube_data.report.a = report->a ? 1 : 0; - gamecube_data.report.b = report->b ? 1 : 0; - gamecube_data.report.x = report->x ? 1 : 0; - gamecube_data.report.y = report->y ? 1 : 0; - gamecube_data.report.start = report->start ? 1 : 0; - gamecube_data.report.dleft = report->dleft ? 1 : 0; - gamecube_data.report.dright = report->dright ? 1 : 0; - gamecube_data.report.ddown = report->ddown ? 1 : 0; - gamecube_data.report.dup = report->dup ? 1 : 0; - gamecube_data.report.z = report->z ? 1 : 0; - gamecube_data.report.r = report->r ? 1 : 0; - gamecube_data.report.l = report->l ? 1 : 0; - gamecube_data.report.xAxis = (uint8_t)report->xAxis; - gamecube_data.report.yAxis = (uint8_t)report->yAxis; - gamecube_data.report.cxAxis = (uint8_t)report->cxAxis; - gamecube_data.report.cyAxis = (uint8_t)report->cyAxis; - gamecube_data.report.left = (uint8_t)report->left; - gamecube_data.report.right = (uint8_t)report->right; - - gamecube_data_reset = report->reset ? true : false; - mutex_exit(&gamecube_data_mtx); + if (changed) { + mutex_enter_blocking(&gamecube_data_mtx); + gamecube_data.report.a = report->a ? 1 : 0; + gamecube_data.report.b = report->b ? 1 : 0; + gamecube_data.report.x = report->x ? 1 : 0; + gamecube_data.report.y = report->y ? 1 : 0; + gamecube_data.report.start = report->start ? 1 : 0; + gamecube_data.report.dleft = report->dleft ? 1 : 0; + gamecube_data.report.dright = report->dright ? 1 : 0; + gamecube_data.report.ddown = report->ddown ? 1 : 0; + gamecube_data.report.dup = report->dup ? 1 : 0; + gamecube_data.report.z = report->z ? 1 : 0; + gamecube_data.report.r = report->r ? 1 : 0; + gamecube_data.report.l = report->l ? 1 : 0; + gamecube_data.report.xAxis = (uint8_t)report->xAxis; + gamecube_data.report.yAxis = (uint8_t)report->yAxis; + gamecube_data.report.cxAxis = (uint8_t)report->cxAxis; + gamecube_data.report.cyAxis = (uint8_t)report->cyAxis; + gamecube_data.report.left = (uint8_t)report->left; + gamecube_data.report.right = (uint8_t)report->right; + + gamecube_data_reset = report->reset ? true : false; + mutex_exit(&gamecube_data_mtx); + } return JIANGTUN_TRUE; } From b51a3d1f074c4f8e54e6b26490ba8bca21953ae2 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 23:33:29 +0900 Subject: [PATCH 21/25] Add get_millis to retrieve system time --- lib/jiangtun-core/include/jiangtun.h | 30 +++-------- lib/jiangtun-core/include/jiangtun/board.h | 6 ++- lib/jiangtun-core/include/jiangtun/optional.h | 11 ++++ lib/jiangtun-core/src/board.c | 11 +++- lib/jiangtun-core/src/jiangtun.c | 50 ++++++++++++------- lib/jiangtun-core/src/optional.c | 27 ++++++++++ lib/jiangtun-core/test/arduino.c | 8 ++- src/main.cpp | 40 ++++++--------- 8 files changed, 111 insertions(+), 72 deletions(-) diff --git a/lib/jiangtun-core/include/jiangtun.h b/lib/jiangtun-core/include/jiangtun.h index 33e45eb..1547c2b 100644 --- a/lib/jiangtun-core/include/jiangtun.h +++ b/lib/jiangtun-core/include/jiangtun.h @@ -11,14 +11,9 @@ extern "C" { #endif -#ifndef JIANGTUN_MICROSECONDS_PER_LOOP -#define JIANGTUN_MICROSECONDS_PER_LOOP 925 -#endif -#define JIANGTUN_LOOPS_FOR_MILLISECONDS(ms) \ - ((jiangtun_uint32_t)((ms) * 1000 / JIANGTUN_MICROSECONDS_PER_LOOP) + 1) -#define JIANGTUN_LOOPS_FOR_TIMEOUT JIANGTUN_LOOPS_FOR_MILLISECONDS(5) -#define JIANGTUN_LOOPS_FOR_LED JIANGTUN_LOOPS_FOR_MILLISECONDS(100) -#define JIANGTUN_LOOPS_FOR_RESET_BLOCKING JIANGTUN_LOOPS_FOR_MILLISECONDS(500) +#define JIANGTUN_LOOPS_FOR_TIMEOUT 5 +#define JIANGTUN_LED_ON_MILLIS 100 +#define JIANGTUN_RESET_BLOCKING_MILLIS 500 typedef jiangtun_uint32_t jiangtun_feature_flag_t; #define JIANGTUN_FEATURE_ENABLE_LED_BLINK ((jiangtun_feature_flag_t)(1 << 4)) @@ -27,20 +22,6 @@ typedef jiangtun_uint32_t jiangtun_feature_flag_t; #define JIANGTUN_FEATURE_ENABLE_ORCA ((jiangtun_feature_flag_t)(1 << 1)) #define JIANGTUN_FEATURE_ENABLE_DOL ((jiangtun_feature_flag_t)(1 << 0)) -/** - * Compared to the levels commonly provided by high-functionality logging - * libraries, such as "FATAL, ERROR, WARN, INFO, DEBUG, TRACE," the logging - * levels provided here are limited. - * First, Jiangtun does not have a path that leads to FATAL. More precisely, - * there is no way to detect when such a condition occurs. Even if there were a - * way to detect it, in situations where we would want to output a FATAL or - * ERROR log from the firmware, the system is likely already in a state where - * halting cannot be avoided, and it's hard to imagine that output resources - * could be secured at that point. - * Additionally, this library is small-scale enough that during debugging, we - * always want information equivalent to TRACE. There's no need to differentiate - * between DEBUG and TRACE. - */ typedef enum jiangtun_log_level_t { JIANGTUN_LOG_LEVEL_WARN, JIANGTUN_LOG_LEVEL_INFO, @@ -65,8 +46,9 @@ typedef struct jiangtun_t { jiangtun_optional_uint8_t carry_over; jiangtun_uint32_t timeout_loop; - jiangtun_uint32_t led_loop; - jiangtun_uint32_t reset_blocking_loop; + + jiangtun_optional_uint32_t led_on_start_time; + jiangtun_optional_uint32_t reset_blocking_start_time; jiangtun_log_level_t log_level; diff --git a/lib/jiangtun-core/include/jiangtun/board.h b/lib/jiangtun-core/include/jiangtun/board.h index c05e304..b9ed139 100644 --- a/lib/jiangtun-core/include/jiangtun/board.h +++ b/lib/jiangtun-core/include/jiangtun/board.h @@ -15,6 +15,7 @@ typedef struct jiangtun_board_t { jiangtun_bool_t (*gamecube_send)(struct jiangtun_board_t *, jiangtun_bool_t, jiangtun_report_mode3_t *); void (*led_set)(struct jiangtun_board_t *, jiangtun_bool_t); + jiangtun_uint32_t (*get_millis)(struct jiangtun_board_t *); } jiangtun_board_t; typedef jiangtun_bool_t (*jiangtun_serial_getc_t)(jiangtun_board_t *, @@ -24,6 +25,7 @@ typedef jiangtun_bool_t (*jiangtun_gamecube_send_t)(jiangtun_board_t *, jiangtun_bool_t, jiangtun_report_mode3_t *); typedef void (*jiangtun_led_set_t)(jiangtun_board_t *, jiangtun_bool_t); +typedef jiangtun_uint32_t (*jiangtun_get_millis_t)(jiangtun_board_t *); jiangtun_bool_t jiangtun_board_serial_getc(jiangtun_board_t *, jiangtun_uint8_t *); @@ -32,9 +34,11 @@ jiangtun_bool_t jiangtun_board_gamecube_send(jiangtun_board_t *, jiangtun_bool_t, jiangtun_report_mode3_t *); void jiangtun_board_led_set(jiangtun_board_t *, jiangtun_bool_t); +jiangtun_uint32_t jiangtun_board_get_millis(jiangtun_board_t *); + void jiangtun_board_init(jiangtun_board_t *, jiangtun_serial_getc_t, jiangtun_serial_puts_t, jiangtun_gamecube_send_t, - jiangtun_led_set_t); + jiangtun_led_set_t, jiangtun_get_millis_t); #ifdef __cplusplus } diff --git a/lib/jiangtun-core/include/jiangtun/optional.h b/lib/jiangtun-core/include/jiangtun/optional.h index 1739223..f11a74b 100644 --- a/lib/jiangtun-core/include/jiangtun/optional.h +++ b/lib/jiangtun-core/include/jiangtun/optional.h @@ -17,6 +17,17 @@ jiangtun_bool_t jiangtun_optional_uint8_get(jiangtun_optional_uint8_t *, jiangtun_uint8_t *); void jiangtun_optional_uint8_clear(jiangtun_optional_uint8_t *); +typedef struct jiangtun_optional_uint32_t { + jiangtun_uint32_t value; + jiangtun_uint32_t *pointer; +} jiangtun_optional_uint32_t; + +void jiangtun_optional_uint32_set(jiangtun_optional_uint32_t *, + jiangtun_uint32_t); +jiangtun_bool_t jiangtun_optional_uint32_get(jiangtun_optional_uint32_t *, + jiangtun_uint32_t *); +void jiangtun_optional_uint32_clear(jiangtun_optional_uint32_t *); + #ifdef __cplusplus } #endif diff --git a/lib/jiangtun-core/src/board.c b/lib/jiangtun-core/src/board.c index 7da017a..2b1d1f3 100644 --- a/lib/jiangtun-core/src/board.c +++ b/lib/jiangtun-core/src/board.c @@ -32,19 +32,28 @@ void jiangtun_board_led_set(jiangtun_board_t *board, jiangtun_bool_t state) { board->led_set(board, state); } +jiangtun_uint32_t jiangtun_board_get_millis(jiangtun_board_t *board) { + assert(board != NULL); + + return board->get_millis(board); +} + void jiangtun_board_init(jiangtun_board_t *board, jiangtun_serial_getc_t serial_getc, jiangtun_serial_puts_t serial_puts, jiangtun_gamecube_send_t gamecube_send, - jiangtun_led_set_t led_set) { + jiangtun_led_set_t led_set, + jiangtun_get_millis_t get_millis) { assert(board != NULL); assert(serial_getc != NULL); assert(serial_puts != NULL); assert(gamecube_send != NULL); assert(led_set != NULL); + assert(get_millis != NULL); board->serial_getc = serial_getc; board->serial_puts = serial_puts; board->gamecube_send = gamecube_send; board->led_set = led_set; + board->get_millis = get_millis; } \ No newline at end of file diff --git a/lib/jiangtun-core/src/jiangtun.c b/lib/jiangtun-core/src/jiangtun.c index 72dd644..22d7d76 100644 --- a/lib/jiangtun-core/src/jiangtun.c +++ b/lib/jiangtun-core/src/jiangtun.c @@ -82,8 +82,8 @@ void jiangtun_init(jiangtun_t *j, jiangtun_board_t *board, j->any_pending = JIANGTUN_FALSE; jiangtun_optional_uint8_clear(&(j->carry_over)); j->timeout_loop = JIANGTUN_LOOPS_FOR_TIMEOUT; - j->led_loop = 0; - j->reset_blocking_loop = 0; + jiangtun_optional_uint32_clear(&(j->led_on_start_time)); + jiangtun_optional_uint32_clear(&(j->reset_blocking_start_time)); j->log_level = log_level; /* @@ -102,15 +102,26 @@ void jiangtun_init(jiangtun_t *j, jiangtun_board_t *board, } } -static jiangtun_bool_t process_input(jiangtun_t *j) { +static jiangtun_bool_t process_input(jiangtun_t *j, + jiangtun_uint32_t current_millis) { size_t i = 0; + jiangtun_uint32_t reset_blocking_start_time = 0; jiangtun_uint8_t c = 0; jiangtun_bool_t all_rejected = JIANGTUN_TRUE; assert(j != NULL); - if (j->reset_blocking_loop > 0) { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking_loop"); - return JIANGTUN_FALSE; + if (jiangtun_optional_uint32_get(&(j->reset_blocking_start_time), + &reset_blocking_start_time)) { + if (current_millis - reset_blocking_start_time < + JIANGTUN_RESET_BLOCKING_MILLIS) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking"); + return JIANGTUN_FALSE; + } else { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "reset_blocking completed"); + j->recently_patched->reset = JIANGTUN_FALSE; + jiangtun_optional_uint32_clear(&(j->reset_blocking_start_time)); + return JIANGTUN_TRUE; + } } if (jiangtun_optional_uint8_get(&(j->carry_over), &c)) { @@ -151,12 +162,13 @@ static jiangtun_bool_t process_input(jiangtun_t *j) { jiangtun_board_led_set( j->board, j->features & JIANGTUN_FEATURE_ENABLE_LED_BLINK); - j->led_loop += JIANGTUN_LOOPS_FOR_LED; + jiangtun_optional_uint32_set(&(j->led_on_start_time), + current_millis); if (!j->any_pending && c == '@') { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, - "'@' received, initiating reset_blocking_loop"); - j->reset_blocking_loop = JIANGTUN_LOOPS_FOR_RESET_BLOCKING; + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "'@' received"); + jiangtun_optional_uint32_set(&(j->reset_blocking_start_time), + current_millis); } init_commands(j); return JIANGTUN_TRUE; @@ -178,23 +190,23 @@ static jiangtun_bool_t process_input(jiangtun_t *j) { void jiangtun_loop(jiangtun_t *j) { jiangtun_bool_t changed = JIANGTUN_FALSE; + jiangtun_uint32_t current_millis = jiangtun_board_get_millis(j->board); + jiangtun_uint32_t led_on_start_time = 0; assert(j != NULL); - changed = process_input(j); - - if (j->reset_blocking_loop > 0 && --(j->reset_blocking_loop) == 0) { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, - "reset_blocking_loop completed"); - j->recently_patched->reset = JIANGTUN_FALSE; + if ((changed = process_input(j, current_millis))) { + jiangtun_report_emend_axis(j->recently_patched); } - jiangtun_report_emend_axis(j->recently_patched); if (!jiangtun_board_gamecube_send(j->board, changed, j->recently_patched)) { serial_log(j, JIANGTUN_LOG_LEVEL_WARN, "failed to send report"); } - if (j->led_loop > 0 && --(j->led_loop) == 0) { - serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "led_loop completed"); + if (jiangtun_optional_uint32_get(&(j->led_on_start_time), + &led_on_start_time) && + current_millis - led_on_start_time >= JIANGTUN_LED_ON_MILLIS) { + serial_log(j, JIANGTUN_LOG_LEVEL_DEBUG, "led_on completed"); jiangtun_board_led_set(j->board, JIANGTUN_FALSE); + jiangtun_optional_uint32_clear(&(j->led_on_start_time)); } } \ No newline at end of file diff --git a/lib/jiangtun-core/src/optional.c b/lib/jiangtun-core/src/optional.c index 9d11ce0..3c135f0 100644 --- a/lib/jiangtun-core/src/optional.c +++ b/lib/jiangtun-core/src/optional.c @@ -25,5 +25,32 @@ jiangtun_bool_t jiangtun_optional_uint8_get(jiangtun_optional_uint8_t *optional, void jiangtun_optional_uint8_clear(jiangtun_optional_uint8_t *optional) { assert(optional != NULL); + optional->pointer = NULL; +} + +void jiangtun_optional_uint32_set(jiangtun_optional_uint32_t *optional, + jiangtun_uint32_t value) { + assert(optional != NULL); + + optional->value = value; + optional->pointer = &(optional->value); +} + +jiangtun_bool_t +jiangtun_optional_uint32_get(jiangtun_optional_uint32_t *optional, + jiangtun_uint32_t *value) { + assert(optional != NULL); + assert(value != NULL); + + if (optional->pointer == NULL) { + return JIANGTUN_FALSE; + } + *value = optional->value; + return JIANGTUN_TRUE; +} + +void jiangtun_optional_uint32_clear(jiangtun_optional_uint32_t *optional) { + assert(optional != NULL); + optional->pointer = NULL; } \ No newline at end of file diff --git a/lib/jiangtun-core/test/arduino.c b/lib/jiangtun-core/test/arduino.c index 79d5dac..e3a8cd2 100644 --- a/lib/jiangtun-core/test/arduino.c +++ b/lib/jiangtun-core/test/arduino.c @@ -37,6 +37,12 @@ static void led_set(jiangtun_board_t *board, jiangtun_bool_t state) { fprintf(stderr, "led_set: %u\n", state); } +static jiangtun_uint32_t get_millis(jiangtun_board_t *board) { + assert(board != NULL); + + return 0; +} + int main(void) { size_t i = 0; jiangtun_t j; @@ -46,7 +52,7 @@ int main(void) { JIANGTUN_FEATURE_ENABLE_POKECON | JIANGTUN_FEATURE_ENABLE_ORCA; jiangtun_board_init(&board, serial_getc, serial_puts, gamecube_send, - led_set); + led_set, get_millis); jiangtun_init(&j, &board, features, JIANGTUN_LOG_LEVEL_DEBUG); for (i = 0; i < 5; i++) { diff --git a/src/main.cpp b/src/main.cpp index e7d9217..b323a2d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,8 +36,7 @@ static Adafruit_NeoPixel pixels(1, PIN_XIAO_NEOPIXEL, NEO_GRB + NEO_KHZ800); static jiangtun_board_t board; static jiangtun_t j; -static jiangtun_bool_t -jiangtun_board_rp2040_serial_getc(jiangtun_board_t *board, unsigned char *c) { +static jiangtun_bool_t serial_getc(jiangtun_board_t *board, unsigned char *c) { assert(board != NULL); assert(c != NULL); @@ -52,18 +51,16 @@ jiangtun_board_rp2040_serial_getc(jiangtun_board_t *board, unsigned char *c) { return JIANGTUN_TRUE; } -static void jiangtun_board_rp2040_serial_puts(jiangtun_board_t *board, - const char *s) { +static void serial_puts(jiangtun_board_t *board, const char *s) { assert(board != NULL); assert(s != NULL); Serial.print(s); } -static jiangtun_bool_t -jiangtun_board_rp2040_gamecube_send(jiangtun_board_t *board, - jiangtun_bool_t changed, - jiangtun_report_mode3_t *report) { +static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, + jiangtun_bool_t changed, + jiangtun_report_mode3_t *report) { assert(board != NULL); assert(report != NULL); @@ -95,8 +92,7 @@ jiangtun_board_rp2040_gamecube_send(jiangtun_board_t *board, return JIANGTUN_TRUE; } -static void jiangtun_board_rp2040_led_set(jiangtun_board_t *board, - jiangtun_bool_t state) { +static void led_set(jiangtun_board_t *board, jiangtun_bool_t state) { assert(board != NULL); digitalWrite(PIN_XIAO_LED_B_PICO_LED_BUILTIN, state ? HIGH : LOW); @@ -107,19 +103,12 @@ static void jiangtun_board_rp2040_led_set(jiangtun_board_t *board, pixels.clear(); } pixels.show(); +} + +static jiangtun_uint32_t get_millis(jiangtun_board_t *board) { + assert(board != NULL); - /** - * Calibrate `JIANGTUN_MICROSECONDS_PER_LOOP` - * to make this duration approximately 100 ms. - */ - // static unsigned long led_on = 0; - // if (state) { - // led_on = micros(); - // } else { - // char buffer[128]; - // sprintf(buffer, "led_on duration: %lu\n", micros() - led_on); - // Serial.print(buffer); - // } + return (jiangtun_uint32_t)(millis() % JIANGTUN_UINT32_MAX); } void setup() { @@ -139,10 +128,8 @@ void setup() { pixels.clear(); pixels.show(); - jiangtun_board_init(&board, jiangtun_board_rp2040_serial_getc, - jiangtun_board_rp2040_serial_puts, - jiangtun_board_rp2040_gamecube_send, - jiangtun_board_rp2040_led_set); + jiangtun_board_init(&board, serial_getc, serial_puts, gamecube_send, + led_set, get_millis); mutex_init(&gamecube_data_mtx); jiangtun_init( &j, &board, @@ -172,6 +159,7 @@ void loop1() { if (!ret) { Serial.println("[core2]\tfailed to send report"); } + if (!(current_reset_state) && reset) { servo.write(65); pinMode(PIN_RESET, OUTPUT); From b1f8f609637af3c09c3ec73df50d4a946fa925c5 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 23:41:46 +0900 Subject: [PATCH 22/25] Use only core0 --- src/main.cpp | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b323a2d..4cb76dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,6 @@ static CGamecubeConsole gamecube(PIN_GAMECUBE); static Servo servo; static Gamecube_Data_t gamecube_data = defaultGamecubeData; static bool gamecube_data_reset = false; -static mutex_t gamecube_data_mtx; static bool current_reset_state = true; // to ensure initial releasing static Adafruit_NeoPixel pixels(1, PIN_XIAO_NEOPIXEL, NEO_GRB + NEO_KHZ800); @@ -65,7 +64,6 @@ static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, assert(report != NULL); if (changed) { - mutex_enter_blocking(&gamecube_data_mtx); gamecube_data.report.a = report->a ? 1 : 0; gamecube_data.report.b = report->b ? 1 : 0; gamecube_data.report.x = report->x ? 1 : 0; @@ -86,9 +84,20 @@ static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, gamecube_data.report.right = (uint8_t)report->right; gamecube_data_reset = report->reset ? true : false; - mutex_exit(&gamecube_data_mtx); } + bool ret = gamecube.write(gamecube_data); + + if (!(current_reset_state) && gamecube_data_reset) { + servo.write(65); + pinMode(PIN_RESET, OUTPUT); + digitalWrite(PIN_RESET, LOW); + } else if (current_reset_state && !gamecube_data_reset) { + servo.write(90); + pinMode(PIN_RESET, INPUT); + } + current_reset_state = gamecube_data_reset; + return JIANGTUN_TRUE; } @@ -114,6 +123,8 @@ static jiangtun_uint32_t get_millis(jiangtun_board_t *board) { void setup() { Serial.begin(115200); + servo.attach(PIN_SERVO, 500, 2400); + pinMode(PIN_XIAO_LED_R, OUTPUT); pinMode(PIN_XIAO_LED_G, OUTPUT); digitalWrite(PIN_XIAO_LED_R, HIGH); @@ -130,7 +141,6 @@ void setup() { jiangtun_board_init(&board, serial_getc, serial_puts, gamecube_send, led_set, get_millis); - mutex_init(&gamecube_data_mtx); jiangtun_init( &j, &board, JIANGTUN_FEATURE_ENABLE_LED_BLINK | JIANGTUN_FEATURE_ENABLE_NXMC2 | @@ -143,30 +153,4 @@ void setup() { ); } -void loop() { jiangtun_loop(&j); } - -void setup1() { - servo.attach(PIN_SERVO, 500, 2400); - while (!mutex_is_initialized(&gamecube_data_mtx)) - ; -} - -void loop1() { - mutex_enter_blocking(&gamecube_data_mtx); - bool ret = gamecube.write(gamecube_data); - bool reset = gamecube_data_reset; - mutex_exit(&gamecube_data_mtx); - if (!ret) { - Serial.println("[core2]\tfailed to send report"); - } - - if (!(current_reset_state) && reset) { - servo.write(65); - pinMode(PIN_RESET, OUTPUT); - digitalWrite(PIN_RESET, LOW); - } else if (current_reset_state && !reset) { - servo.write(90); - pinMode(PIN_RESET, INPUT); - } - current_reset_state = reset; -} \ No newline at end of file +void loop() { jiangtun_loop(&j); } \ No newline at end of file From 19ca62b7ff475f220a1699b8d729d7241c5d44a2 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 23:49:01 +0900 Subject: [PATCH 23/25] Revert "Use only core0" This reverts commit b1f8f609637af3c09c3ec73df50d4a946fa925c5. --- src/main.cpp | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4cb76dc..b323a2d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ static CGamecubeConsole gamecube(PIN_GAMECUBE); static Servo servo; static Gamecube_Data_t gamecube_data = defaultGamecubeData; static bool gamecube_data_reset = false; +static mutex_t gamecube_data_mtx; static bool current_reset_state = true; // to ensure initial releasing static Adafruit_NeoPixel pixels(1, PIN_XIAO_NEOPIXEL, NEO_GRB + NEO_KHZ800); @@ -64,6 +65,7 @@ static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, assert(report != NULL); if (changed) { + mutex_enter_blocking(&gamecube_data_mtx); gamecube_data.report.a = report->a ? 1 : 0; gamecube_data.report.b = report->b ? 1 : 0; gamecube_data.report.x = report->x ? 1 : 0; @@ -84,20 +86,9 @@ static jiangtun_bool_t gamecube_send(jiangtun_board_t *board, gamecube_data.report.right = (uint8_t)report->right; gamecube_data_reset = report->reset ? true : false; + mutex_exit(&gamecube_data_mtx); } - bool ret = gamecube.write(gamecube_data); - - if (!(current_reset_state) && gamecube_data_reset) { - servo.write(65); - pinMode(PIN_RESET, OUTPUT); - digitalWrite(PIN_RESET, LOW); - } else if (current_reset_state && !gamecube_data_reset) { - servo.write(90); - pinMode(PIN_RESET, INPUT); - } - current_reset_state = gamecube_data_reset; - return JIANGTUN_TRUE; } @@ -123,8 +114,6 @@ static jiangtun_uint32_t get_millis(jiangtun_board_t *board) { void setup() { Serial.begin(115200); - servo.attach(PIN_SERVO, 500, 2400); - pinMode(PIN_XIAO_LED_R, OUTPUT); pinMode(PIN_XIAO_LED_G, OUTPUT); digitalWrite(PIN_XIAO_LED_R, HIGH); @@ -141,6 +130,7 @@ void setup() { jiangtun_board_init(&board, serial_getc, serial_puts, gamecube_send, led_set, get_millis); + mutex_init(&gamecube_data_mtx); jiangtun_init( &j, &board, JIANGTUN_FEATURE_ENABLE_LED_BLINK | JIANGTUN_FEATURE_ENABLE_NXMC2 | @@ -153,4 +143,30 @@ void setup() { ); } -void loop() { jiangtun_loop(&j); } \ No newline at end of file +void loop() { jiangtun_loop(&j); } + +void setup1() { + servo.attach(PIN_SERVO, 500, 2400); + while (!mutex_is_initialized(&gamecube_data_mtx)) + ; +} + +void loop1() { + mutex_enter_blocking(&gamecube_data_mtx); + bool ret = gamecube.write(gamecube_data); + bool reset = gamecube_data_reset; + mutex_exit(&gamecube_data_mtx); + if (!ret) { + Serial.println("[core2]\tfailed to send report"); + } + + if (!(current_reset_state) && reset) { + servo.write(65); + pinMode(PIN_RESET, OUTPUT); + digitalWrite(PIN_RESET, LOW); + } else if (current_reset_state && !reset) { + servo.write(90); + pinMode(PIN_RESET, INPUT); + } + current_reset_state = reset; +} \ No newline at end of file From 6000a0087d25d51bb5b3d22eb5fad9779802e7a8 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Mon, 14 Oct 2024 23:56:29 +0900 Subject: [PATCH 24/25] Fix nxmc2 z input --- lib/jiangtun-core/src/nxmc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jiangtun-core/src/nxmc2.c b/lib/jiangtun-core/src/nxmc2.c index 44fcfd8..2f7d76c 100644 --- a/lib/jiangtun-core/src/nxmc2.c +++ b/lib/jiangtun-core/src/nxmc2.c @@ -36,7 +36,7 @@ static jiangtun_bool_t patch(const jiangtun_uint8_t *buffer, size_t length, report->l = (btn0 >> 4) & 1; report->r = (btn0 >> 5) & 1; /* zl = (btn0 >> 6) & 1; */ - report->z = (btn1 >> 7) & 1; + report->z = (btn0 >> 7) & 1; /* minus = (btn1 >> 0) & 1; */ report->start = (btn1 >> 1) & 1; /* l_click = (btn1 >> 2) & 1; */ From b5ccc835258d1a8e8c38ad489c4abe9e485934cb Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Tue, 15 Oct 2024 00:11:20 +0900 Subject: [PATCH 25/25] Update documents --- Makefile | 48 ---------------------------- README.md | 22 ++++++++----- lib/jiangtun-core/library.properties | 2 +- 3 files changed, 15 insertions(+), 57 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 37c2ee2..0000000 --- a/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -.PHONY: all clean - -ifeq ($(OS),Windows_NT) - RM = powershell -Command Remove-Item -Recurse -Force - CP = copy - FIXPATH = $(subst /,\,$1) - PIO = $(USERPROFILE)\.platformio\penv\Scripts\platformio.exe -else - RM = rm -rf - CP = cp - FIXPATH = $1 - PIO = $(HOME)/.platformio/penv/bin/platformio -endif - -VERSION = v2.0.0-alpha - -.pio/build/pico/firmware.uf2: src/main.cpp src/jiangtun.h - $(PIO) run --environment pico - -.pio/build/dol-pico/firmware.uf2: src/main.cpp src/jiangtun.h - $(PIO) run --environment dol-pico - -.pio/build/xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.h - $(PIO) run --environment xiao-rp2040 - -.pio/build/dol-xiao-rp2040/firmware.uf2: src/main.cpp src/jiangtun.h - $(PIO) run --environment dol-xiao-rp2040 - -dist: - mkdir dist - -dist/jiangtun-$(VERSION)-pico.uf2: .pio/build/pico/firmware.uf2 dist - $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) - -dist/jiangtun-$(VERSION)-dol-pico.uf2: .pio/build/dol-pico/firmware.uf2 dist - $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) - -dist/jiangtun-$(VERSION)-xiao-rp2040.uf2: .pio/build/xiao-rp2040/firmware.uf2 dist - $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) - -dist/jiangtun-$(VERSION)-dol-xiao-rp2040.uf2: .pio/build/dol-xiao-rp2040/firmware.uf2 dist - $(CP) $(call FIXPATH,$<) $(call FIXPATH,$@) - -all: dist/jiangtun-$(VERSION)-pico.uf2 dist/jiangtun-$(VERSION)-dol-pico.uf2 dist/jiangtun-$(VERSION)-xiao-rp2040.uf2 dist/jiangtun-$(VERSION)-dol-xiao-rp2040.uf2 - -clean: - $(RM) $(call FIXPATH,dist/*) - $(RM) $(call FIXPATH,.pio/build/*) \ No newline at end of file diff --git a/README.md b/README.md index 44ed5b6..9081a06 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,18 @@ # Jiangtun (江豚) -GC automation alternative firmware for Raspberry Pi Pico. +GameCube automation alternative firmware for RP2040. - [NX Macro Controller](https://blog.bzl-web.com/entry/2020/01/20/165719) - [Poke-Controller Modified](https://github.com/Moi-poke/Poke-Controller-Modified) -- [ORCA GC Controller](https://github.com/yatsuna827/Orca-GC-Controller) (experimental) +- [ORCA GC Controller](https://github.com/yatsuna827/Orca-GC-Controller) -Use GameCube: `GPIO5`, Servo: `GPIO6`. ([WHALE](https://github.com/mizuyoukanao/Bluewhale) compatible) +## Pin assignment + +| Pico | XIAO RP2040 | Function | +| :---: | :---------: | :----------------: | +| 7 | D5 | GameCube DATA | +| 0 | D6 | Servo | +| 3 | D10 | Reset (Active Low) | ## Button mapping @@ -18,14 +24,14 @@ Use GameCube: `GPIO5`, Servo: `GPIO6`. ([WHALE](https://github.com/mizuyoukanao/ | X | X | | L | L | | R | R | -| ZL | (none) | +| ZL | | | ZR | Z | -| - | (none) | +| - | | | + | Start | -| L Click | (none) | -| R Click | (none) | +| L Click | | +| R Click | | | Home | Reset | -| Capture | (none) | +| Capture | | ## Development diff --git a/lib/jiangtun-core/library.properties b/lib/jiangtun-core/library.properties index 2ef39ff..0dcd2db 100644 --- a/lib/jiangtun-core/library.properties +++ b/lib/jiangtun-core/library.properties @@ -1,5 +1,5 @@ name=jiangtun-core -version=1.0.0 +version=0.1.0 author=Koutaro Mukai maintainer=Koutaro Mukai sentence=The core library of Jiangtun.