commit 1fee02a2717a44f3b5edddda1d5fc330082e4b7f
parent 2bc1b60f6f1793a27e90ebe1c754f492573d925c
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 6 Mar 2023 18:35:09 -0800
multithreaded mayhem
- fire up a second thread to run all debugger commands on
- wire up a handoff between the ui thread and debugger thread
- set up periodic polling to detect target detach, usb disconnect,
and usb connect and inform the user in a timely fashion
Diffstat:
5 files changed, 188 insertions(+), 29 deletions(-)
diff --git a/src/transport-dap.c b/src/transport-dap.c
@@ -12,15 +12,31 @@
#include "transport.h"
#include "transport-private.h"
+static void usb_failure(DC* dc, int status) {
+ ERROR("usb_failure status %d usb %p\n", status, dc->usb);
+ if (dc->usb != NULL) {
+ usb_close(dc->usb);
+ dc->usb = NULL;
+ }
+ dc->status = DC_OFFLINE;
+}
+
static int dap_get_info(DC* dc, unsigned di, void *out, unsigned minlen, unsigned maxlen) {
uint8_t buf[256 + 2];
buf[0] = DAP_Info;
buf[1] = di;
- if (usb_write(dc->usb, buf, 2) != 2) {
+ int r;
+ if ((r = usb_write(dc->usb, buf, 2)) != 2) {
+ if (r < 0) {
+ usb_failure(dc, r);
+ }
return DC_ERR_IO;
}
int sz = usb_read(dc->usb, buf, 256 + 2);
if ((sz < 2) || (buf[0] != DAP_Info)) {
+ if (sz < 0) {
+ usb_failure(dc, sz);
+ }
return DC_ERR_PROTOCOL;
}
if ((buf[1] < minlen) || (buf[1] > maxlen)) {
@@ -33,13 +49,20 @@ static int dap_get_info(DC* dc, unsigned di, void *out, unsigned minlen, unsigne
static int dap_cmd(DC* dc, const void* tx, unsigned txlen, void* rx, unsigned rxlen) {
uint8_t cmd = ((const uint8_t*) tx)[0];
dump("TX>", tx, txlen);
- if (usb_write(dc->usb, tx, txlen) != txlen) {
+ int r;
+ if ((r = usb_write(dc->usb, tx, txlen)) != txlen) {
ERROR("dap_cmd(0x%02x): usb write error\n", cmd);
+ if (r < 0) {
+ usb_failure(dc, r);
+ }
return DC_ERR_IO;
}
int sz = usb_read(dc->usb, rx, rxlen);
if (sz < 1) {
ERROR("dap_cmd(0x%02x): usb read error\n", cmd);
+ if (sz < 0) {
+ usb_failure(dc, sz);
+ }
return DC_ERR_IO;
}
dump("RX>", rx, rxlen);
@@ -66,7 +89,14 @@ static int dap_cmd_std(DC* dc, const char* name, uint8_t* io,
static int dap_connect(DC* dc) {
uint8_t io[2] = { DAP_Connect, PORT_SWD };
- return dap_cmd_std(dc, "dap_connect()", io, 2, 2);
+ int r = dap_cmd(dc, io, 2, io, 2);
+ if (r < 0) {
+ return r;
+ }
+ if (io[1] != PORT_SWD) {
+ return DC_ERR_REMOTE;
+ }
+ return 0;
}
static int dap_swd_configure(DC* dc, unsigned cfg) {
@@ -171,16 +201,21 @@ static int _dc_q_exec(DC* dc) {
}
int sz = dc->txnext - dc->txbuf;
dump("TX>", dc->txbuf, sz);
- if (usb_write(dc->usb, dc->txbuf, sz) != sz) {
+ int n = usb_write(dc->usb, dc->txbuf, sz);
+ if (n != sz) {
ERROR("dc_q_exec() usb write error\n");
+ if (n < 0) {
+ usb_failure(dc, n);
+ }
return DC_ERR_IO;
}
sz = 3 + (dc->rxnext - dc->rxptr) * 4;
uint8_t rxbuf[1024];
memset(rxbuf, 0xEE, 1024); // DEBUG
- int n = usb_read(dc->usb, rxbuf, sz);
+ n = usb_read(dc->usb, rxbuf, sz);
if (n < 0) {
ERROR("dc_q_exec() usb read error\n");
+ usb_failure(dc, n);
return DC_ERR_IO;
}
dump("RX>", rxbuf, sz);
@@ -209,7 +244,6 @@ int dc_q_exec(DC* dc) {
if (r == DC_ERR_SWD_FAULT) {
// clear all sticky errors
dc_dp_wr(dc, DP_ABORT, DP_ABORT_ALLCLR);
-
}
return r;
}
@@ -456,6 +490,8 @@ int dc_attach(DC* dc, unsigned flags, unsigned tgt, uint32_t* idcode) {
dc->map_csw_keep &= MAP_CSW_KEEP;
+ dc->status = DC_ATTACHED;
+
return 0;
}
@@ -477,6 +513,21 @@ static usb_handle* usb_connect(void) {
return usb_open(dc_vid, dc_pid, dc_serialno);
}
+static const char* di_name(unsigned n) {
+ switch (n) {
+ case DI_Vendor_Name: return "Vendor Name";
+ case DI_Product_Name: return "Product Name";
+ case DI_Serial_Number: return "Serial Number";
+ case DI_Protocol_Version: return "Protocol Version";
+ case DI_Target_Device_Vendor: return "Target Device Vendor";
+ case DI_Target_Device_Name: return "Target Device Name";
+ case DI_Target_Board_Vendor: return "Target Board Vendor";
+ case DI_Target_Board_Name: return "Target Board Name";
+ case DI_Product_Firmware_Version: return "Product Firmware Version";
+ default: return "???";
+ }
+}
+
// setup a newly connected DAP device
static int dap_configure(DC* dc) {
uint8_t buf[256 + 2];
@@ -506,14 +557,13 @@ static int dap_configure(DC* dc) {
int sz = dap_get_info(dc, n, buf, 0, 255);
if (sz > 0) {
buf[sz] = 0;
- INFO("0x%02x: '%s'\n", n, (char*) buf);
+ INFO("connect: %s: '%s'\n", di_name(n), (char*) buf);
}
}
buf[0] = 0; buf[1] = 0;
if (dap_get_info(dc, DI_Capabilities, buf, 1, 2) > 0) {
- INFO("Capabilities: 0x%02x 0x%02x\n", buf[0], buf[1]);
- INFO("Capabilities:");
+ INFO("connect: Capabilities:");
if (buf[0] & I0_SWD) INFO(" SWD");
if (buf[0] & I0_JTAG) INFO(" JTAG");
if (buf[0] & I0_SWO_UART) INFO(" SWO(UART)");
@@ -526,22 +576,22 @@ static int dap_configure(DC* dc) {
INFO("\n");
}
if (dap_get_info(dc, DI_UART_RX_Buffer_Size, &n32, 4, 4) == 4) {
- INFO("UART RX Buffer Size: %u\n", n32);
+ INFO("connect: UART RX Buffer Size: %u\n", n32);
}
if (dap_get_info(dc, DI_UART_TX_Buffer_Size, &n32, 4, 4) == 4) {
- INFO("UART TX Buffer Size: %u\n", n32);
+ INFO("connect: UART TX Buffer Size: %u\n", n32);
}
if (dap_get_info(dc, DI_SWO_Trace_Buffer_Size, &n32, 4, 4) == 4) {
- INFO("SWO Trace Buffer Size: %u\n", n32);
+ INFO("connect: SWO Trace Buffer Size: %u\n", n32);
}
if (dap_get_info(dc, DI_Max_Packet_Count, &n8, 1, 1) == 1) {
- INFO("Max Packet Count: %u\n", n8);
dc->max_packet_count = n8;
}
if (dap_get_info(dc, DI_Max_Packet_Size, &n16, 2, 2) == 2) {
- INFO("Max Packet Size: %u\n", n16);
dc->max_packet_size = n16;
}
+ INFO("connect: Max Packet Count: %u, Size: %u\n",
+ dc->max_packet_count, dc->max_packet_size);
if ((dc->max_packet_count < 1) || (dc->max_packet_size < 64)) {
ERROR("dc_init() impossible packet configuration\n");
return DC_ERR_PROTOCOL;
@@ -561,23 +611,54 @@ static int dap_configure(DC* dc) {
return DC_OK;
}
+static void dc_connect(DC* dc) {
+ if ((dc->usb = usb_connect()) != NULL) {
+ dc->status = DC_UNCONFIG;
+ if (dap_configure(dc) == 0) {
+ dc->status = DC_DETACHED;
+ }
+ }
+}
+
int dc_create(DC** out) {
DC* dc;
if ((dc = calloc(1, sizeof(DC))) == NULL) {
return DC_ERR_FAILED;
}
-
- if ((dc->usb = usb_connect()) == NULL) {
- free(dc);
- return DC_ERR_OFFLINE;
- }
+ *out = dc;
+ dc->status = DC_OFFLINE;
+ dc_connect(dc);
+ return 0;
+}
- int r = dap_configure(dc);
- if (r < 0) {
- free(dc);
- } else {
- *out = dc;
+int dc_periodic(DC* dc) {
+ switch (dc->status) {
+ case DC_OFFLINE:
+ dc_connect(dc);
+ return 1000;
+ case DC_ATTACHED: {
+ uint32_t n;
+ int r = dc_dp_rd(dc, DP_CS, &n);
+ if (r == DC_ERR_IO) {
+ dc->status = DC_OFFLINE;
+ ERROR("offline\n");
+ } else if (r < 0) {
+ dc->status = DC_DETACHED;
+ ERROR("detached\n");
+ }
+ return 250;
+ }
+ case DC_FAILURE:
+ case DC_UNCONFIG:
+ case DC_DETACHED: {
+ // ping the probe to see if USB is still connected
+ uint8_t buf[256 + 2];
+ dap_get_info(dc, DI_Protocol_Version, buf, 0, 255);
+ return 1000;
+ }
+ default:
+ return 1000;
}
- return r;
}
+
diff --git a/src/transport-private.h b/src/transport-private.h
@@ -48,7 +48,8 @@ typedef struct debug_context DC;
#define DC_ATTACHED 0 // attached and ready to do txns
#define DC_FAILURE 1 // last txn failed, need to re-attach
#define DC_DETACHED 2 // have not yet attached
-#define DC_OFFLINE 3 // usb connection not available
+#define DC_UNCONFIG 3 // configure failed
+#define DC_OFFLINE 4 // usb connection not available
#define INVALID 0xFFFFFFFFU
diff --git a/src/transport.h b/src/transport.h
@@ -5,9 +5,13 @@
#include <stdint.h>
+
void dc_require_vid_pid(unsigned vid, unsigned pid);
void dc_require_serialno(const char* sn);
+typedef struct debug_context dctx_t;
+int dc_periodic(dctx_t* dc);
+
#define DC_OK 0
#define DC_ERR_FAILED -1 // generic internal failure
#define DC_ERR_BAD_PARAMS -2 // Invalid parameters
@@ -24,8 +28,6 @@ void dc_require_serialno(const char* sn);
#define DC_ERR_REMOTE -13 // failure from debug probe
#define DC_ERR_DETACHED -14 // transport not connected to target
-typedef struct debug_context dctx_t;
-
int dc_set_clock(dctx_t* dc, uint32_t hz);
// queue Debug Port reads and writes
diff --git a/src/usb.c b/src/usb.c
@@ -269,6 +269,9 @@ void usb_close(usb_handle *usb) {
int usb_ctrl(usb_handle *usb, void *data,
uint8_t typ, uint8_t req, uint16_t val, uint16_t idx, uint16_t len) {
+ if (usb == NULL) {
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
int r = libusb_control_transfer(usb->dev, typ, req, val, idx, data, len, 5000);
if (r < 0) {
return -1;
@@ -278,6 +281,9 @@ int usb_ctrl(usb_handle *usb, void *data,
}
int usb_read(usb_handle *usb, void *data, int len) {
+ if (usb == NULL) {
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
int xfer = len;
int r = libusb_bulk_transfer(usb->dev, usb->ei, data, len, &xfer, 5000);
if (r < 0) {
@@ -287,6 +293,9 @@ int usb_read(usb_handle *usb, void *data, int len) {
}
int usb_read_forever(usb_handle *usb, void *data, int len) {
+ if (usb == NULL) {
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
int xfer = len;
int r = libusb_bulk_transfer(usb->dev, usb->ei, data, len, &xfer, 0);
if (r < 0) {
@@ -296,6 +305,9 @@ int usb_read_forever(usb_handle *usb, void *data, int len) {
}
int usb_write(usb_handle *usb, const void *data, int len) {
+ if (usb == NULL) {
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
int xfer = len;
int r = libusb_bulk_transfer(usb->dev, usb->eo, (void*) data, len, &xfer, 5000);
if (r < 0) {
diff --git a/src/xdebug.c b/src/xdebug.c
@@ -7,6 +7,10 @@
#include <string.h>
#include <stdarg.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+#include <poll.h>
+
#include "xdebug.h"
#include "tui.h"
@@ -109,7 +113,7 @@ int parse(TOKEN* tok) {
return 0;
}
-void handle_line(char *line, unsigned len) {
+void debug_command(char *line) {
CC cc;
while (*line && (*line <= ' ')) line++;
@@ -165,6 +169,52 @@ void handle_line(char *line, unsigned len) {
debugger_command(dc, &cc);
}
+static volatile int running = 1;
+static volatile int busy = 0;
+static int efd = -1;
+static char linebuf[1024];
+
+static void *work_thread(void* arg) {
+ struct pollfd pfd = {
+ .fd = efd,
+ .events = POLLIN,
+ };
+ int timeout = 250;
+ while (running) {
+ int r = poll(&pfd, 1, timeout);
+ if (r < 0) {
+ exit(-1);
+ }
+ if (r == 0) {
+ timeout = dc_periodic(dc);
+ if (timeout < 100) {
+ timeout = 100;
+ }
+ continue;
+ }
+ uint64_t n;
+ if (read(efd, &n, sizeof(n)) != sizeof(n)) {
+ break;
+ }
+ if (busy) {
+ debug_command(linebuf);
+ busy = 0;
+ }
+ }
+ return 0;
+}
+
+void handle_line(char *line, unsigned len) {
+ if (busy) {
+ INFO("busy\n");
+ } else if (len < (sizeof(linebuf)-1)) {
+ memcpy(linebuf, line, len + 1);
+ busy = 1;
+ uint64_t n = 1;
+ if (write(efd, &n, sizeof(n))) {}
+ }
+}
+
static tui_ch_t* ch;
int main(int argc, char** argv) {
@@ -193,9 +243,22 @@ int main(int argc, char** argv) {
return -1;
}
}
+
+ if ((efd = eventfd(0, 0)) < 0) {
+ fprintf(stderr, "cannot create eventfd\n");
+ return -1;
+ }
+
tui_init();
tui_ch_create(&ch, 0);
dc_create(&dc);
+
+ pthread_t t;
+ if (pthread_create(&t, NULL, work_thread, NULL) != 0) {
+ fprintf(stderr, "cannot start thread\n");
+ return -1;
+ }
+
while (tui_handle_event(handle_line) == 0) ;
tui_exit();
return 0;