int slogic_open(struct slogic_ctx *handle, int logic_index){ int err,i; size_t cnt; libusb_device **list; libusb_device *found = NULL; struct libusb_device_descriptor descriptor; cnt = libusb_get_device_list(handle->usb_context, &list); i = 0; if (cnt < 0) { log_printf( DEBUG, "Failed to get a list of devices\n"); return 0; } for (i = 0; i < cnt; i++) { libusb_device *device = list[i]; err = libusb_get_device_descriptor(device, &descriptor); if (err) { log_printf( DEBUG, "libusb_get_device_descriptor: %s\n", usbutil_error_to_string(err)); libusb_free_device_list(list, 1); return 0; } if ((descriptor.idVendor == USB_VENDOR_ID) && (descriptor.idProduct == USB_PRODUCT_ID)) { found = device; usbutil_dump_device_descriptor(&descriptor); break; } } if (!found) { log_printf( DEBUG, "Device not found\n"); libusb_free_device_list(list, 1); return 0; } if ((err = libusb_open(found, &handle->device_handle))) { log_printf( DEBUG, "Failed OPEN the device: %s\n", usbutil_error_to_string(err)); libusb_free_device_list(list, 1); return 0; } log_printf( DEBUG, "libusb_open: %s\n", usbutil_error_to_string(err)); if ((err = claim_device(handle->device_handle, 0)) != 0) { log_printf( DEBUG, "Failed to claim the usb interface: %s\n", usbutil_error_to_string(err)); libusb_free_device_list(list, 1); return 0; } if (!handle->device_handle) { log_printf( ERR, "Failed to open the device\n"); libusb_free_device_list(list, 1); return -1; } libusb_free_device_list(list, 1); handle->dev = libusb_get_device(handle->device_handle); handle->transfers = calloc(1,sizeof(struct logic_transfers) * handle->n_transfer_buffers); return 0; }
/* * This method looks if the kernel already has a driver attached to the device. if so I will take over the device. */ static enum libusb_error claim_device(libusb_device_handle * dev, int interface) { enum libusb_error err; if (libusb_kernel_driver_active(dev, interface)) { fprintf(stderr, "A kernel has claimed the interface, detaching it...\n"); if ((err = libusb_detach_kernel_driver(dev, interface)) != 0) { fprintf(stderr, "Failed to Disconnected the OS driver: %s\n", usbutil_error_to_string(err)); return err; } } if ((err = libusb_set_configuration(dev, 1))) { fprintf(stderr, "libusb_set_configuration: %s\n", usbutil_error_to_string(err)); return err; } fprintf(stderr, "libusb_set_configuration: %s\n", usbutil_error_to_string(err)); /* claim interface */ if ((err = libusb_claim_interface(dev, interface))) { fprintf(stderr, "Claim interface error: %s\n", usbutil_error_to_string(err)); return err; } fprintf(stderr, "libusb_claim_interface: %s\n", usbutil_error_to_string(err)); if ((err = libusb_set_interface_alt_setting(dev, interface, 0))) { fprintf(stderr, "libusb_set_interface_alt_setting: %s\n", usbutil_error_to_string(err)); return err; } fprintf(stderr, "libusb_set_interface_alt_setting: %s\n", usbutil_error_to_string(err)); return LIBUSB_SUCCESS; }
int slogic_readbyte(struct slogic_handle *handle, unsigned char *out) { int ret; unsigned char command = 0x05; int transferred; ret = libusb_bulk_transfer(handle->device_handle, COMMAND_OUT_ENDPOINT, &command, 1, &transferred, 100); if (ret) { log_printf(&logger, ERR, "libusb_bulk_transfer (out): %s\n", usbutil_error_to_string(ret)); return ret; } ret = libusb_bulk_transfer(handle->device_handle, COMMAND_IN_ENDPOINT, out, 1, &transferred, 100); if (ret) { log_printf(&logger, ERR, "libusb_bulk_transfer (in): %s\n", usbutil_error_to_string(ret)); return ret; } return 0; }
int slogic_pump_data(struct slogic_ctx *handle, unsigned int transfer_id){ int retval; if((retval = libusb_submit_transfer(handle->transfers[transfer_id].transfer))){ handle->transfers[transfer_id].state = 1; log_printf( ERR, "libusb_submit_transfer: %s\n", usbutil_error_to_string(retval)); handle->recording_state = UNKNOWN; return 1; } return 0; }
int slogic_execute_recording(struct slogic_ctx *handle){ int transfer_id,retval,ret; struct timeval timeout; handle->recording_state = WARMING_UP; for (transfer_id = 0; transfer_id < handle->n_transfer_buffers; transfer_id++) { slogic_prime_data(handle, transfer_id); } handle->recording_state = RUNNING; for (transfer_id = 0; transfer_id < handle->n_transfer_buffers; transfer_id++) { if(!transfer_id){ slogic_set_capture_async(handle); } slogic_pump_data(handle, transfer_id); handle->transfer_count++; } while (handle->recording_state == RUNNING) { timeout.tv_sec = 1; if((ret = libusb_handle_events_timeout(handle->usb_context, &timeout))){ log_printf( ERR, "libusb_handle_events: %s\n", usbutil_error_to_string(ret)); break; } } //spindown! if (handle->recording_state == COMPLETED_SUCCESSFULLY) { log_printf(INFO, "Capture Success!\n"); }else{ log_printf( ERR, "Capture Fail! recording_state=%d\n", handle->recording_state); retval = 1; } return retval; }
int slogic_set_capture(struct slogic_ctx *handle){ struct libusb_transfer *transfer; struct slogic_command command; int ret,transferred; transfer = libusb_alloc_transfer(0); if (transfer == NULL) { log_printf( ERR, "libusb_alloc_transfer failed\n"); handle->recording_state = UNKNOWN; ret = 1; return ret; } command.command = SALEAE_LOGIC_COMMAND_SET_SAMPLE_DELAY; command.sample_delay = handle->sample_rate->sample_delay; if((ret = libusb_bulk_transfer(handle->device_handle, SALEAE_COMMAND_OUT_ENDPOINT, (unsigned char *)&command, sizeof(command), &transferred, handle->transfer_timeout))){ log_printf( ERR, "libusb_bulk_transfer (in): %s\n", usbutil_error_to_string(ret)); return ret; } return 0; }
int slogic_execute_recording(struct slogic_handle *handle, struct slogic_recording *recording) { /* TODO: validate recording */ int retval =0; struct libusb_transfer *transfer; unsigned char *buffer; int counter; int ret; struct slogic_internal_recording *internal_recording = allocate_internal_recording(handle, recording); /* * TODO: We probably want to tune the transfer buffer size to a sane * default based on the sampling rate. If transfer_buffer_size is * samples per second / 10 we can expect 10 transfers per second which * should be sufficient for a user application to be responsive while * not having too many transfers per second. * - Trygve */ log_printf(&logger, DEBUG, "Starting recording...\n"); log_printf(&logger, DEBUG, "Transfer buffers: %d\n", internal_recording->n_transfer_buffers); log_printf(&logger, DEBUG, "Transfer buffer size: %zu\n", handle->transfer_buffer_size); log_printf(&logger, DEBUG, "Transfer timeout: %u\n", handle->transfer_timeout); /* Pre-allocate transfers */ for (counter = 0; counter < internal_recording->n_transfer_buffers; counter++) { buffer = malloc(handle->transfer_buffer_size); assert(buffer); transfer = libusb_alloc_transfer(0); if (transfer == NULL) { log_printf(&logger, ERR, "libusb_alloc_transfer failed\n"); recording->recording_state = UNKNOWN; retval = 1; return retval; } libusb_fill_bulk_transfer(transfer, handle->device_handle, STREAMING_DATA_IN_ENDPOINT, buffer, handle->transfer_buffer_size, slogic_read_samples_callback, &internal_recording->transfers[counter], handle->transfer_timeout); internal_recording->transfers[counter].internal_recording = internal_recording; internal_recording->transfers[counter].transfer = transfer; } recording->recording_state = WARMING_UP; internal_recording->done = false; /* Submit all transfers */ for (counter = 0; counter < internal_recording->n_transfer_buffers; counter++) { internal_recording->transfers[counter].seq = tcounter++; ret = libusb_submit_transfer(internal_recording->transfers[counter].transfer); if (ret) { log_printf(&logger, ERR, "libusb_submit_transfer: %s\n", usbutil_error_to_string(ret)); recording->recording_state = UNKNOWN; retval =1; return retval; } } log_printf(&logger, DEBUG, "sample_delay=%d\n", recording->sample_rate->sample_delay); struct timeval start; assert(gettimeofday(&start, NULL) == 0); struct timeval timeout = { 1, 0 }; while (!internal_recording->done) { ret = libusb_handle_events_timeout(handle->context, &timeout); if (ret) { log_printf(&logger, ERR, "libusb_handle_events: %s\n", usbutil_error_to_string(ret)); break; } } struct timeval end; assert(gettimeofday(&end, NULL) == 0); for (counter = 0; counter < internal_recording->n_transfer_buffers; counter++) { libusb_cancel_transfer(internal_recording->transfers[counter].transfer); libusb_free_transfer(internal_recording->transfers[counter].transfer); internal_recording->transfers[counter].transfer = NULL; } if (internal_recording->recording->recording_state != COMPLETED_SUCCESSFULLY) { log_printf(&logger, ERR, "FAIL! recording_state=%d\n", internal_recording->recording->recording_state); retval =1; } else { log_printf(&logger, DEBUG, "SUCCESS!\n"); } log_printf(&logger, DEBUG, "Total number of samples read: %i\n", internal_recording->sample_count); log_printf(&logger, DEBUG, "Total number of transfers: %i\n", internal_recording->transfer_counter); int sec = end.tv_sec - start.tv_sec; int usec = (end.tv_usec - start.tv_usec) / 1000; if (usec < 0) { sec--; usec = 1 - usec; } log_printf(&logger, DEBUG, "Time elapsed: %d.%03ds\n", sec, usec); free_internal_recording(internal_recording); return retval; }
/* * Is some kind of synchronization required here? libusb is not supposed to * create its own threads, but I've seen mentions of an event thread in debug * output - Trygve */ void slogic_read_samples_callback(struct libusb_transfer *transfer) { struct slogic_transfer *slogic_transfer = transfer->user_data; struct slogic_internal_recording *internal_recording = slogic_transfer->internal_recording; struct slogic_recording *recording = internal_recording->recording; assert(slogic_transfer); if (internal_recording->done) { /* * This will happen if there was more incoming transfers when the * callback wanted to stop recording. The outer method will handle * the cleanup so just return here. */ return; } slogic_transfer->internal_recording->transfer_counter++; /* * Handle the success as a special case, the failure logic is basically: abort. * Note that this does not indicate that the entire amount of requested data was transferred. */ if (transfer->status == LIBUSB_TRANSFER_COMPLETED || recording->recording_state == RUNNING) { internal_recording->sample_count += transfer->actual_length; bool more = recording->on_data_callback(transfer->buffer, transfer->actual_length, recording->user_data); if (!more) { internal_recording->recording->recording_state = COMPLETED_SUCCESSFULLY; internal_recording->done = true; log_printf(&logger, DEBUG, "Callback signalled completion\n"); return; } int old_seq = slogic_transfer->seq; slogic_transfer->seq = tcounter++; int ret = libusb_submit_transfer(slogic_transfer->transfer); if (ret) { log_printf(&logger, ERR, "libusb_submit_transfer: %s\n", usbutil_error_to_string(ret)); internal_recording->recording->recording_state = UNKNOWN; internal_recording->done = true; return; } log_printf(&logger, DEBUG, "Rescheduled transfer %d as %d\n", old_seq, slogic_transfer->seq); return; } if (internal_recording->transfer_counter == 200) { struct libusb_transfer *transfer; unsigned char command[] = { 0x01, recording->sample_rate->sample_delay }; transfer = libusb_alloc_transfer(0 /* we use bulk */ ); assert(transfer); libusb_fill_bulk_transfer(transfer, internal_recording->shandle->device_handle, 0x01, command, 2, slogic_read_samples_callback_start_log, recording, 40); libusb_submit_transfer(transfer); } if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { if (recording->recording_state == RUNNING){ slogic_transfer->internal_recording->timeout_counter++; } if (internal_recording->timeout_counter < 1000){ slogic_transfer->seq = tcounter++; int ret = libusb_submit_transfer(slogic_transfer->transfer); if (ret) { log_printf(&logger, ERR, "libusb_submit_transfer: %s\n", usbutil_error_to_string(ret)); internal_recording->recording->recording_state = UNKNOWN; internal_recording->done = true; } return; } } internal_recording->done = true; log_printf(&logger, ERR, "Transfer failed: %s\n", usbutil_transfer_status_to_string(transfer->status)); switch (transfer->status) { default: /* Make the compiler shut up */ case LIBUSB_TRANSFER_COMPLETED: /* * This shouldn't happen in slogic. * From libusb docs: * For bulk/interrupt endpoints: halt condition detected (endpoint stalled). * For control endpoints: control request not supported. */ case LIBUSB_TRANSFER_STALL: /* We don't cancel transfers without setting should_run = 0 so this should not happen */ case LIBUSB_TRANSFER_CANCELLED: case LIBUSB_TRANSFER_ERROR: recording->recording_state = UNKNOWN; break; case LIBUSB_TRANSFER_TIMED_OUT: recording->recording_state = TIMEOUT; break; case LIBUSB_TRANSFER_NO_DEVICE: recording->recording_state = DEVICE_GONE; break; case LIBUSB_TRANSFER_OVERFLOW: recording->recording_state = OVERFLOW; break; } }
/* * Iterates over the usb devices on the usb busses and returns a handle to the * first device found that matches the predefined vendor and product id */ libusb_device_handle *open_device(libusb_context * ctx, int vendor_id, int product_id) { // discover devices libusb_device **list; libusb_device *found = NULL; libusb_device_handle *device_handle = NULL; struct libusb_device_descriptor descriptor; size_t cnt = libusb_get_device_list(ctx, &list); size_t i = 0; int err = 0; if (cnt < 0) { fprintf(stderr, "Failed to get a list of devices\n"); return NULL; } for (i = 0; i < cnt; i++) { libusb_device *device = list[i]; err = libusb_get_device_descriptor(device, &descriptor); if (err) { fprintf(stderr, "libusb_get_device_descriptor: %s\n", usbutil_error_to_string(err)); libusb_free_device_list(list, 1); return NULL; } if ((descriptor.idVendor == vendor_id) && (descriptor.idProduct == product_id)) { found = device; usbutil_dump_device_descriptor(stderr, &descriptor); break; } } if (!found) { fprintf(stderr, "Device not found\n"); libusb_free_device_list(list, 1); return NULL; } if ((err = libusb_open(found, &device_handle))) { fprintf(stderr, "Failed OPEN the device: %s\n", usbutil_error_to_string(err)); libusb_free_device_list(list, 1); return NULL; } fprintf(stderr, "libusb_open: %s\n", usbutil_error_to_string(err)); libusb_free_device_list(list, 1); if ((err = claim_device(device_handle, 0)) != 0) { fprintf(stderr, "Failed to claim the usb interface: %s\n", usbutil_error_to_string(err)); return NULL; } struct libusb_config_descriptor *config_descriptor; err = libusb_get_active_config_descriptor(found, &config_descriptor); if (err) { fprintf(stderr, "libusb_get_active_config_descriptor: %s\n", usbutil_error_to_string(err)); return NULL; } fprintf(stderr, "Active configuration:%d\n", config_descriptor->bConfigurationValue); libusb_free_config_descriptor(config_descriptor); fprintf(stderr, "Available configurations (%d):\n", descriptor.bNumConfigurations); for (i = 0; i < descriptor.bNumConfigurations; i++) { err = libusb_get_config_descriptor(found, i, &config_descriptor); if (err) { fprintf(stderr, "libusb_get_config_descriptor: %s\n", usbutil_error_to_string(err)); return NULL; } usbutil_dump_config_descriptor(stderr, config_descriptor); libusb_free_config_descriptor(config_descriptor); } return device_handle; }