/** * Write data of a certain length to the LA8's FTDI device. * * @param devc The struct containing private per-device-instance data. Must not * be NULL. devc->ftdic must not be NULL either. * @param buf The buffer containing the data to write. Must not be NULL. * @param size The number of bytes to write. Must be >= 0. * @return The number of bytes written, or a negative value upon errors. */ SR_PRIV int la8_write(struct dev_context *devc, uint8_t *buf, int size) { int bytes_written; /* Note: Caller checked that devc and devc->ftdic != NULL. */ if (!buf) { sr_err("%s: buf was NULL.", __func__); return SR_ERR_ARG; } if (size < 0) { sr_err("%s: size was < 0.", __func__); return SR_ERR_ARG; } bytes_written = ftdi_write_data(devc->ftdic, buf, size); if (bytes_written < 0) { sr_err("%s: ftdi_write_data: (%d) %s.", __func__, bytes_written, ftdi_get_error_string(devc->ftdic)); (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ } else if (bytes_written != size) { sr_err("%s: bytes to write: %d, bytes written: %d.", __func__, size, bytes_written); (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ } return bytes_written; }
static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; if (!(devc = sdi->priv)) { sr_err("%s: sdi->priv was NULL.", __func__); return SR_ERR_BUG; } sr_dbg("Opening LA8 device (%04x:%04x).", USB_VENDOR_ID, devc->usb_pid); /* Open the device. */ if ((ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, devc->usb_pid, USB_DESCRIPTION, NULL)) < 0) { sr_err("%s: ftdi_usb_open_desc: (%d) %s", __func__, ret, ftdi_get_error_string(devc->ftdic)); (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ return SR_ERR; } sr_dbg("Device opened successfully."); /* Purge RX/TX buffers in the FTDI chip. */ if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) { sr_err("%s: ftdi_usb_purge_buffers: (%d) %s", __func__, ret, ftdi_get_error_string(devc->ftdic)); (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ goto err_dev_open_close_ftdic; } sr_dbg("FTDI buffers purged successfully."); /* Enable flow control in the FTDI chip. */ if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) { sr_err("%s: ftdi_setflowcontrol: (%d) %s", __func__, ret, ftdi_get_error_string(devc->ftdic)); (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ goto err_dev_open_close_ftdic; } sr_dbg("FTDI flow control enabled successfully."); /* Wait 100ms. */ g_usleep(100 * 1000); sdi->status = SR_ST_ACTIVE; return SR_OK; err_dev_open_close_ftdic: (void) la8_close(devc); /* Log, but ignore errors. */ return SR_ERR; }
static int dev_close(struct sr_dev_inst *sdi) { struct dev_context *devc; devc = sdi->priv; if (sdi->status == SR_ST_ACTIVE) { sr_dbg("Status ACTIVE, closing device."); (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ } else { sr_spew("Status not ACTIVE, nothing to do."); } sdi->status = SR_ST_INACTIVE; return SR_OK; }
/** * Reset the ChronoVu LA8. * * The LA8 must be reset after a failed read/write operation or upon timeouts. * * @param devc The struct containing private per-device-instance data. * @return SR_OK upon success, SR_ERR upon failure. */ SR_PRIV int la8_reset(struct dev_context *devc) { uint8_t buf[BS]; time_t done, now; int bytes_read; if (!devc) { sr_err("%s: devc was NULL.", __func__); return SR_ERR_ARG; } if (!devc->ftdic) { sr_err("%s: devc->ftdic was NULL.", __func__); return SR_ERR_ARG; } sr_dbg("Resetting the device."); /* * Purge pending read data from the FTDI hardware FIFO until * no more data is left, or a timeout occurs (after 20s). */ done = 20 + time(NULL); do { /* TODO: Ignore errors? Check for < 0 at least! */ bytes_read = la8_read(devc, (uint8_t *)&buf, BS); now = time(NULL); } while ((done > now) && (bytes_read > 0)); /* Reset the LA8 sequencer logic and close the USB port. */ (void) la8_close_usb_reset_sequencer(devc); /* Ignore errors. */ sr_dbg("Device reset finished."); return SR_OK; }