mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	Re-indent and style up serial ftdi
Signed-off-by: Anton Lundin <glance@acc.umu.se> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
		
							parent
							
								
									f33843ed35
								
							
						
					
					
						commit
						3104508247
					
				
					 1 changed files with 315 additions and 351 deletions
				
			
		
							
								
								
									
										666
									
								
								serial_ftdi.c
									
										
									
									
									
								
							
							
						
						
									
										666
									
								
								serial_ftdi.c
									
										
									
									
									
								
							|  | @ -46,31 +46,30 @@ | |||
| #define MAX_BACKOFF 500 // Max milliseconds to wait before timing out.
 | ||||
| 
 | ||||
| struct serial_t { | ||||
|         /* Library ftdi_ctx. */ | ||||
|         dc_context_t *context; | ||||
|         /*
 | ||||
|          * The file descriptor corresponding to the serial port. | ||||
|          * Also a libftdi_ftdi_ctx could be used? | ||||
|          */ | ||||
|         struct ftdi_context *ftdi_ctx; | ||||
|         long timeout; | ||||
|         /*
 | ||||
|          * Serial port settings are saved into this variable immediately | ||||
|          * after the port is opened. These settings are restored when the | ||||
|          * serial port is closed. | ||||
| 	/* Library ftdi_ctx. */ | ||||
| 	dc_context_t *context; | ||||
| 	/*
 | ||||
| 	 * The file descriptor corresponding to the serial port. | ||||
| 	 * Also a libftdi_ftdi_ctx could be used? | ||||
| 	 */ | ||||
| 	struct ftdi_context *ftdi_ctx; | ||||
| 	long timeout; | ||||
| 	/*
 | ||||
| 	 * Serial port settings are saved into this variable immediately | ||||
| 	 * after the port is opened. These settings are restored when the | ||||
| 	 * serial port is closed. | ||||
| 	 * Saving this using libftdi context or libusb. Search further. | ||||
| 	 * Custom implementation using libftdi functions could be done. | ||||
|          */ | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* Half-duplex settings */ | ||||
|         int halfduplex; | ||||
|         unsigned int baudrate; | ||||
|         unsigned int nbits; | ||||
| 	int halfduplex; | ||||
| 	unsigned int baudrate; | ||||
| 	unsigned int nbits; | ||||
| }; | ||||
| 
 | ||||
| // Used internally for opening ftdi devices
 | ||||
