From 5f96329b8873e4b1af6377f1dd1dfc8af90bc5fa Mon Sep 17 00:00:00 2001 From: No0ne Date: Sun, 18 Dec 2022 15:33:11 +0100 Subject: [PATCH] ready for testing --- ps2x2pico.c | 128 +++++++++++++++++++++++--------------------------- ps2x2pico.uf2 | Bin 74752 -> 77824 bytes 2 files changed, 59 insertions(+), 69 deletions(-) diff --git a/ps2x2pico.c b/ps2x2pico.c index 73e8cfc..0530286 100644 --- a/ps2x2pico.c +++ b/ps2x2pico.c @@ -34,6 +34,8 @@ #define MSCLK 14 #define MSDAT 15 +#define DEBUG true + uint8_t const led2ps2[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; uint8_t const mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; uint8_t const hid2ps2[] = { @@ -49,11 +51,10 @@ uint8_t const hid2ps2[] = { uint8_t const maparray = sizeof(hid2ps2) / sizeof(uint8_t); PIO iokb = pio0; -uint smkb; -uint smkb_jmp; - PIO ioms = pio1; +uint smkb; uint smms; +uint smkb_jmp; uint smms_jmp; bool kb_enabled = true; @@ -99,29 +100,25 @@ int64_t repeat_callback(alarm_id_t id, void *user_data) { return 0; } -void ps2_send(uint8_t data, bool channel) { - if(channel) { - resend_kb = data; - } else { - resend_ms = data; - } - +uint16_t ps2_frame(uint8_t data) { uint8_t parity = 1; for(uint8_t i = 0; i < 8; i++) { parity = parity ^ (data >> i & 1); } - pio_sm_put(channel ? iokb : ioms, channel ? smkb : smms, ((1 << 10) | (parity << 9) | (data << 1)) ^ 0x7ff); + return ((1 << 10) | (parity << 9) | (data << 1)) ^ 0x7ff; } void ms_send(uint8_t data) { - printf("send MS %02x\n", data); - ps2_send(data, false); + if(DEBUG) printf("send MS %02x\n", data); + resend_ms = data; + pio_sm_put(ioms, smms, ps2_frame(data)); } void kb_send(uint8_t data) { - printf("send KB %02x\n", data); - ps2_send(data, true); + if(DEBUG) printf("send KB %02x\n", data); + resend_kb = data; + pio_sm_put(iokb, smkb, ps2_frame(data)); } void maybe_send_e0(uint8_t data) { @@ -130,7 +127,7 @@ void maybe_send_e0(uint8_t data) { data == 0x54 || data == 0x58 || data == 0x65 || data == 0x66 || data >= 0x81) { - ps2_send(0xe0, true); + kb_send(0xe0); } } @@ -176,14 +173,13 @@ void process_kb(uint8_t data) { default: switch(data) { case 0xff: // CMD: Reset - pio_sm_drain_tx_fifo(iokb, smkb); - pio_sm_clear_fifos(iokb, smkb); - kb_send(0xfa); - kb_enabled = true; blinking = true; add_alarm_in_ms(1, blink_callback, NULL, false); + pio_sm_clear_fifos(iokb, smkb); + pio_sm_drain_tx_fifo(iokb, smkb); + kb_send(0xfa); kb_send(0xaa); return; @@ -225,7 +221,6 @@ void process_kb(uint8_t data) { } void process_ms(uint8_t data) { - if(ms_input_mode == MS_INPUT_SET_RATE) { ms_rate = data; // TODO... need to actually honor the sample rate! ms_input_mode = MS_INPUT_CMD; @@ -237,7 +232,7 @@ void process_ms(uint8_t data) { } else if (ms_type == MS_TYPE_WHEEL_3 && ms_magic_seq == 0xc8c850) { ms_type = MS_TYPE_WHEEL_5; } - printf(" MS magic seq: %06x type: %d\n", ms_magic_seq, ms_type); + if(DEBUG) printf(" MS magic seq: %06x type: %d\n", ms_magic_seq, ms_type); return; } @@ -247,14 +242,13 @@ void process_ms(uint8_t data) { switch(data) { case 0xff: // CMD: Reset - pio_sm_drain_tx_fifo(ioms, smms); - pio_sm_clear_fifos(ioms, smms); - ms_send(0xfa); - ms_type = MS_TYPE_STANDARD; ms_mode = MS_MODE_IDLE; ms_rate = 100; + pio_sm_clear_fifos(ioms, smms); + pio_sm_drain_tx_fifo(ioms, smms); + ms_send(0xfa); ms_send(0xaa); ms_send(ms_type); return; @@ -305,11 +299,11 @@ void process_ms(uint8_t data) { } void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { - printf("HID device address = %d, instance = %d is mounted\n", dev_addr, instance); + if(DEBUG) printf("HID device address = %d, instance = %d is mounted\n", dev_addr, instance); switch(tuh_hid_interface_protocol(dev_addr, instance)) { case HID_ITF_PROTOCOL_KEYBOARD: - printf("HID Interface Protocol = Keyboard\n"); + if(DEBUG) printf("HID Interface Protocol = Keyboard\n"); kb_addr = dev_addr; kb_inst = instance; @@ -322,7 +316,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re break; case HID_ITF_PROTOCOL_MOUSE: - printf("HID Interface Protocol = Mouse\n"); + if(DEBUG) printf("HID Interface Protocol = Mouse\n"); //tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_REPORT); ms_send(0xaa); tuh_hid_receive_report(dev_addr, instance); @@ -331,7 +325,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re } void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { - printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); + if(DEBUG) printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); } void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { @@ -431,7 +425,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons break; case HID_ITF_PROTOCOL_MOUSE: - printf("%02x %02x %02x %02x\n", report[0], report[1], report[2], report[3]); + if(DEBUG) printf("%02x %02x %02x %02x\n", report[0], report[1], report[2], report[3]); if(ms_mode != MS_MODE_STREAMING) { tuh_hid_receive_report(dev_addr, instance); @@ -480,15 +474,44 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons } +void check_fifo(PIO pio, uint sm, bool channel) { + if(!pio_sm_is_rx_fifo_empty(pio, sm)) { + uint32_t fifo = pio_sm_get(pio, sm); + if(DEBUG) printf("fifo %08x ", fifo); + fifo = fifo >> 23; + + uint8_t parity = 1; + for(uint8_t i = 0; i < 8; i++) { + parity = parity ^ (fifo >> i & 1); + } + + if(parity != fifo & 0x100) { + if(channel) { + kb_send(0xfe); + } else { + ms_send(0xfe); + } + } else { + if(channel) { + if(DEBUG) printf("got KB %02x ", (uint8_t)fifo); + process_kb(fifo); + } else { + if(DEBUG) printf("got MS %02x ", (uint8_t)fifo); + process_ms(fifo); + } + } + } +} + void irq_callback(uint gpio, uint32_t events) { if(gpio == KBCLK && !gpio_get(KBDAT) && !pio_interrupt_get(iokb, 0)) { - printf("IRQ KB "); + if(DEBUG) printf("IRQ KB "); pio_sm_drain_tx_fifo(iokb, smkb); pio_sm_exec(iokb, smkb, pio_encode_jmp(smkb_jmp + 2)); } if(gpio == MSCLK && !gpio_get(MSDAT) && !pio_interrupt_get(ioms, 0)) { - printf("IRQ MS "); + if(DEBUG) printf("IRQ MS "); pio_sm_drain_tx_fifo(ioms, smms); pio_sm_exec(ioms, smms, pio_encode_jmp(smms_jmp + 2)); } @@ -496,7 +519,7 @@ void irq_callback(uint gpio, uint32_t events) { void main() { board_init(); - printf("ps2x2pico-0.6\n"); + printf("ps2x2pico-0.6 DEBUG=%s\n", DEBUG ? "true" : "false"); smkb = pio_claim_unused_sm(iokb, true); smms = pio_claim_unused_sm(ioms, true); @@ -517,41 +540,8 @@ void main() { while(true) { tuh_task(); - if(!pio_sm_is_rx_fifo_empty(iokb, smkb)) { - uint32_t fifo = pio_sm_get(iokb, smkb); - printf("fifo %08x ", fifo); - fifo = fifo >> 23; - - uint8_t parity = 1; - for(uint8_t i = 0; i < 8; i++) { - parity = parity ^ (fifo >> i & 1); - } - - if(parity != fifo & 0x100) { - kb_send(0xfe); - } else { - printf("got KB %02x ", (unsigned char)fifo); - process_kb(fifo); - } - } - - if(pio_sm_get_rx_fifo_level(ioms, smms)) { - uint32_t fifo = pio_sm_get_blocking(ioms, smms); - printf("fifo %08x ", fifo); - fifo = fifo >> 23; - - uint8_t parity = 1; - for(uint8_t i = 0; i < 8; i++) { - parity = parity ^ (fifo >> i & 1); - } - - if(parity != fifo & 0x100) { - ms_send(0xfe); - } else { - printf("got MS %02x ", (unsigned char)fifo); - process_ms(fifo); - } - } + check_fifo(iokb, smkb, true); + check_fifo(ioms, smms, false); if(repeating) { repeating = false; diff --git a/ps2x2pico.uf2 b/ps2x2pico.uf2 index 15598b818c7693eade380d2a4dcd4029a5eaaece..a283bf5fed94e1275e149f7df4ad6782690ad20c 100644 GIT binary patch delta 13832 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 delta 12135 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