diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt new file mode 100644 index 0000000..d55c6ce --- /dev/null +++ b/firmware/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) + +# initialize the SDK based on PICO_SDK_PATH +# note: this must happen before project() +include(pico_sdk_import.cmake) + +project(td-io) + +# initialize the Raspberry Pi Pico SDK +pico_sdk_init() + +# rest of your project + +add_executable(td-io + td-io.c + ) + +# Pull in our pico_stdlib which aggregates commonly used features +target_link_libraries(td-io pico_stdlib) + +# enable usb output, disable uart output +pico_enable_stdio_usb(td-io 1) +pico_enable_stdio_uart(td-io 0) + +# create map/bin/hex/uf2 file etc. +pico_add_extra_outputs(td-io) diff --git a/firmware/td-io.c b/firmware/td-io.c new file mode 100644 index 0000000..c681a4f --- /dev/null +++ b/firmware/td-io.c @@ -0,0 +1,232 @@ +#include +#include "pico/stdlib.h" +#include + +const uint PIN_JVS_RE = 2; +const uint PIN_JVS_DE = 3; + +const uint PIN_JVS_SENSE_2_5V = 14; +const uint PIN_JVS_SENSE_0V = 13; + +const uint PIN_SR_DATA = 6; +const uint PIN_SR_CLK = 5; +const uint PIN_SR_SH = 4; + +const uint8_t JVS_STATUS_GOOD = 1; + +const uint8_t JVS_REPORT_GOOD = 1; + +const uint8_t JVS_MAX_LEN = 253; // minus two for status and checksum + +uint8_t our_address = 0; + +const char id_str[] = "TD;TD-IO;v1.0;https://github.com/tdaede/td-io"; + +const uint8_t input_desc[] = { + 0x01, 2, 12, 0, + 0x02, 2, 0, 0, + 0x00 +}; + +void start_transmit() { + gpio_put(PIN_JVS_RE, 1); // disable receive + gpio_put(PIN_JVS_DE, 1); // enable transmitter +} + +void stop_transmit() { + uart_tx_wait_blocking(uart0); + gpio_put(PIN_JVS_DE, 0); // disable transmitter + gpio_put(PIN_JVS_RE, 0); // enable receiver +} + +void send_message(uint8_t* m, uint8_t msg_len) { + start_transmit(); + uart_putc(uart0, 0xe0); + uint8_t checksum = 0; + uart_putc(uart0, 0); + checksum += 0; + uart_putc(uart0, msg_len + 2); + checksum += msg_len + 2; + uint8_t status = JVS_STATUS_GOOD; + uart_putc(uart0, status); + checksum += status; + for (int i = 0; i < msg_len; i++) { + uart_putc(uart0, m[i]); + checksum += m[i]; + } + uart_putc(uart0, checksum); + stop_transmit(); +} + +uint32_t read_switches() { + uint32_t r; + gpio_put(PIN_SR_SH, 1); + busy_wait_us(1); + for (int i = 0; i < 32; i++) { + gpio_put(PIN_SR_CLK, 1); + busy_wait_us(1); + gpio_put(PIN_SR_CLK, 0); + busy_wait_us(1); + r <<= 1; + r |= gpio_get(PIN_SR_DATA); + } + gpio_put(PIN_SR_SH, 0); + return ~r; +} + +int main() { + stdio_init_all(); + uart_init(uart0, 115200); + uart_set_translate_crlf(uart0, false); + gpio_set_function(0, GPIO_FUNC_UART); + gpio_set_function(1, GPIO_FUNC_UART); + gpio_init(PIN_JVS_RE); + gpio_put(PIN_JVS_RE, 0); // enable receiver + gpio_set_dir(PIN_JVS_RE, GPIO_OUT); + gpio_init(PIN_JVS_DE); + gpio_put(PIN_JVS_DE, 0); //disable transmitter + gpio_set_dir(PIN_JVS_DE, GPIO_OUT); + gpio_init(PIN_JVS_SENSE_2_5V); + gpio_put(PIN_JVS_SENSE_2_5V, 1); // always appear present + gpio_set_dir(PIN_JVS_SENSE_2_5V, GPIO_OUT); + gpio_init(PIN_JVS_SENSE_0V); + gpio_put(PIN_JVS_SENSE_0V, 0); + gpio_set_dir(PIN_JVS_SENSE_0V, GPIO_OUT); + + // sr + gpio_init(PIN_SR_DATA); + gpio_set_dir(PIN_SR_DATA, GPIO_IN); + gpio_init(PIN_SR_CLK); + gpio_put(PIN_SR_CLK, 0); + gpio_set_dir(PIN_SR_CLK, GPIO_OUT); + gpio_init(PIN_SR_SH); + gpio_put(PIN_SR_SH, 0); + gpio_set_dir(PIN_SR_SH, GPIO_OUT); + + while (true) { + uint8_t sync = uart_getc(uart0); + if (sync == 0xe0) { + uint8_t our_checksum = 0; + uint8_t node_num = uart_getc(uart0); + our_checksum += node_num; + uint8_t length = uart_getc(uart0); + our_checksum += length; + uint8_t msg_length = length - 1; + uint8_t message[256]; + for (int i = 0; i < msg_length; i++) { + uint8_t c = uart_getc(uart0); + our_checksum += c; + message[i] = c; + } + uint8_t msg_send[256]; + int o = 0; + uint8_t status = JVS_STATUS_GOOD; + uint8_t their_checksum = uart_getc(uart0); + if (our_checksum == their_checksum) { + int i = 0; + while (i < msg_length) { + if ((msg_length - i) >= 2 && message[i] == 0xf0 && message[i+1] == 0xd9) { + printf("N: %02x Reset\n", node_num); + our_address = 0; + gpio_put(PIN_JVS_SENSE_0V, 0); + i += 2; + } else if ((msg_length - i) >= 2 && message[i] == 0xf1) { + printf("Assign node id N: %02x\n", message[i+1]); + printf("Assume it is us\n"); + our_address = message[i+1]; + i += 2; + msg_send[o] = JVS_REPORT_GOOD; + o++; + gpio_put(PIN_JVS_SENSE_0V, 1); + } else if ((msg_length - i) >= 1 && message[i] == 0x10) { + i++; + printf("Got ID code request\n"); + msg_send[o] = JVS_REPORT_GOOD; + o++; + strcpy(&msg_send[o], id_str); + o += strlen(id_str) + 1; + } else if ((msg_length - i) >= 1 && message[i] == 0x11) { + i++; + printf("Got revision request\n"); + msg_send[o] = JVS_REPORT_GOOD; + o++; + msg_send[o] = 0x13; + o++; + } else if ((msg_length - i) >= 1 && message[i] == 0x12) { + i++; + printf("Got video revision request\n"); + msg_send[o] = JVS_REPORT_GOOD; + o++; + msg_send[o] = 0x30; + o++; + } else if ((msg_length - i) >= 1 && message[i] == 0x13) { + i++; + printf("Got io revision request\n"); + msg_send[o] = JVS_REPORT_GOOD; + o++; + msg_send[o] = 0x10; + o++; + } else if ((msg_length - i) >= 1 && message[i] == 0x14) { + i++; + printf("Got input descriptor request\n"); + msg_send[o] = JVS_REPORT_GOOD; + o++; + memcpy(&msg_send[o], input_desc, sizeof(input_desc)); + o += sizeof(input_desc); + } else if ((msg_length - i) >= 3 && message[i] == 0x20) { + int num_players = message[i+1]; + int bytes_per_player = message[i+2]; + i += 3; + msg_send[o] = JVS_REPORT_GOOD; + o++; + uint32_t switches = read_switches(); + msg_send[o] = 0x00; // test switches + o++; + //printf("Got coin slot request for %02x slots\n", slots); + for (int player = 0; player < num_players; player++) { + for (int byte = 0; byte < bytes_per_player; byte++) { + uint8_t b = 0; + if ((player == 0) && (byte == 0)) { + b = switches & 0xFF; + } else if ((player == 0) && (byte == 1)) { + b = (switches >> 8) & 0xFF; + } else if ((player == 1) && (byte == 0)) { + b = (switches >> 16) & 0xFF; + } else if ((player == 1) && (byte == 1)) { + b = (switches >> 24) & 0xFF; + } + msg_send[o] = b; + o++; + } + } + } else if ((msg_length - i) >= 2 && message[i] == 0x21) { + int slots = message[i+1]; + i += 2; + msg_send[o] = JVS_REPORT_GOOD; + o++; + //printf("Got coin slot request for %02x slots\n", slots); + for (int slot = 0; slot < slots; slot++) { + msg_send[o] = 0x00; + msg_send[o+1] = 0x00; + o += 2; + } + } else { + printf("Unsupported message: N: %02x L: %02x M: ", node_num, msg_length); + for (int j = 0; j < msg_length; j++) { + printf("%02x", message[j]); + } + printf("\n"); + } + } + if (o > 0) { + send_message(msg_send, o); + } + } else { + printf("Checksum mismatch: theirs: %02x ours: %02x\n", their_checksum, our_checksum); + } + } else { + //printf("Saw non-sync code %02x\n", sync); + } + } + return 0; +}