| int | ||||
| open_ftdi_device (struct ftdi_context *ftdi_ctx) | ||||
| int open_ftdi_device (struct ftdi_context *ftdi_ctx) | ||||
| { | ||||
| 	int accepted_pids[] = { 0x6001, 0x6010, 0x6011, // Suunto (Smart Interface), Heinrichs Weikamp
 | ||||
| 		0xF460, // Oceanic
 | ||||
|  | @ -91,11 +90,10 @@ open_ftdi_device (struct ftdi_context *ftdi_ctx) | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| serial_enumerate (serial_callback_t callback, void *userdata) | ||||
| int serial_enumerate (serial_callback_t callback, void *userdata) | ||||
| { | ||||
| 	// Unimplemented.
 | ||||
|         return -1; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -103,21 +101,19 @@ serial_enumerate (serial_callback_t callback, void *userdata) | |||
| // Open the serial port.
 | ||||
| // Initialise ftdi_context and use it to open the device
 | ||||
| //
 | ||||
| 
 | ||||
| int | ||||
| serial_open (serial_t **out, dc_context_t *context, const char* name) | ||||
| int serial_open (serial_t **out, dc_context_t *context, const char* name) | ||||
| { | ||||
| 	if (out == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (context, "Open: name=%s", name ? name : ""); | ||||
| 	INFO (context, "Open: name=%s", name ? name : ""); | ||||
| 
 | ||||
|         // Allocate memory.
 | ||||
|         serial_t *device = (serial_t *) malloc (sizeof (serial_t)); | ||||
|         if (device == NULL) { | ||||
|                 SYSERROR (context, errno); | ||||
|                 return -1; // ENOMEM (Not enough space)
 | ||||
|         } | ||||
| 	// Allocate memory.
 | ||||
| 	serial_t *device = (serial_t *) malloc (sizeof (serial_t)); | ||||
| 	if (device == NULL) { | ||||
| 		SYSERROR (context, errno); | ||||
| 		return -1; // ENOMEM (Not enough space)
 | ||||
| 	} | ||||
| 
 | ||||
| 	struct ftdi_context *ftdi_ctx = ftdi_new(); | ||||
| 	if (ftdi_ctx == NULL) { | ||||
|  | @ -125,223 +121,212 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) | |||
| 		return -1; // ENOMEM (Not enough space)
 | ||||
| 	} | ||||
| 
 | ||||
|         // Library context.
 | ||||
|         device->context = context; | ||||
| 	// Library context.
 | ||||
| 	device->context = context; | ||||
| 
 | ||||
|         // Default to blocking reads.
 | ||||
|         device->timeout = -1; | ||||
| 	// Default to blocking reads.
 | ||||
| 	device->timeout = -1; | ||||
| 
 | ||||
|         // Default to full-duplex.
 | ||||
|         device->halfduplex = 0; | ||||
|         device->baudrate = 0; | ||||
|         device->nbits = 0; | ||||
| 	// Default to full-duplex.
 | ||||
| 	device->halfduplex = 0; | ||||
| 	device->baudrate = 0; | ||||
| 	device->nbits = 0; | ||||
| 
 | ||||
| 	// Initialize device ftdi context
 | ||||
|         ftdi_init(ftdi_ctx); | ||||
| 	ftdi_init(ftdi_ctx); | ||||
| 
 | ||||
|         if (ftdi_set_interface(ftdi_ctx,INTERFACE_ANY)) { | ||||
|                 ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 	if (ftdi_set_interface(ftdi_ctx,INTERFACE_ANY)) { | ||||
| 		ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         if (open_ftdi_device(ftdi_ctx) < 0) { | ||||
|                 ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
|                 return -1; | ||||
|         } | ||||
| 
 | ||||
|         if (ftdi_usb_reset(ftdi_ctx)) { | ||||
|                 ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 	if (open_ftdi_device(ftdi_ctx) < 0) { | ||||
| 		ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         if (ftdi_usb_purge_buffers(ftdi_ctx)) { | ||||
|                 ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 	if (ftdi_usb_reset(ftdi_ctx)) { | ||||
| 		ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ftdi_usb_purge_buffers(ftdi_ctx)) { | ||||
| 		ERROR (context, ftdi_get_error_string(ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	device->ftdi_ctx = ftdi_ctx; | ||||
|         *out = device; | ||||
| 	*out = device; | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Close the serial port.
 | ||||
| //
 | ||||
| 
 | ||||
| int | ||||
| serial_close (serial_t *device) | ||||
| int serial_close (serial_t *device) | ||||
| { | ||||
| 	if (device == NULL) | ||||
|                 return 0; | ||||
| 		return 0; | ||||
| 
 | ||||
|         // Restore the initial terminal attributes.
 | ||||
| 	// Restore the initial terminal attributes.
 | ||||
| 	// See if it is possible using libusb or libftdi
 | ||||
| 
 | ||||
| 	int ret = ftdi_usb_close(device->ftdi_ctx); | ||||
| 	if (ret < 0) { | ||||
| 		ERROR (device->context, "Unable to close the ftdi device : %d (%s)\n", | ||||
| 				ret, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		       ret, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ftdi_free(device->ftdi_ctx); | ||||
| 
 | ||||
|         // Free memory.
 | ||||
|         free (device); | ||||
| 	// Free memory.
 | ||||
| 	free (device); | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol).
 | ||||
| //
 | ||||
| 
 | ||||
| int | ||||
| serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol) | ||||
| int serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol) | ||||
| { | ||||
| 	if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", | ||||
|                 baudrate, databits, parity, stopbits, flowcontrol); | ||||
| 	INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", | ||||
| 	      baudrate, databits, parity, stopbits, flowcontrol); | ||||
| 
 | ||||
|         enum ftdi_bits_type ft_bits; | ||||
|         enum ftdi_stopbits_type ft_stopbits; | ||||
|         enum ftdi_parity_type ft_parity; | ||||
| 	enum ftdi_bits_type ft_bits; | ||||
| 	enum ftdi_stopbits_type ft_stopbits; | ||||
| 	enum ftdi_parity_type ft_parity; | ||||
| 
 | ||||
|         if (ftdi_set_baudrate(device->ftdi_ctx, baudrate) < 0) { | ||||
|                 ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 	if (ftdi_set_baudrate(device->ftdi_ctx, baudrate) < 0) { | ||||
| 		ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         // Set the character size.
 | ||||
|         switch (databits) { | ||||
|         case 7: | ||||
|                 ft_bits = BITS_7; | ||||
|                 break; | ||||
|         case 8: | ||||
|                 ft_bits = BITS_8; | ||||
|                 break; | ||||
|         default: | ||||
|                 return -1; | ||||
|         } | ||||
| 	// Set the character size.
 | ||||
| 	switch (databits) { | ||||
| 	case 7: | ||||
| 		ft_bits = BITS_7; | ||||
| 		break; | ||||
| 	case 8: | ||||
| 		ft_bits = BITS_8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         // Set the parity type.
 | ||||
|         switch (parity) { | ||||
|         case SERIAL_PARITY_NONE: // No parity
 | ||||
|                 ft_parity = NONE; | ||||
|                 break; | ||||
|         case SERIAL_PARITY_EVEN: // Even parity
 | ||||
|                 ft_parity = EVEN; | ||||
|                 break; | ||||
|         case SERIAL_PARITY_ODD: // Odd parity
 | ||||
|                 ft_parity = ODD; | ||||
|                 break; | ||||
|         default: | ||||
| 	// Set the parity type.
 | ||||
| 	switch (parity) { | ||||
| 	case SERIAL_PARITY_NONE: // No parity
 | ||||
| 		ft_parity = NONE; | ||||
| 		break; | ||||
| 	case SERIAL_PARITY_EVEN: // Even parity
 | ||||
| 		ft_parity = EVEN; | ||||
| 		break; | ||||
| 	case SERIAL_PARITY_ODD: // Odd parity
 | ||||
| 		ft_parity = ODD; | ||||
| 		break; | ||||
| 	default: | ||||
| 
 | ||||
|                 return -1; | ||||
|         } | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         // Set the number of stop bits.
 | ||||
|         switch (stopbits) { | ||||
|         case 1: // One stopbit
 | ||||
|                 ft_stopbits = STOP_BIT_1; | ||||
|                 break; | ||||
|         case 2: // Two stopbits
 | ||||
|                 ft_stopbits = STOP_BIT_2; | ||||
|                 break; | ||||
|         default: | ||||
|                 return -1; | ||||
|         } | ||||
| 	// Set the number of stop bits.
 | ||||
| 	switch (stopbits) { | ||||
| 	case 1: // One stopbit
 | ||||
| 		ft_stopbits = STOP_BIT_1; | ||||
| 		break; | ||||
| 	case 2: // Two stopbits
 | ||||
| 		ft_stopbits = STOP_BIT_2; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	// Set the attributes
 | ||||
|         if (ftdi_set_line_property(device->ftdi_ctx, ft_bits, ft_stopbits, ft_parity)) { | ||||
|                 ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 	if (ftdi_set_line_property(device->ftdi_ctx, ft_bits, ft_stopbits, ft_parity)) { | ||||
| 		ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         // Set the flow control.
 | ||||
|         switch (flowcontrol) { | ||||
|         case SERIAL_FLOWCONTROL_NONE: // No flow control.
 | ||||
|                 if (ftdi_setflowctrl(device->ftdi_ctx, SIO_DISABLE_FLOW_CTRL) < 0) { | ||||
|                         ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
|                 break; | ||||
|         case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control.
 | ||||
|                if (ftdi_setflowctrl(device->ftdi_ctx, SIO_RTS_CTS_HS) < 0) { | ||||
| 	// Set the flow control.
 | ||||
| 	switch (flowcontrol) { | ||||
| 	case SERIAL_FLOWCONTROL_NONE: // No flow control.
 | ||||
| 		if (ftdi_setflowctrl(device->ftdi_ctx, SIO_DISABLE_FLOW_CTRL) < 0) { | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		break; | ||||
|         case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control.
 | ||||
|                 if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_HS) < 0) { | ||||
|                         ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 	case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control.
 | ||||
| 		if (ftdi_setflowctrl(device->ftdi_ctx, SIO_RTS_CTS_HS) < 0) { | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
|                 break; | ||||
|         default: | ||||
|                 return -1; | ||||
|         } | ||||
| 		break; | ||||
| 	case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control.
 | ||||
| 		if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_HS) < 0) { | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         device->baudrate = baudrate; | ||||
|         device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); | ||||
| 	device->baudrate = baudrate; | ||||
| 	device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Configure the serial port (timeouts).
 | ||||
| //
 | ||||
| 
 | ||||
| int | ||||
| serial_set_timeout (serial_t *device, long timeout) | ||||
| int serial_set_timeout (serial_t *device, long timeout) | ||||
| { | ||||
| 	if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (device->context, "Timeout: value=%li", timeout); | ||||
| 	INFO (device->context, "Timeout: value=%li", timeout); | ||||
| 
 | ||||
|         device->timeout = timeout; | ||||
| 	device->timeout = timeout; | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // Configure the serial port (recommended size of the input/output buffers).
 | ||||
| //
 | ||||
| 
 | ||||
| int | ||||
| serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output) | ||||
| int serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output) | ||||
| { | ||||
| 	if (device == NULL) | ||||
|                 return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect)
 | ||||
| 		return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect)
 | ||||
| 
 | ||||
| 	ftdi_read_data_set_chunksize(device->ftdi_ctx, output); | ||||
|         ftdi_write_data_set_chunksize(device->ftdi_ctx, input); | ||||
| 	ftdi_write_data_set_chunksize(device->ftdi_ctx, input); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_set_halfduplex (serial_t *device, int value) | ||||
| int serial_set_halfduplex (serial_t *device, int value) | ||||
| { | ||||
| 	if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
| 	// Most ftdi chips support full duplex operation. ft232rl does.
 | ||||
| 	// Crosscheck other chips.
 | ||||
| 
 | ||||
| 	device->halfduplex = value; | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| serial_set_latency (serial_t *device, unsigned int milliseconds) | ||||
| int serial_set_latency (serial_t *device, unsigned int milliseconds) | ||||
| { | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
|  | @ -351,60 +336,59 @@ serial_set_latency (serial_t *device, unsigned int milliseconds) | |||
| 
 | ||||
| 	if (milliseconds < 1 || milliseconds > 255) | ||||
| 		return -1; | ||||
|         ftdi_set_latency_timer(device->ftdi_ctx, milliseconds); | ||||
| 	ftdi_set_latency_timer(device->ftdi_ctx, milliseconds); | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| serial_read (serial_t *device, void *data, unsigned int size) | ||||
| int serial_read (serial_t *device, void *data, unsigned int size) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         // The total timeout.
 | ||||
|         long timeout = device->timeout; | ||||
| 	// The total timeout.
 | ||||
| 	long timeout = device->timeout; | ||||
| 
 | ||||
|         // The absolute target time.
 | ||||
|         struct timeval tve; | ||||
| 	// The absolute target time.
 | ||||
| 	struct timeval tve; | ||||
| 
 | ||||
| 	static int backoff = 1; | ||||
|         int init = 1; | ||||
|         unsigned int nbytes = 0; | ||||
|         while (nbytes < size) { | ||||
|                 struct timeval tvt; | ||||
|                 if (timeout > 0) { | ||||
|                         struct timeval now; | ||||
|                         if (gettimeofday (&now, NULL) != 0) { | ||||
|                                 SYSERROR (device->context, errno); | ||||
|                                 return -1; | ||||
|                         } | ||||
| 	int init = 1; | ||||
| 	unsigned int nbytes = 0; | ||||
| 	while (nbytes < size) { | ||||
| 		struct timeval tvt; | ||||
| 		if (timeout > 0) { | ||||
| 			struct timeval now; | ||||
| 			if (gettimeofday (&now, NULL) != 0) { | ||||
| 				SYSERROR (device->context, errno); | ||||
| 				return -1; | ||||
| 			} | ||||
| 
 | ||||
|                         if (init) { | ||||
|                                 // Calculate the initial timeout.
 | ||||
|                                 tvt.tv_sec  = (timeout / 1000); | ||||
|                                 tvt.tv_usec = (timeout % 1000) * 1000; | ||||
|                                 // Calculate the target time.
 | ||||
|                                 timeradd (&now, &tvt, &tve); | ||||
|                         } else { | ||||
|                                 // Calculate the remaining timeout.
 | ||||
|                                 if (timercmp (&now, &tve, <)) | ||||
|                                         timersub (&tve, &now, &tvt); | ||||
|                                 else | ||||
|                                         timerclear (&tvt); | ||||
|                         } | ||||
|                         init = 0; | ||||
|                 } else if (timeout == 0) { | ||||
|                         timerclear (&tvt); | ||||
|                 } | ||||
| 			if (init) { | ||||
| 				// Calculate the initial timeout.
 | ||||
| 				tvt.tv_sec  = (timeout / 1000); | ||||
| 				tvt.tv_usec = (timeout % 1000) * 1000; | ||||
| 				// Calculate the target time.
 | ||||
| 				timeradd (&now, &tvt, &tve); | ||||
| 			} else { | ||||
| 				// Calculate the remaining timeout.
 | ||||
| 				if (timercmp (&now, &tve, <)) | ||||
| 					timersub (&tve, &now, &tvt); | ||||
| 				else | ||||
| 					timerclear (&tvt); | ||||
| 			} | ||||
| 			init = 0; | ||||
| 		} else if (timeout == 0) { | ||||
| 			timerclear (&tvt); | ||||
| 		} | ||||
| 
 | ||||
|                 int n = ftdi_read_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes); | ||||
| 		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, ftdi_get_error_string(device->ftdi_ctx)); | ||||
|                         return -1; //Error during read call.
 | ||||
|                 } else if (n == 0) { | ||||
| 			if (n == LIBUSB_ERROR_INTERRUPTED) | ||||
| 				continue; //Retry.
 | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; //Error during read call.
 | ||||
| 		} else if (n == 0) { | ||||
| 			// Exponential backoff.
 | ||||
| 			if (backoff > MAX_BACKOFF) { | ||||
| 				ERROR(device->context, "FTDI read timed out."); | ||||
|  | @ -417,119 +401,113 @@ serial_read (serial_t *device, void *data, unsigned int size) | |||
| 			backoff = 1; | ||||
| 		} | ||||
| 
 | ||||
|                 nbytes += n; | ||||
|         } | ||||
| 		nbytes += n; | ||||
| 	} | ||||
| 
 | ||||
|         HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); | ||||
| 	HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); | ||||
| 
 | ||||
|         return nbytes; | ||||
| 	return nbytes; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_write (serial_t *device, const void *data, unsigned int size) | ||||
| int serial_write (serial_t *device, const void *data, unsigned int size) | ||||
| { | ||||
| 	if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         struct timeval tve, tvb; | ||||
|         if (device->halfduplex) { | ||||
|                 // Get the current time.
 | ||||
|                 if (gettimeofday (&tvb, NULL) != 0) { | ||||
|                         SYSERROR (device->context, errno); | ||||
|                         return -1; | ||||
|                 } | ||||
|         } | ||||
| 	struct timeval tve, tvb; | ||||
| 	if (device->halfduplex) { | ||||
| 		// Get the current time.
 | ||||
| 		if (gettimeofday (&tvb, NULL) != 0) { | ||||
| 			SYSERROR (device->context, errno); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|         unsigned int nbytes = 0; | ||||
|         while (nbytes < size) { | ||||
| 	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, ftdi_get_error_string(device->ftdi_ctx)); | ||||
|                         return -1; // Error during write call.
 | ||||
|                 } else if (n == 0) { | ||||
|                          break; // EOF.
 | ||||
|                 } | ||||
| 		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, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; // Error during write call.
 | ||||
| 		} else if (n == 0) { | ||||
| 			break; // EOF.
 | ||||
| 		} | ||||
| 
 | ||||
|                 nbytes += n; | ||||
|         } | ||||
| 		nbytes += n; | ||||
| 	} | ||||
| 
 | ||||
|         if (device->halfduplex) { | ||||
|                 // Get the current time.
 | ||||
|                 if (gettimeofday (&tve, NULL) != 0) { | ||||
|                         SYSERROR (device->context, errno); | ||||
|                         return -1; | ||||
|                 } | ||||
| 	if (device->halfduplex) { | ||||
| 		// Get the current time.
 | ||||
| 		if (gettimeofday (&tve, NULL) != 0) { | ||||
| 			SYSERROR (device->context, errno); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
|                 // Calculate the elapsed time (microseconds).
 | ||||
|                 struct timeval tvt; | ||||
|                 timersub (&tve, &tvb, &tvt); | ||||
|                 unsigned long elapsed = tvt.tv_sec * 1000000 + tvt.tv_usec; | ||||
| 		// 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; | ||||
| 		// 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; | ||||
| 		// 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_sleep (device, (remaining + 999) / 1000); | ||||
|                 } | ||||
|         } | ||||
| 			// 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_sleep (device, (remaining + 999) / 1000); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|         HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); | ||||
| 	HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); | ||||
| 
 | ||||
|         return nbytes; | ||||
| 	return nbytes; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_flush (serial_t *device, int queue) | ||||
| int serial_flush (serial_t *device, int queue) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, | ||||
|                 serial_get_received (device), | ||||
|                 serial_get_transmitted (device)); | ||||
| 	INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, | ||||
| 	      serial_get_received (device), | ||||
| 	      serial_get_transmitted (device)); | ||||
| 
 | ||||
|         switch (queue) { | ||||
|         case SERIAL_QUEUE_INPUT: | ||||
|                 if (ftdi_usb_purge_tx_buffer(device->ftdi_ctx)) { | ||||
| 	switch (queue) { | ||||
| 	case SERIAL_QUEUE_INPUT: | ||||
| 		if (ftdi_usb_purge_tx_buffer(device->ftdi_ctx)) { | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
|                 break; | ||||
|         case SERIAL_QUEUE_OUTPUT: | ||||
|                 if (ftdi_usb_purge_rx_buffer(device->ftdi_ctx)) { | ||||
| 		break; | ||||
| 	case SERIAL_QUEUE_OUTPUT: | ||||
| 		if (ftdi_usb_purge_rx_buffer(device->ftdi_ctx)) { | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
|                 break; | ||||
|         default: | ||||
|                 if (ftdi_usb_purge_buffers(device->ftdi_ctx)) { | ||||
| 		break; | ||||
| 	default: | ||||
| 		if (ftdi_usb_purge_buffers(device->ftdi_ctx)) { | ||||
| 			ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 			return -1; | ||||
| 		} | ||||
|                 break; | ||||
|         } | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_send_break (serial_t *device) | ||||
| int serial_send_break (serial_t *device) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)a
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)a
 | ||||
| 
 | ||||
| 	INFO (device->context, "Break : One time period."); | ||||
| 
 | ||||
|  | @ -538,133 +516,119 @@ serial_send_break (serial_t *device) | |||
| 	// and resetting the baudrate up again. But it has flaws.
 | ||||
| 	// Not implementing it before researching more.
 | ||||
| 
 | ||||
|         return -1; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_set_break (serial_t *device, int level) | ||||
| int serial_set_break (serial_t *device, int level) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (device->context, "Break: value=%i", level); | ||||
| 	INFO (device->context, "Break: value=%i", level); | ||||
| 
 | ||||
| 	// Not implemented in libftdi yet. Research it further.
 | ||||
| 
 | ||||
|         return -1; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_set_dtr (serial_t *device, int level) | ||||
| int serial_set_dtr (serial_t *device, int level) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (device->context, "DTR: value=%i", level); | ||||
| 	INFO (device->context, "DTR: value=%i", level); | ||||
| 
 | ||||
|         if (ftdi_setdtr(device->ftdi_ctx, level)) { | ||||
|                 ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
|                 return -1; | ||||
|         } | ||||
| 	if (ftdi_setdtr(device->ftdi_ctx, level)) { | ||||
| 		ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_set_rts (serial_t *device, int level) | ||||
| int serial_set_rts (serial_t *device, int level) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         INFO (device->context, "RTS: value=%i", level); | ||||
| 	INFO (device->context, "RTS: value=%i", level); | ||||
| 
 | ||||
|         if (ftdi_setrts(device->ftdi_ctx, level)) { | ||||
|                 ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
|                 return -1; | ||||
|         } | ||||
| 	if (ftdi_setrts(device->ftdi_ctx, level)) { | ||||
| 		ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_get_received (serial_t *device) | ||||
| int serial_get_received (serial_t *device) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         // Direct access is not encouraged. But function implementation
 | ||||
|         // is not available. The return quantity might be anything.
 | ||||
|         // Find out further about its possible values and correct way of
 | ||||
|         // access.
 | ||||
|         int bytes = device->ftdi_ctx->readbuffer_remaining; | ||||
| 	// Direct access is not encouraged. But function implementation
 | ||||
| 	// is not available. The return quantity might be anything.
 | ||||
| 	// Find out further about its possible values and correct way of
 | ||||
| 	// access.
 | ||||
| 	int bytes = device->ftdi_ctx->readbuffer_remaining; | ||||
| 
 | ||||
| 	return bytes; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_get_transmitted (serial_t *device) | ||||
| int serial_get_transmitted (serial_t *device) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
| 	// This is not possible using libftdi. Look further into it.
 | ||||
|         return -1; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_get_line (serial_t *device, int line) | ||||
| int serial_get_line (serial_t *device, int line) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; // EINVAL (Invalid argument)
 | ||||
| 	if (device == NULL) | ||||
| 		return -1; // EINVAL (Invalid argument)
 | ||||
| 
 | ||||
|         unsigned short int status[2] = {0}; | ||||
| 	unsigned short int status[2] = {0}; | ||||
| 
 | ||||
| 	if(ftdi_poll_modem_status(device->ftdi_ctx, status)) { | ||||
| 		ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         switch (line) { | ||||
|         case SERIAL_LINE_DCD: | ||||
|                 return (status[0] & MODEM_DCD) == MODEM_DCD; | ||||
|         case SERIAL_LINE_CTS: | ||||
|                 return (status[0] & MODEM_CTS) == MODEM_CTS; | ||||
|         case SERIAL_LINE_DSR: | ||||
|                 return (status[0] & MODEM_DSR) == MODEM_DSR; | ||||
|         case SERIAL_LINE_RNG: | ||||
|                 return (status[0] & MODEM_RNG) == MODEM_RNG; | ||||
|         default: | ||||
|                 return -1; | ||||
|         } | ||||
| 	switch (line) { | ||||
| 	case SERIAL_LINE_DCD: | ||||
| 		return (status[0] & MODEM_DCD) == MODEM_DCD; | ||||
| 	case SERIAL_LINE_CTS: | ||||
| 		return (status[0] & MODEM_CTS) == MODEM_CTS; | ||||
| 	case SERIAL_LINE_DSR: | ||||
| 		return (status[0] & MODEM_DSR) == MODEM_DSR; | ||||
| 	case SERIAL_LINE_RNG: | ||||
| 		return (status[0] & MODEM_RNG) == MODEM_RNG; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|         return 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| serial_sleep (serial_t *device, unsigned long timeout) | ||||
| int serial_sleep (serial_t *device, unsigned long timeout) | ||||
| { | ||||
|         if (device == NULL) | ||||
|                 return -1; | ||||
| 	if (device == NULL) | ||||
| 		return -1; | ||||
| 
 | ||||
|         INFO (device->context, "Sleep: value=%lu", timeout); | ||||
| 	INFO (device->context, "Sleep: value=%lu", timeout); | ||||
| 
 | ||||
|         struct timespec ts; | ||||
|         ts.tv_sec  = (timeout / 1000); | ||||
|         ts.tv_nsec = (timeout % 1000) * 1000000; | ||||
| 	struct timespec ts; | ||||
| 	ts.tv_sec  = (timeout / 1000); | ||||
| 	ts.tv_nsec = (timeout % 1000) * 1000000; | ||||
| 
 | ||||
|         while (nanosleep (&ts, &ts) != 0) { | ||||
|                 if (errno != EINTR ) { | ||||
|                         SYSERROR (device->context, errno); | ||||
|                         return -1; | ||||
|                 } | ||||
|         } | ||||
| 	while (nanosleep (&ts, &ts) != 0) { | ||||
| 		if (errno != EINTR ) { | ||||
| 			SYSERROR (device->context, errno); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	return 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue