|
|
|
|
@@ -12,207 +12,270 @@ static uint8_t _rhport;
|
|
|
|
|
|
|
|
|
|
volatile uint32_t _resp_len;
|
|
|
|
|
|
|
|
|
|
uint8_t _out_ep_addr;
|
|
|
|
|
uint8_t _in_ep_addr;
|
|
|
|
|
static uint8_t _out_ep_addr;
|
|
|
|
|
static uint8_t _in_ep_addr;
|
|
|
|
|
|
|
|
|
|
buffer_t USBRequestBuffer;
|
|
|
|
|
buffer_t USBResponseBuffer;
|
|
|
|
|
static buffer_t USBRequestBuffer;
|
|
|
|
|
static buffer_t USBResponseBuffer;
|
|
|
|
|
|
|
|
|
|
static uint8_t DAPRequestBuffer[DAP_PACKET_SIZE];
|
|
|
|
|
static uint8_t DAPResponseBuffer[DAP_PACKET_SIZE];
|
|
|
|
|
|
|
|
|
|
#define WR_IDX(x) (x.wptr % DAP_PACKET_COUNT)
|
|
|
|
|
#define RD_IDX(x) (x.rptr % DAP_PACKET_COUNT)
|
|
|
|
|
|
|
|
|
|
#define WR_SLOT_PTR(x) &(x.data[WR_IDX(x)][0])
|
|
|
|
|
#define RD_SLOT_PTR(x) &(x.data[RD_IDX(x)][0])
|
|
|
|
|
|
|
|
|
|
bool buffer_full(buffer_t *buffer)
|
|
|
|
|
{
|
|
|
|
|
return ((buffer->wptr + 1) % DAP_PACKET_COUNT == buffer->rptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool buffer_empty(buffer_t *buffer)
|
|
|
|
|
{
|
|
|
|
|
return (buffer->wptr == buffer->rptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dap_edpt_init(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void dap_edpt_reset(uint8_t __unused rhport)
|
|
|
|
|
{
|
|
|
|
|
itf_num = 0;
|
|
|
|
|
itf_num = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char * dap_cmd_string[] = {
|
|
|
|
|
[ID_DAP_Info ] = "DAP_Info",
|
|
|
|
|
[ID_DAP_HostStatus ] = "DAP_HostStatus",
|
|
|
|
|
[ID_DAP_Connect ] = "DAP_Connect",
|
|
|
|
|
[ID_DAP_Disconnect ] = "DAP_Disconnect",
|
|
|
|
|
[ID_DAP_TransferConfigure ] = "DAP_TransferConfigure",
|
|
|
|
|
[ID_DAP_Transfer ] = "DAP_Transfer",
|
|
|
|
|
[ID_DAP_TransferBlock ] = "DAP_TransferBlock",
|
|
|
|
|
[ID_DAP_TransferAbort ] = "DAP_TransferAbort",
|
|
|
|
|
[ID_DAP_WriteABORT ] = "DAP_WriteABORT",
|
|
|
|
|
[ID_DAP_Delay ] = "DAP_Delay",
|
|
|
|
|
[ID_DAP_ResetTarget ] = "DAP_ResetTarget",
|
|
|
|
|
[ID_DAP_SWJ_Pins ] = "DAP_SWJ_Pins",
|
|
|
|
|
[ID_DAP_SWJ_Clock ] = "DAP_SWJ_Clock",
|
|
|
|
|
[ID_DAP_SWJ_Sequence ] = "DAP_SWJ_Sequence",
|
|
|
|
|
[ID_DAP_SWD_Configure ] = "DAP_SWD_Configure",
|
|
|
|
|
[ID_DAP_SWD_Sequence ] = "DAP_SWD_Sequence",
|
|
|
|
|
[ID_DAP_JTAG_Sequence ] = "DAP_JTAG_Sequence",
|
|
|
|
|
[ID_DAP_JTAG_Configure ] = "DAP_JTAG_Configure",
|
|
|
|
|
[ID_DAP_JTAG_IDCODE ] = "DAP_JTAG_IDCODE",
|
|
|
|
|
[ID_DAP_SWO_Transport ] = "DAP_SWO_Transport",
|
|
|
|
|
[ID_DAP_SWO_Mode ] = "DAP_SWO_Mode",
|
|
|
|
|
[ID_DAP_SWO_Baudrate ] = "DAP_SWO_Baudrate",
|
|
|
|
|
[ID_DAP_SWO_Control ] = "DAP_SWO_Control",
|
|
|
|
|
[ID_DAP_SWO_Status ] = "DAP_SWO_Status",
|
|
|
|
|
[ID_DAP_SWO_ExtendedStatus ] = "DAP_SWO_ExtendedStatus",
|
|
|
|
|
[ID_DAP_SWO_Data ] = "DAP_SWO_Data",
|
|
|
|
|
[ID_DAP_QueueCommands ] = "DAP_QueueCommands",
|
|
|
|
|
[ID_DAP_ExecuteCommands ] = "DAP_ExecuteCommands",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t dap_edpt_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
|
|
|
|
|
PICOPROBE_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
|
|
|
|
|
PICOPROBE_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Initialise circular buffer indices
|
|
|
|
|
USBResponseBuffer.packet_wr_idx = 0;
|
|
|
|
|
USBResponseBuffer.packet_rd_idx = 0;
|
|
|
|
|
USBRequestBuffer.packet_wr_idx = 0;
|
|
|
|
|
USBRequestBuffer.packet_rd_idx = 0;
|
|
|
|
|
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
|
|
|
|
|
PICOPROBE_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
|
|
|
|
|
PICOPROBE_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
|
|
|
|
|
|
|
|
|
|
// Initialse full/empty flags
|
|
|
|
|
USBResponseBuffer.wasFull = false;
|
|
|
|
|
USBResponseBuffer.wasEmpty = true;
|
|
|
|
|
USBRequestBuffer.wasFull = false;
|
|
|
|
|
USBRequestBuffer.wasEmpty = true;
|
|
|
|
|
// Initialise circular buffer indices
|
|
|
|
|
USBResponseBuffer.wptr = 0;
|
|
|
|
|
USBResponseBuffer.rptr = 0;
|
|
|
|
|
USBRequestBuffer.wptr = 0;
|
|
|
|
|
USBRequestBuffer.rptr = 0;
|
|
|
|
|
|
|
|
|
|
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + (itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
|
|
|
|
|
TU_VERIFY(max_len >= drv_len, 0);
|
|
|
|
|
itf_num = itf_desc->bInterfaceNumber;
|
|
|
|
|
// Initialse full/empty flags
|
|
|
|
|
USBResponseBuffer.wasFull = false;
|
|
|
|
|
USBResponseBuffer.wasEmpty = true;
|
|
|
|
|
USBRequestBuffer.wasFull = false;
|
|
|
|
|
USBRequestBuffer.wasEmpty = true;
|
|
|
|
|
|
|
|
|
|
// Initialising the OUT endpoint
|
|
|
|
|
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + (itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
|
|
|
|
|
TU_VERIFY(max_len >= drv_len, 0);
|
|
|
|
|
itf_num = itf_desc->bInterfaceNumber;
|
|
|
|
|
|
|
|
|
|
tusb_desc_endpoint_t *edpt_desc = (tusb_desc_endpoint_t *) (itf_desc + 1);
|
|
|
|
|
uint8_t ep_addr = edpt_desc->bEndpointAddress;
|
|
|
|
|
// Initialising the OUT endpoint
|
|
|
|
|
|
|
|
|
|
_out_ep_addr = ep_addr;
|
|
|
|
|
tusb_desc_endpoint_t *edpt_desc = (tusb_desc_endpoint_t *) (itf_desc + 1);
|
|
|
|
|
uint8_t ep_addr = edpt_desc->bEndpointAddress;
|
|
|
|
|
|
|
|
|
|
// The OUT endpoint requires a call to usbd_edpt_xfer to initialise the endpoint, giving tinyUSB a buffer to consume when a transfer occurs at the endpoint
|
|
|
|
|
usbd_edpt_open(rhport, edpt_desc);
|
|
|
|
|
usbd_edpt_xfer(rhport, ep_addr, &(USBRequestBuffer.data[USBRequestBuffer.packet_wr_idx][0]), DAP_PACKET_SIZE);
|
|
|
|
|
_out_ep_addr = ep_addr;
|
|
|
|
|
|
|
|
|
|
// Initiliasing the IN endpoint
|
|
|
|
|
// The OUT endpoint requires a call to usbd_edpt_xfer to initialise the endpoint, giving tinyUSB a buffer to consume when a transfer occurs at the endpoint
|
|
|
|
|
usbd_edpt_open(rhport, edpt_desc);
|
|
|
|
|
usbd_edpt_xfer(rhport, ep_addr, WR_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
|
|
|
|
|
|
|
|
|
|
edpt_desc++;
|
|
|
|
|
ep_addr = edpt_desc->bEndpointAddress;
|
|
|
|
|
// Initiliasing the IN endpoint
|
|
|
|
|
|
|
|
|
|
_in_ep_addr = ep_addr;
|
|
|
|
|
edpt_desc++;
|
|
|
|
|
ep_addr = edpt_desc->bEndpointAddress;
|
|
|
|
|
|
|
|
|
|
// The IN endpoint doesn't need a transfer to initialise it, as this will be done by the main loop of dap_thread
|
|
|
|
|
usbd_edpt_open(rhport, edpt_desc);
|
|
|
|
|
_in_ep_addr = ep_addr;
|
|
|
|
|
|
|
|
|
|
return drv_len;
|
|
|
|
|
// The IN endpoint doesn't need a transfer to initialise it, as this will be done by the main loop of dap_thread
|
|
|
|
|
usbd_edpt_open(rhport, edpt_desc);
|
|
|
|
|
|
|
|
|
|
return drv_len;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool dap_edpt_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const *request)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Manage USBResponseBuffer (request) write and USBRequestBuffer (response) read indices
|
|
|
|
|
bool dap_edpt_xfer_cb(uint8_t __unused rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t ep_dir = tu_edpt_dir(ep_addr);
|
|
|
|
|
{
|
|
|
|
|
const uint8_t ep_dir = tu_edpt_dir(ep_addr);
|
|
|
|
|
|
|
|
|
|
if(ep_dir == TUSB_DIR_IN)
|
|
|
|
|
{
|
|
|
|
|
if(xferred_bytes >= 0u && xferred_bytes <= DAP_PACKET_SIZE)
|
|
|
|
|
{
|
|
|
|
|
USBResponseBuffer.packet_rd_idx = (USBResponseBuffer.packet_rd_idx + 1) % DAP_PACKET_COUNT;
|
|
|
|
|
if(ep_dir == TUSB_DIR_IN)
|
|
|
|
|
{
|
|
|
|
|
if(xferred_bytes >= 0u && xferred_bytes <= DAP_PACKET_SIZE)
|
|
|
|
|
{
|
|
|
|
|
USBResponseBuffer.rptr++;
|
|
|
|
|
|
|
|
|
|
// This checks that the buffer was not empty in DAP thread, which means the next buffer was not queued up for the in endpoint callback
|
|
|
|
|
// So, queue up the buffer at the new read index, since we expect read to catch up to write at this point.
|
|
|
|
|
// It is possible for the read index to be multiple spaces behind the write index (if the USB callbacks are lagging behind dap thread),
|
|
|
|
|
// so we account for this by only setting wasEmpty to true if the next callback will empty the buffer
|
|
|
|
|
if(!USBResponseBuffer.wasEmpty)
|
|
|
|
|
{
|
|
|
|
|
usbd_edpt_xfer(rhport, ep_addr, &(USBResponseBuffer.data[USBResponseBuffer.packet_rd_idx][0]), (uint16_t) _resp_len);
|
|
|
|
|
USBResponseBuffer.wasEmpty = ((USBResponseBuffer.packet_rd_idx + 1) % DAP_PACKET_COUNT == USBResponseBuffer.packet_wr_idx);
|
|
|
|
|
}
|
|
|
|
|
// This checks that the buffer was not empty in DAP thread, which means the next buffer was not queued up for the in endpoint callback
|
|
|
|
|
// So, queue up the buffer at the new read index, since we expect read to catch up to write at this point.
|
|
|
|
|
// It is possible for the read index to be multiple spaces behind the write index (if the USB callbacks are lagging behind dap thread),
|
|
|
|
|
// so we account for this by only setting wasEmpty to true if the next callback will empty the buffer
|
|
|
|
|
if(!USBResponseBuffer.wasEmpty)
|
|
|
|
|
{
|
|
|
|
|
usbd_edpt_xfer(rhport, ep_addr, RD_SLOT_PTR(USBResponseBuffer), (uint16_t) _resp_len);
|
|
|
|
|
USBResponseBuffer.wasEmpty = (USBResponseBuffer.rptr + 1) == USBResponseBuffer.wptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wake up DAP thread after processing the callback
|
|
|
|
|
vTaskResume(dap_taskhandle);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
// Wake up DAP thread after processing the callback
|
|
|
|
|
vTaskResume(dap_taskhandle);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if(ep_dir == TUSB_DIR_OUT) {
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(xferred_bytes >= 0u && xferred_bytes <= DAP_PACKET_SIZE)
|
|
|
|
|
{
|
|
|
|
|
// Only queue the next buffer in the out callback if the buffer is not full
|
|
|
|
|
// If full, we set the wasFull flag, which will be checked by dap thread
|
|
|
|
|
if(!buffer_full(&USBRequestBuffer))
|
|
|
|
|
{
|
|
|
|
|
USBRequestBuffer.packet_wr_idx = (USBRequestBuffer.packet_wr_idx + 1) % DAP_PACKET_COUNT;
|
|
|
|
|
usbd_edpt_xfer(rhport, ep_addr, &(USBRequestBuffer.data[USBRequestBuffer.packet_wr_idx][0]), DAP_PACKET_SIZE);
|
|
|
|
|
USBRequestBuffer.wasFull = false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
USBRequestBuffer.wasFull = true;
|
|
|
|
|
}
|
|
|
|
|
} else if(ep_dir == TUSB_DIR_OUT) {
|
|
|
|
|
|
|
|
|
|
// Wake up DAP thread after processing the callback
|
|
|
|
|
vTaskResume(dap_taskhandle);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if(xferred_bytes >= 0u && xferred_bytes <= DAP_PACKET_SIZE)
|
|
|
|
|
{
|
|
|
|
|
// Only queue the next buffer in the out callback if the buffer is not full
|
|
|
|
|
// If full, we set the wasFull flag, which will be checked by dap thread
|
|
|
|
|
if(!buffer_full(&USBRequestBuffer))
|
|
|
|
|
{
|
|
|
|
|
USBRequestBuffer.wptr++;
|
|
|
|
|
usbd_edpt_xfer(rhport, ep_addr, WR_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
|
|
|
|
|
USBRequestBuffer.wasFull = false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
USBRequestBuffer.wasFull = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else return false;
|
|
|
|
|
// Wake up DAP thread after processing the callback
|
|
|
|
|
vTaskResume(dap_taskhandle);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dap_thread(void *ptr)
|
|
|
|
|
{
|
|
|
|
|
uint8_t DAPRequestBuffer[DAP_PACKET_SIZE];
|
|
|
|
|
uint8_t DAPResponseBuffer[DAP_PACKET_SIZE];
|
|
|
|
|
uint32_t n;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
while(USBRequestBuffer.rptr != USBRequestBuffer.wptr)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Atomic command support - buffer QueueCommands, but don't process them
|
|
|
|
|
* until a non-QueueCommands packet is seen.
|
|
|
|
|
*/
|
|
|
|
|
n = USBRequestBuffer.rptr;
|
|
|
|
|
while (USBRequestBuffer.data[n % DAP_PACKET_COUNT][0] == ID_DAP_QueueCommands) {
|
|
|
|
|
picoprobe_info("%u %u DAP queued cmd %s len %02x\n",
|
|
|
|
|
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
|
|
|
|
|
dap_cmd_string[USBRequestBuffer.data[n % DAP_PACKET_COUNT][0]], USBRequestBuffer.data[n % DAP_PACKET_COUNT][1]);
|
|
|
|
|
USBRequestBuffer.data[n % DAP_PACKET_COUNT][0] = ID_DAP_ExecuteCommands;
|
|
|
|
|
n++;
|
|
|
|
|
while (n == USBRequestBuffer.wptr) {
|
|
|
|
|
/* Need yield in a loop here, as IN callbacks will also wake the thread */
|
|
|
|
|
picoprobe_info("DAP wait\n");
|
|
|
|
|
vTaskSuspend(dap_taskhandle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Read a single packet from the USB buffer into the DAP Request buffer
|
|
|
|
|
memcpy(DAPRequestBuffer, RD_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
|
|
|
|
|
picoprobe_info("%u %u DAP cmd %s len %02x\n",
|
|
|
|
|
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
|
|
|
|
|
dap_cmd_string[DAPRequestBuffer[0]], DAPRequestBuffer[1]);
|
|
|
|
|
USBRequestBuffer.rptr++;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
while(USBRequestBuffer.packet_rd_idx != USBRequestBuffer.packet_wr_idx)
|
|
|
|
|
{
|
|
|
|
|
// Read a single packet from the USB buffer into the DAP Request buffer
|
|
|
|
|
memcpy(DAPRequestBuffer, &(USBRequestBuffer.data[USBRequestBuffer.packet_rd_idx]), DAP_PACKET_SIZE);
|
|
|
|
|
USBRequestBuffer.packet_rd_idx = (USBRequestBuffer.packet_rd_idx + 1) % DAP_PACKET_COUNT;
|
|
|
|
|
// If the buffer was full in the out callback, we need to queue up another buffer for the endpoint to consume, now that we know there is space in the buffer.
|
|
|
|
|
if(USBRequestBuffer.wasFull)
|
|
|
|
|
{
|
|
|
|
|
vTaskSuspendAll(); // Suspend the scheduler to safely update the write index
|
|
|
|
|
USBRequestBuffer.wptr++;
|
|
|
|
|
usbd_edpt_xfer(_rhport, _out_ep_addr, WR_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
|
|
|
|
|
USBRequestBuffer.wasFull = false;
|
|
|
|
|
xTaskResumeAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the buffer was full in the out callback, we need to queue up another buffer for the endpoint to consume, now that we know there is space in the buffer.
|
|
|
|
|
if(USBRequestBuffer.wasFull)
|
|
|
|
|
{
|
|
|
|
|
vTaskSuspendAll(); // Suspend the scheduler to safely update the write index
|
|
|
|
|
USBRequestBuffer.packet_wr_idx = (USBRequestBuffer.packet_wr_idx + 1) % DAP_PACKET_COUNT;
|
|
|
|
|
usbd_edpt_xfer(_rhport, _out_ep_addr, &(USBRequestBuffer.data[USBRequestBuffer.packet_wr_idx][0]), DAP_PACKET_SIZE);
|
|
|
|
|
USBRequestBuffer.wasFull = false;
|
|
|
|
|
xTaskResumeAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_resp_len = DAP_ProcessCommand(DAPRequestBuffer, DAPResponseBuffer);
|
|
|
|
|
_resp_len = DAP_ExecuteCommand(DAPRequestBuffer, DAPResponseBuffer);
|
|
|
|
|
picoprobe_info("%u %u DAP resp %s\n",
|
|
|
|
|
USBResponseBuffer.wptr, USBResponseBuffer.rptr,
|
|
|
|
|
dap_cmd_string[DAPResponseBuffer[0]]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Suspend the scheduler to avoid stale values/race conditions between threads
|
|
|
|
|
vTaskSuspendAll();
|
|
|
|
|
// Suspend the scheduler to avoid stale values/race conditions between threads
|
|
|
|
|
vTaskSuspendAll();
|
|
|
|
|
|
|
|
|
|
if(buffer_empty(&USBResponseBuffer))
|
|
|
|
|
{
|
|
|
|
|
memcpy(&(USBResponseBuffer.data[USBResponseBuffer.packet_wr_idx]), DAPResponseBuffer, (uint16_t) _resp_len);
|
|
|
|
|
USBResponseBuffer.packet_wr_idx = (USBResponseBuffer.packet_wr_idx + 1) % DAP_PACKET_COUNT;
|
|
|
|
|
if(buffer_empty(&USBResponseBuffer))
|
|
|
|
|
{
|
|
|
|
|
memcpy(WR_SLOT_PTR(USBResponseBuffer), DAPResponseBuffer, (uint16_t) _resp_len);
|
|
|
|
|
USBResponseBuffer.wptr++;
|
|
|
|
|
|
|
|
|
|
usbd_edpt_xfer(_rhport, _in_ep_addr, &(USBResponseBuffer.data[USBResponseBuffer.packet_rd_idx][0]), (uint16_t) _resp_len);
|
|
|
|
|
} else {
|
|
|
|
|
usbd_edpt_xfer(_rhport, _in_ep_addr, RD_SLOT_PTR(USBResponseBuffer), (uint16_t) _resp_len);
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
memcpy(&(USBResponseBuffer.data[USBResponseBuffer.packet_wr_idx]), DAPResponseBuffer, (uint16_t) _resp_len);
|
|
|
|
|
USBResponseBuffer.packet_wr_idx = (USBResponseBuffer.packet_wr_idx + 1) % DAP_PACKET_COUNT;
|
|
|
|
|
|
|
|
|
|
// The In callback needs to check this flag to know when to queue up the next buffer.
|
|
|
|
|
USBResponseBuffer.wasEmpty = false;
|
|
|
|
|
}
|
|
|
|
|
xTaskResumeAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Suspend DAP thread until it is awoken by a USB thread callback
|
|
|
|
|
vTaskSuspend(dap_taskhandle);
|
|
|
|
|
memcpy(WR_SLOT_PTR(USBResponseBuffer), DAPResponseBuffer, (uint16_t) _resp_len);
|
|
|
|
|
USBResponseBuffer.wptr++;
|
|
|
|
|
|
|
|
|
|
// The In callback needs to check this flag to know when to queue up the next buffer.
|
|
|
|
|
USBResponseBuffer.wasEmpty = false;
|
|
|
|
|
}
|
|
|
|
|
xTaskResumeAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Suspend DAP thread until it is awoken by a USB thread callback
|
|
|
|
|
vTaskSuspend(dap_taskhandle);
|
|
|
|
|
|
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_class_driver_t const _dap_edpt_driver =
|
|
|
|
|
{
|
|
|
|
|
.init = dap_edpt_init,
|
|
|
|
|
.reset = dap_edpt_reset,
|
|
|
|
|
.open = dap_edpt_open,
|
|
|
|
|
.control_xfer_cb = dap_edpt_control_xfer_cb,
|
|
|
|
|
.xfer_cb = dap_edpt_xfer_cb,
|
|
|
|
|
.sof = NULL,
|
|
|
|
|
#if CFG_TUSB_DEBUG >= 2
|
|
|
|
|
.name = "PICOPROBE ENDPOINT"
|
|
|
|
|
#endif
|
|
|
|
|
.init = dap_edpt_init,
|
|
|
|
|
.reset = dap_edpt_reset,
|
|
|
|
|
.open = dap_edpt_open,
|
|
|
|
|
.control_xfer_cb = dap_edpt_control_xfer_cb,
|
|
|
|
|
.xfer_cb = dap_edpt_xfer_cb,
|
|
|
|
|
.sof = NULL,
|
|
|
|
|
#if CFG_TUSB_DEBUG >= 2
|
|
|
|
|
.name = "PICOPROBE ENDPOINT"
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Add the custom driver to the tinyUSB stack
|
|
|
|
|
usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count)
|
|
|
|
|
{
|
|
|
|
|
*driver_count = 1;
|
|
|
|
|
return &_dap_edpt_driver;
|
|
|
|
|
*driver_count = 1;
|
|
|
|
|
return &_dap_edpt_driver;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool buffer_full(buffer_t *buffer)
|
|
|
|
|
{
|
|
|
|
|
return ((buffer->packet_wr_idx + 1) % DAP_PACKET_COUNT == buffer->packet_rd_idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool buffer_empty(buffer_t *buffer)
|
|
|
|
|
{
|
|
|
|
|
return (buffer->packet_wr_idx == buffer->packet_rd_idx);
|
|
|
|
|
}
|
|
|
|
|
|