Exemplo n.º 1
0
static dc_status_t serial_ftdi_read (void **userdata, void *data, size_t size, size_t *actual)
{
	ftdi_serial_t *device = (ftdi_serial_t*) *userdata;

	if (device == NULL)
		return DC_STATUS_INVALIDARGS;

	// The total timeout.
	long timeout = device->timeout;

	// Simulate blocking read as 10s timeout
	if (timeout == -1)
		timeout = 10000;

	int backoff = 1;
	int slept = 0;
	unsigned int nbytes = 0;
	while (nbytes < size) {
		int n = ftdi_read_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes);
		if (n < 0) {
			if (n == LIBUSB_ERROR_INTERRUPTED)
				continue; //Retry.
			ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
			return DC_STATUS_IO; //Error during read call.
		} else if (n == 0) {
			// Exponential backoff.
			if (slept >= timeout) {
				ERROR(device->context, "%s", "FTDI read timed out.");
				return DC_STATUS_TIMEOUT;
			}
			serial_ftdi_sleep (device, backoff);
			slept += backoff;
			backoff *= 2;
			if (backoff + slept > timeout)
				backoff = timeout - slept;
		} else {
			// Reset backoff to 1 on success.
			backoff = 1;
		}

		nbytes += n;
	}

	INFO (device->context, "Read %d bytes", nbytes);

	if (actual)
		*actual = nbytes;

	return DC_STATUS_SUCCESS;
}
Exemplo n.º 2
0
static dc_status_t serial_ftdi_read (void *io, void *data, size_t size, size_t *actual)
{
	ftdi_serial_t *device = io;

	if (device == NULL)
		return DC_STATUS_INVALIDARGS;

	// The total timeout.
	long timeout = device->timeout;

	// Simulate blocking read as 10s timeout
	if (timeout == -1)
		timeout = 10000;

	unsigned int start_time = serial_ftdi_get_msec();
	unsigned int nbytes = 0;
	while (nbytes < size) {
		int n = ftdi_read_data (device->ftdi_ctx, (unsigned char *) data + nbytes, size - nbytes);
		if (n < 0) {
			if (n == LIBUSB_ERROR_INTERRUPTED)
				continue; //Retry.
			ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
			return DC_STATUS_IO; //Error during read call.
		} else if (n == 0) {
			if (serial_ftdi_get_msec() - start_time > timeout) {
				ERROR(device->context, "%s", "FTDI read timed out.");
				return DC_STATUS_TIMEOUT;
			}
			serial_ftdi_sleep (device, 1);
		}

		nbytes += n;
	}

	INFO (device->context, "Read %d bytes", nbytes);

	if (actual)
		*actual = nbytes;

	return DC_STATUS_SUCCESS;
}
Exemplo n.º 3
0
static dc_status_t serial_ftdi_write (void **userdata, const void *data, size_t size, size_t *actual)
{
	ftdi_serial_t *device = (ftdi_serial_t*) *userdata;

	if (device == NULL)
		return DC_STATUS_INVALIDARGS;

	struct timeval tve, tvb;
	if (device->halfduplex) {
		// Get the current time.
		if (gettimeofday (&tvb, NULL) != 0) {
			SYSERROR (device->context, errno);
			return DC_STATUS_IO;
		}
	}

	unsigned int nbytes = 0;
	while (nbytes < size) {

		int n = ftdi_write_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes);
		if (n < 0) {
			if (n == LIBUSB_ERROR_INTERRUPTED)
				continue; // Retry.
			ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
			return DC_STATUS_IO; // Error during write call.
		} else if (n == 0) {
			break; // EOF.
		}

		nbytes += n;
	}

	if (device->halfduplex) {
		// Get the current time.
		if (gettimeofday (&tve, NULL) != 0) {
			SYSERROR (device->context, errno);
			return DC_STATUS_IO;
		}

		// Calculate the elapsed time (microseconds).
		struct timeval tvt;
		timersub (&tve, &tvb, &tvt);
		unsigned long elapsed = tvt.tv_sec * 1000000 + tvt.tv_usec;

		// Calculate the expected duration (microseconds). A 2 millisecond fudge
		// factor is added because it improves the success rate significantly.
		unsigned long expected = 1000000.0 * device->nbits / device->baudrate * size + 0.5 + 2000;

		// Wait for the remaining time.
		if (elapsed < expected) {
			unsigned long remaining = expected - elapsed;

			// The remaining time is rounded up to the nearest millisecond to
			// match the Windows implementation. The higher resolution is
			// pointless anyway, since we already added a fudge factor above.
			serial_ftdi_sleep (device, (remaining + 999) / 1000);
		}
	}

	INFO (device->context, "Wrote %d bytes", nbytes);

	if (actual)
		*actual = nbytes;

	return DC_STATUS_SUCCESS;
}