Skip to content

Commit

Permalink
dap_link: fix application freezes, terminal is not open (#51)
Browse files Browse the repository at this point in the history
Co-authored-by: あく <alleteam@gmail.com>
  • Loading branch information
Skorpionm and skotopes authored Oct 10, 2023
1 parent e906219 commit bab62cf
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 62 deletions.
2 changes: 1 addition & 1 deletion application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ App(
],
stack_size=4 * 1024,
fap_description="Enables use of Flipper as a debug probe for ARM devices, implements the CMSIS-DAP protocol",
fap_version="1.0",
fap_version="1.1",
fap_icon="dap_link.png",
fap_category="GPIO",
fap_private_libs=[
Expand Down
134 changes: 81 additions & 53 deletions dap_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ void dap_app_get_state(DapApp* app, DapState* state) {
#define DAP_PROCESS_THREAD_TICK 500

typedef enum {
DapThreadEventStop = (1 << 0),
} DapThreadEvent;
DapEventStop = (1 << 0),
} DapEvent;

void dap_thread_send_stop(FuriThread* thread) {
furi_thread_flags_set(furi_thread_get_id(thread), DapThreadEventStop);
furi_thread_flags_set(furi_thread_get_id(thread), DapEventStop);
}

GpioPin flipper_dap_swclk_pin;
Expand All @@ -59,16 +59,16 @@ typedef struct {
} DapPacket;

typedef enum {
DAPThreadEventStop = DapThreadEventStop,
DAPThreadEventRxV1 = (1 << 1),
DAPThreadEventRxV2 = (1 << 2),
DAPThreadEventUSBConnect = (1 << 3),
DAPThreadEventUSBDisconnect = (1 << 4),
DAPThreadEventApplyConfig = (1 << 5),
DAPThreadEventAll = DAPThreadEventStop | DAPThreadEventRxV1 | DAPThreadEventRxV2 |
DAPThreadEventUSBConnect | DAPThreadEventUSBDisconnect |
DAPThreadEventApplyConfig,
} DAPThreadEvent;
DapThreadEventStop = DapEventStop,
DapThreadEventRxV1 = (1 << 1),
DapThreadEventRxV2 = (1 << 2),
DapThreadEventUsbConnect = (1 << 3),
DapThreadEventUsbDisconnect = (1 << 4),
DapThreadEventApplyConfig = (1 << 5),
DapThreadEventAll = DapThreadEventStop | DapThreadEventRxV1 | DapThreadEventRxV2 |
DapThreadEventUsbConnect | DapThreadEventUsbDisconnect |
DapThreadEventApplyConfig,
} DapThreadEvent;

#define USB_SERIAL_NUMBER_LEN 16
char usb_serial_number[USB_SERIAL_NUMBER_LEN] = {0};
Expand All @@ -81,22 +81,22 @@ const char* dap_app_get_serial(DapApp* app) {
static void dap_app_rx1_callback(void* context) {
furi_assert(context);
FuriThreadId thread_id = (FuriThreadId)context;
furi_thread_flags_set(thread_id, DAPThreadEventRxV1);
furi_thread_flags_set(thread_id, DapThreadEventRxV1);
}

static void dap_app_rx2_callback(void* context) {
furi_assert(context);
FuriThreadId thread_id = (FuriThreadId)context;
furi_thread_flags_set(thread_id, DAPThreadEventRxV2);
furi_thread_flags_set(thread_id, DapThreadEventRxV2);
}

static void dap_app_usb_state_callback(bool state, void* context) {
furi_assert(context);
FuriThreadId thread_id = (FuriThreadId)context;
if(state) {
furi_thread_flags_set(thread_id, DAPThreadEventUSBConnect);
furi_thread_flags_set(thread_id, DapThreadEventUsbConnect);
} else {
furi_thread_flags_set(thread_id, DAPThreadEventUSBDisconnect);
furi_thread_flags_set(thread_id, DapThreadEventUsbDisconnect);
}
}

Expand Down Expand Up @@ -207,39 +207,39 @@ static int32_t dap_process(void* p) {
// work
uint32_t events;
while(1) {
events = furi_thread_flags_wait(DAPThreadEventAll, FuriFlagWaitAny, FuriWaitForever);
events = furi_thread_flags_wait(DapThreadEventAll, FuriFlagWaitAny, FuriWaitForever);

if(!(events & FuriFlagError)) {
if(events & DAPThreadEventRxV1) {
if(events & DapThreadEventRxV1) {
dap_app_process_v1();
dap_state->dap_counter++;
dap_state->dap_version = DapVersionV1;
}

if(events & DAPThreadEventRxV2) {
if(events & DapThreadEventRxV2) {
dap_app_process_v2();
dap_state->dap_counter++;
dap_state->dap_version = DapVersionV2;
}

if(events & DAPThreadEventUSBConnect) {
if(events & DapThreadEventUsbConnect) {
dap_state->usb_connected = true;
}

if(events & DAPThreadEventUSBDisconnect) {
if(events & DapThreadEventUsbDisconnect) {
dap_state->usb_connected = false;
dap_state->dap_version = DapVersionUnknown;
}

if(events & DAPThreadEventApplyConfig) {
if(events & DapThreadEventApplyConfig) {
if(swd_pins_prev != app->config.swd_pins) {
dap_deinit_gpio(swd_pins_prev);
swd_pins_prev = app->config.swd_pins;
dap_init_gpio(swd_pins_prev);
}
}

if(events & DAPThreadEventStop) {
if(events & DapThreadEventStop) {
break;
}
}
Expand All @@ -257,14 +257,20 @@ static int32_t dap_process(void* p) {
/***************************************************************************/

typedef enum {
CDCThreadEventStop = DapThreadEventStop,
CDCThreadEventUARTRx = (1 << 1),
CDCThreadEventCDCRx = (1 << 2),
CDCThreadEventCDCConfig = (1 << 3),
CDCThreadEventApplyConfig = (1 << 4),
CDCThreadEventAll = CDCThreadEventStop | CDCThreadEventUARTRx | CDCThreadEventCDCRx |
CDCThreadEventCDCConfig | CDCThreadEventApplyConfig,
} CDCThreadEvent;
CdcThreadEventStop = DapEventStop,
CdcThreadEventUartRx = (1 << 1),
CdcThreadEventCdcRx = (1 << 2),
CdcThreadEventCdcConfig = (1 << 3),
CdcThreadEventApplyConfig = (1 << 4),
CdcThreadEventCdcDtrHigh = (1 << 5),
CdcThreadEventCdcDtrLow = (1 << 6),
CdcThreadEventCdcTxComplete = (1 << 7),

CdcThreadEventAll = CdcThreadEventStop | CdcThreadEventUartRx | CdcThreadEventCdcRx |
CdcThreadEventCdcConfig | CdcThreadEventApplyConfig |
CdcThreadEventCdcDtrHigh | CdcThreadEventCdcDtrLow |
CdcThreadEventCdcTxComplete,
} CdcThreadEvent;

typedef struct {
FuriStreamBuffer* rx_stream;
Expand All @@ -278,24 +284,36 @@ static void cdc_uart_irq_cb(UartIrqEvent ev, uint8_t data, void* ctx) {

if(ev == UartIrqEventRXNE) {
furi_stream_buffer_send(app->rx_stream, &data, 1, 0);
furi_thread_flags_set(app->thread_id, CDCThreadEventUARTRx);
furi_thread_flags_set(app->thread_id, CdcThreadEventUartRx);
}
}

static void cdc_usb_rx_callback(void* context) {
CDCProcess* app = context;
furi_thread_flags_set(app->thread_id, CDCThreadEventCDCRx);
furi_thread_flags_set(app->thread_id, CdcThreadEventCdcRx);
}

static void cdc_usb_tx_complete_callback(void* context) {
CDCProcess* app = context;
furi_thread_flags_set(app->thread_id, CdcThreadEventCdcTxComplete);
}

static void cdc_usb_control_line_callback(uint8_t state, void* context) {
UNUSED(context);
UNUSED(state);
CDCProcess* app = context;
// bit 0: DTR state, bit 1: RTS state
bool dtr = state & (1 << 0);

if(dtr == true) {
furi_thread_flags_set(app->thread_id, CdcThreadEventCdcDtrHigh);
} else {
furi_thread_flags_set(app->thread_id, CdcThreadEventCdcDtrLow);
}
}

static void cdc_usb_config_callback(struct usb_cdc_line_coding* config, void* context) {
CDCProcess* app = context;
app->line_coding = *config;
furi_thread_flags_set(app->thread_id, CDCThreadEventCDCConfig);
furi_thread_flags_set(app->thread_id, CdcThreadEventCdcConfig);
}

static FuriHalUartId cdc_init_uart(
Expand Down Expand Up @@ -350,7 +368,7 @@ static void cdc_deinit_uart(DapUartType type) {
}
}

static int32_t cdc_process(void* p) {
static int32_t dap_cdc_process(void* p) {
DapApp* dap_app = p;
DapState* dap_state = &(dap_app->state);

Expand All @@ -372,15 +390,18 @@ static int32_t cdc_process(void* p) {

dap_cdc_usb_set_context(app);
dap_cdc_usb_set_rx_callback(cdc_usb_rx_callback);
dap_cdc_usb_set_tx_complete_callback(cdc_usb_tx_complete_callback);
dap_cdc_usb_set_control_line_callback(cdc_usb_control_line_callback);
dap_cdc_usb_set_config_callback(cdc_usb_config_callback);

bool cdc_connect = false;

uint32_t events;
while(1) {
events = furi_thread_flags_wait(CDCThreadEventAll, FuriFlagWaitAny, FuriWaitForever);
events = furi_thread_flags_wait(CdcThreadEventAll, FuriFlagWaitAny, FuriWaitForever);

if(!(events & FuriFlagError)) {
if(events & CDCThreadEventCDCConfig) {
if(events & CdcThreadEventCdcConfig) {
if(dap_state->cdc_baudrate != app->line_coding.dwDTERate) {
dap_state->cdc_baudrate = app->line_coding.dwDTERate;
if(dap_state->cdc_baudrate > 0) {
Expand All @@ -389,25 +410,26 @@ static int32_t cdc_process(void* p) {
}
}

if(events & CDCThreadEventUARTRx) {
if(events & (CdcThreadEventUartRx | CdcThreadEventCdcTxComplete)) {
size_t len =
furi_stream_buffer_receive(app->rx_stream, rx_buffer, rx_buffer_size, 0);

if(len > 0) {
dap_cdc_usb_tx(rx_buffer, len);
if(cdc_connect) {
if(len > 0) {
dap_cdc_usb_tx(rx_buffer, len);
}
dap_state->cdc_rx_counter += len;
}
dap_state->cdc_rx_counter += len;
}

if(events & CDCThreadEventCDCRx) {
if(events & CdcThreadEventCdcRx) {
size_t len = dap_cdc_usb_rx(rx_buffer, rx_buffer_size);
if(len > 0) {
furi_hal_uart_tx(app->uart_id, rx_buffer, len);
}
dap_state->cdc_tx_counter += len;
}

if(events & CDCThreadEventApplyConfig) {
if(events & CdcThreadEventApplyConfig) {
if(uart_pins_prev != dap_app->config.uart_pins ||
uart_swap_prev != dap_app->config.uart_swap) {
cdc_deinit_uart(uart_pins_prev);
Expand All @@ -422,9 +444,15 @@ static int32_t cdc_process(void* p) {
}
}

if(events & CDCThreadEventStop) {
if(events & CdcThreadEventStop) {
break;
}
if(events & CdcThreadEventCdcDtrHigh) {
cdc_connect = true;
}
if(events & CdcThreadEventCdcDtrLow) {
cdc_connect = false;
}
}
}

Expand All @@ -442,9 +470,9 @@ static int32_t cdc_process(void* p) {

static DapApp* dap_app_alloc() {
DapApp* dap_app = malloc(sizeof(DapApp));
dap_app->dap_thread = furi_thread_alloc_ex("DAP Process", 1024, dap_process, dap_app);
dap_app->cdc_thread = furi_thread_alloc_ex("DAP CDC", 1024, cdc_process, dap_app);
dap_app->gui_thread = furi_thread_alloc_ex("DAP GUI", 1024, dap_gui_thread, dap_app);
dap_app->dap_thread = furi_thread_alloc_ex("DapProcess", 1024, dap_process, dap_app);
dap_app->cdc_thread = furi_thread_alloc_ex("DapCdcProcess", 1024, dap_cdc_process, dap_app);
dap_app->gui_thread = furi_thread_alloc_ex("DapGui", 1024, dap_gui_thread, dap_app);
return dap_app;
}

Expand Down Expand Up @@ -472,8 +500,8 @@ void dap_app_connect_jtag() {

void dap_app_set_config(DapApp* app, DapConfig* config) {
app->config = *config;
furi_thread_flags_set(furi_thread_get_id(app->dap_thread), DAPThreadEventApplyConfig);
furi_thread_flags_set(furi_thread_get_id(app->cdc_thread), CDCThreadEventApplyConfig);
furi_thread_flags_set(furi_thread_get_id(app->dap_thread), DapThreadEventApplyConfig);
furi_thread_flags_set(furi_thread_get_id(app->cdc_thread), CdcThreadEventApplyConfig);
}

DapConfig* dap_app_get_config(DapApp* app) {
Expand Down
24 changes: 16 additions & 8 deletions usb/dap_v2_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ typedef struct {
DapRxCallback rx_callback_v1;
DapRxCallback rx_callback_v2;
DapRxCallback rx_callback_cdc;
DapRxCallback tx_complete_cdc;
DapCDCControlLineCallback control_line_callback_cdc;
DapCDCConfigCallback config_callback_cdc;
void* context;
Expand Down Expand Up @@ -522,15 +523,15 @@ int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size) {
int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size) {
if((dap_state.semaphore_cdc == NULL) || (dap_state.connected == false)) return 0;

furi_check(furi_semaphore_acquire(dap_state.semaphore_cdc, FuriWaitForever) == FuriStatusOk);

if(dap_state.connected) {
int32_t len = usbd_ep_write(dap_state.usb_dev, HID_EP_IN | DAP_CDC_EP_SEND, buffer, size);
furi_console_log_printf("cdc tx %ld", len);
return len;
} else {
return 0;
if(furi_semaphore_acquire(dap_state.semaphore_cdc, 100) == FuriStatusOk) {
if(dap_state.connected) {
int32_t len =
usbd_ep_write(dap_state.usb_dev, HID_EP_IN | DAP_CDC_EP_SEND, buffer, size);
furi_console_log_printf("cdc tx %ld", len);
return len;
}
}
return 0;
}

void dap_v1_usb_set_rx_callback(DapRxCallback callback) {
Expand All @@ -545,6 +546,10 @@ void dap_cdc_usb_set_rx_callback(DapRxCallback callback) {
dap_state.rx_callback_cdc = callback;
}

void dap_cdc_usb_set_tx_complete_callback(DapRxCallback callback) {
dap_state.tx_complete_cdc = callback;
}

void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback) {
dap_state.control_line_callback_cdc = callback;
}
Expand Down Expand Up @@ -735,6 +740,9 @@ static void cdc_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
switch(event) {
case usbd_evt_eptx:
furi_semaphore_release(dap_state.semaphore_cdc);
if(dap_state.tx_complete_cdc != NULL) {
dap_state.tx_complete_cdc(dap_state.context_cdc);
}
furi_console_log_printf("cdc tx complete");
break;
case usbd_evt_eprx:
Expand Down
2 changes: 2 additions & 0 deletions usb/dap_v2_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size);

void dap_cdc_usb_set_rx_callback(DapRxCallback callback);

void dap_cdc_usb_set_tx_complete_callback(DapRxCallback callback);

void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback);

void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback);
Expand Down

0 comments on commit bab62cf

Please sign in to comment.