diff options
Diffstat (limited to 'contrib/firmware/angie/c/src/protocol.c')
-rw-r--r-- | contrib/firmware/angie/c/src/protocol.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c new file mode 100644 index 0000000..3f3aaaf --- /dev/null +++ b/contrib/firmware/angie/c/src/protocol.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : protocol.c * + Contents : Jtag commands handling protocol code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + <aboudjelida@nanoxplore.com> * + <ahmederrachedbjld@gmail.com> * +*****************************************************************************/ + +#include "usb.h" +#include "protocol.h" +#include "jtag.h" +#include "delay.h" +#include "io.h" +#include "msgtypes.h" +#include "reg_ezusb.h" +#include <serial.h> +#include <stdio.h> + +/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */ +volatile uint8_t cmd_id_index; + +/** Number of data bytes already in EP1 Bulk-IN buffer */ +volatile uint8_t payload_index_in; + +/** + * Executes one command and updates global command indexes. + * + * @return true if this command was the last command. + * @return false if there are more commands within the current contents of the + * Bulk EP1-OUT data buffer. + */ +bool execute_command(void) +{ + uint8_t usb_out_bytecount, usb_in_bytecount; + uint16_t signal_state = 0; + uint16_t count; + + /* Most commands do not transfer IN data. To save code space, we write 0 to + * usb_in_bytecount here, then modify it in the switch statement below where + * necessary */ + usb_in_bytecount = 0; + + switch (EP1OUTBUF[cmd_id_index] /* Command ID */) { + case CMD_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + jtag_scan_in((cmd_id_index + 1), payload_index_in); + break; + case CMD_SCAN_OUT: + usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; + jtag_scan_out(cmd_id_index + 1); + break; + case CMD_SCAN_IO: + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_scan_io((cmd_id_index + 1), payload_index_in); + break; + case CMD_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_CLOCK_TCK: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + jtag_clock_tck(count); + break; + case CMD_SLOW_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_SCAN_OUT: + usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; + jtag_slow_scan_out(cmd_id_index + 1); + break; + case CMD_SLOW_SCAN_IO: + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_slow_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_SLOW_CLOCK_TCK: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + jtag_slow_clock_tck(count); + break; + case CMD_SLEEP_US: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + delay_us(count); + break; + case CMD_SLEEP_MS: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + delay_ms(count); + break; + case CMD_GET_SIGNALS: + usb_out_bytecount = 0; + usb_in_bytecount = 2; + signal_state = jtag_get_signals(); + EP1INBUF[payload_index_in] = (signal_state >> 8); + EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF); + break; + case CMD_SET_SIGNALS: + usb_out_bytecount = 2; + jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_CONFIGURE_TCK_FREQ: + usb_out_bytecount = 5; + jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */ + EP1OUTBUF[cmd_id_index + 2], /* scan_out */ + EP1OUTBUF[cmd_id_index + 3], /* scan_io */ + EP1OUTBUF[cmd_id_index + 4], /* clock_tck */ + EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */ + break; + case CMD_TEST: + usb_out_bytecount = 1; + /* Do nothing... This command is only used to test if the device is ready + * to accept new commands */ + break; + default: + /* Should never be reached */ + usb_out_bytecount = 0; + break; + } + + /* Update EP1 Bulk-IN data byte count */ + payload_index_in += usb_in_bytecount; + + /* Determine if this was the last command */ + if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) { + return true; + /* Line between return and else required by checkpatch: */ + uint8_t a = 0; + } else { + /* Not the last command, update cmd_id_index */ + cmd_id_index += (usb_out_bytecount + 1); + return false; + } +} + +/** + * Forever wait for commands and execute them as they arrive. + */ +void command_loop(void) +{ + bool last_command; + while (1) { + cmd_id_index = 0; + payload_index_in = 0; + + /* Wait until host sends EP1 Bulk-OUT packet */ + while (!ep1_out) + ; + ep1_out = false; + + /* Execute the commands */ + last_command = false; + while (!last_command) + last_command = execute_command(); + + /* Send back EP6 Bulk-IN packet if required */ + if (payload_index_in > 0) { + EP1INBC = payload_index_in; + syncdelay(3); + + while (!ep1_in) + ; + ep1_in = false; + } + + /* Re-arm EP1-OUT after command execution */ + EP1OUTBC = 0; + syncdelay(3); + EP1OUTBC = 0; + syncdelay(3); + } +} |