Created
February 14, 2025 04:45
-
-
Save xobs/1bc85cbe7da8aef31c3b5443d752f2cf to your computer and use it in GitHub Desktop.
dap42 probe test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <libusb.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
typedef struct bmda_probe | |
{ | |
// uint16_t vid; | |
// uint16_t pid; | |
uint8_t interface_num; | |
uint8_t in_ep; | |
uint8_t out_ep; | |
uint16_t max_packet_length; | |
libusb_context *libusb_ctx; | |
libusb_device *libusb_dev; | |
libusb_device_handle *handle; | |
} bmda_probe_s; | |
#define MIN(a, b) ((a) < (b) ? (a) : (b)) | |
static bool check_cmsis_interface_type(libusb_device *const device, bmda_probe_s *const info) | |
{ | |
bool found = false; | |
/* Try to get the active configuration descriptor for the device */ | |
struct libusb_config_descriptor *config; | |
if (libusb_get_active_config_descriptor(device, &config) != LIBUSB_SUCCESS) | |
return false; | |
/* Try to open the device */ | |
libusb_device_handle *handle; | |
if (libusb_open(device, &handle) != LIBUSB_SUCCESS) | |
{ | |
libusb_free_config_descriptor(config); | |
return false; | |
} | |
/* Enumerate the device's interfaces and all their alt modes */ | |
for (uint8_t iface = 0; iface < config->bNumInterfaces; ++iface) | |
{ | |
const struct libusb_interface *interface = &config->interface[iface]; | |
for (int altmode = 0; altmode < interface->num_altsetting; ++altmode) | |
{ | |
const struct libusb_interface_descriptor *descriptor = &interface->altsetting[altmode]; | |
/* If we've found an interface without a description string, ignore it */ | |
if (descriptor->iInterface == 0) | |
continue; | |
char interface_string[128U]; | |
/* Read out the string */ | |
if (libusb_get_string_descriptor_ascii( | |
handle, descriptor->iInterface, (unsigned char *)interface_string, sizeof(interface_string)) < 0) | |
continue; | |
/* Check if it's a CMSIS-DAP interface */ | |
if (strstr(interface_string, "CMSIS") == NULL) | |
continue; | |
/* Scan through the endpoints finding the one with the narrowest max transfer length */ | |
info->max_packet_length = UINT16_MAX; | |
for (uint8_t index = 0; index < descriptor->bNumEndpoints; ++index) | |
info->max_packet_length = MIN(descriptor->endpoint[index].wMaxPacketSize, info->max_packet_length); | |
/* Check if it's a CMSIS-DAP v2 interface */ | |
if (descriptor->bInterfaceClass == 0xffU && descriptor->bNumEndpoints == 2U) | |
{ | |
info->interface_num = descriptor->bInterfaceNumber; | |
/* Extract the endpoints required */ | |
for (uint8_t index = 0; index < descriptor->bNumEndpoints; ++index) | |
{ | |
const uint8_t ep = descriptor->endpoint[index].bEndpointAddress; | |
if (ep & 0x80U) | |
info->in_ep = ep; | |
else | |
info->out_ep = ep; | |
} | |
/* If we've found a CMSIS-DAP v2 interface, look no further - we want to prefer these to v1. */ | |
found = true; | |
break; | |
} | |
} | |
} | |
libusb_close(handle); | |
libusb_free_config_descriptor(config); | |
return found; | |
} | |
static bmda_probe_s *find_cmsis_dap(struct libusb_context *libusb_ctx) | |
{ | |
bmda_probe_s *probe = malloc(sizeof(bmda_probe_s)); | |
libusb_device **device_list; | |
libusb_device_handle *handle = NULL; | |
const ssize_t cnt = libusb_get_device_list(libusb_ctx, &device_list); | |
assert(cnt >= 0); | |
for (size_t device_index = 0; device_list[device_index]; ++device_index) | |
{ | |
memset(probe, 0, sizeof(*probe)); | |
libusb_device *const device = device_list[device_index]; | |
struct libusb_device_descriptor device_descriptor; | |
const int result = libusb_get_device_descriptor(device, &device_descriptor); | |
if (result < 0) | |
{ | |
fprintf(stderr, "Failed to get device descriptor (%d): %s\n", result, libusb_error_name(result)); | |
return NULL; | |
} | |
if (!check_cmsis_interface_type(device, probe)) | |
{ | |
continue; | |
} | |
printf("In EP: 0x%02x Out EP: 0x%02x Interface: %d Max packet length: %d\n", | |
probe->in_ep, probe->out_ep, probe->interface_num, probe->max_packet_length); | |
printf("Opening...\n"); | |
int error; | |
error = libusb_open(device, &handle); | |
if (error != 0) | |
{ | |
fprintf(stderr, "Unable to open: %s (%d)\n", libusb_error_name(error), error); | |
assert(error); | |
} | |
printf("Claiming...\n"); | |
error = libusb_claim_interface(handle, probe->interface_num); | |
if (error != 0) | |
{ | |
fprintf(stderr, "Unable to claim: %s (%d)\n", libusb_error_name(error), error); | |
assert(error); | |
} | |
probe->libusb_ctx = libusb_ctx; | |
probe->libusb_dev = device; | |
probe->handle = handle; | |
break; | |
} | |
libusb_free_device_list(device_list, (int)cnt); | |
if (probe->handle) | |
{ | |
return probe; | |
} | |
else | |
{ | |
free(probe); | |
return NULL; | |
} | |
} | |
int main() | |
{ | |
struct libusb_context *libusb_ctx; | |
libusb_init(&libusb_ctx); | |
printf("Finding...\n"); | |
bmda_probe_s *probe = find_cmsis_dap(libusb_ctx); | |
assert(probe); | |
// ID_DAP_Info | |
uint8_t request[] = {0 /* ID_DAP_Info */, 2 /* DAP_ID_PRODUCT */}; | |
uint8_t response[64]; | |
memset(response, 0, sizeof(response)); | |
int bytes_transferred = 0; | |
int error; | |
error = libusb_bulk_transfer(probe->handle, probe->out_ep, request, sizeof(request), &bytes_transferred, 0); | |
if (error != 0) | |
{ | |
fprintf(stderr, "Unable to send data: %s (%d)\n", libusb_error_name(error), error); | |
assert(error); | |
} | |
printf("Transferred %d bytes out (DAP_ID_PRODUCT)\n", bytes_transferred); | |
request[1] = 4; | |
error = libusb_bulk_transfer(probe->handle, probe->out_ep, request, sizeof(request), &bytes_transferred, 0); | |
if (error != 0) | |
{ | |
fprintf(stderr, "Unable to send data: %s (%d)\n", libusb_error_name(error), error); | |
assert(error); | |
} | |
printf("Transferred %d bytes out (DAP_ID_FW_VER)\n", bytes_transferred); | |
error = libusb_bulk_transfer(probe->handle, probe->in_ep, response, sizeof(response), &bytes_transferred, 0); | |
if (error != 0) | |
{ | |
fprintf(stderr, "Unable to receive data: %s (%d)\n", libusb_error_name(error), error); | |
assert(error); | |
} | |
if (bytes_transferred > 64) | |
{ | |
fprintf(stderr, "Transferred too many bytes! Expected 64 bytes max, got %d bytes (0x%08x)", bytes_transferred, bytes_transferred); | |
assert(bytes_transferred); | |
} | |
printf("Response was %d bytes: ", bytes_transferred); | |
for (int i = 0; i < bytes_transferred; i += 1) | |
{ | |
printf(" 0x%02x", response[i]); | |
} | |
printf("\n"); | |
error = libusb_bulk_transfer(probe->handle, probe->in_ep, response, sizeof(response), &bytes_transferred, 0); | |
if (error != 0) | |
{ | |
fprintf(stderr, "Unable to receive data: %s (%d)\n", libusb_error_name(error), error); | |
assert(error); | |
} | |
if (bytes_transferred > 64) | |
{ | |
fprintf(stderr, "Transferred too many bytes! Expected 64 bytes max, got %d bytes (0x%08x)", bytes_transferred, bytes_transferred); | |
assert(bytes_transferred); | |
} | |
printf("Response was %d bytes: ", bytes_transferred); | |
for (int i = 0; i < bytes_transferred; i += 1) | |
{ | |
printf(" 0x%02x", response[i]); | |
} | |
printf("\n"); | |
libusb_close(probe->handle); | |
free(probe); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment