/*** BeginHeader xbee_ser_get_cts */
int xbee_ser_get_cts( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	// the xCheckCTS returns the pin's value, negate it since CTS is active low.
	return 1;
}
/*** EndHeader */
int xbee_ser_flowcontrol( xbee_serial_t *serial, bool_t enabled)
{
	XBEE_SER_CHECK( serial);

	if (enabled)
	{
		switch ( serial->usart )
		{
		case USART0:
			return 0;
			break;

#if defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
		case USART1:
			return 0;
			break;
#endif

		default:
			return -EINVAL;
			break;
		}
	}

	return 0;
}
int xbee_ser_break( xbee_serial_t *serial, int enabled)
{
	BOOL success;

	XBEE_SER_CHECK( serial);

	if (enabled)
	{
		success = SetCommBreak( serial->hCom);
	}
	else
	{
		success = ClearCommBreak( serial->hCom);
	}

	#ifdef XBEE_SERIAL_VERBOSE
		if (success == 0)
		{
			printf( "%s: {Set|Clear}CommBreak error %lu\n", __FUNCTION__,
					GetLastError());
		}
	#endif

	return success ? 0 : -EIO;
}
int xbee_ser_write( xbee_serial_t *serial, const void FAR *buffer,
	int length)
{
	int result;

	XBEE_SER_CHECK( serial);
	if (length < 0)
	{
		return -EINVAL;
	}

	result = write( serial->fd, buffer, length);

	if (result < 0)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: error %d trying to write %d bytes\n", __FUNCTION__,
				errno, length);
		#endif
		return -errno;
	}

	#ifdef XBEE_SERIAL_VERBOSE
		printf( "%s: wrote %d of %d bytes\n", __FUNCTION__, result, length);
		hex_dump( buffer, result, HEX_DUMP_FLAG_TAB);
	#endif

	return result;
}
int xbee_ser_flowcontrol( xbee_serial_t *serial, int enabled)
{
	struct termios options;

	XBEE_SER_CHECK( serial);

	// Get the current options for the port...
	if (tcgetattr( serial->fd, &options) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: %s failed (%d)\n", __FUNCTION__, "tcgetattr", errno);
		#endif
		return -errno;
	}

	if (enabled)
	{
		options.c_cflag |= CRTSCTS;
	}
	else
	{
		options.c_cflag &= ~CRTSCTS;
	}

	// Set the new options for the port immediately
	if (tcsetattr( serial->fd, TCSANOW, &options) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: %s failed (%d)\n", __FUNCTION__, "tcsetattr", errno);
		#endif
		return -errno;
	}

	return 0;
}
int xbee_ser_flowcontrol( xbee_serial_t *serial, int enabled)
{
	DCB dcb;

	XBEE_SER_CHECK( serial);

	memset( &dcb, 0, sizeof dcb);
	dcb.DCBlength = sizeof dcb;
	if (!GetCommState( serial->hCom, &dcb))
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: GetComState error %lu\n", __FUNCTION__, GetLastError());
		#endif
		return -EIO;
	}

	dcb.fOutxCtsFlow = enabled ? TRUE : FALSE;
	dcb.fRtsControl = enabled ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;

	if (!SetCommState( serial->hCom, &dcb))
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: SetComState error %lu\n", __FUNCTION__, GetLastError());
		#endif
		return -EIO;
	}

	#ifdef XBEE_SERIAL_VERBOSE
		printf( "%s: flowcontrol %s\n", __FUNCTION__,
			enabled ? "enabled" : "disabled");
	#endif

	return 0;
}
int xbee_ser_break( xbee_serial_t *serial, int enabled)
{
	XBEE_SER_CHECK( serial);

	/* Devnote regarding use of ioctl() over tcsendbreak():
		"The effect of a nonzero duration with tcsendbreak() varies. SunOS
		specifies a break of duration * N seconds, where N is at least 0.25,
		and not more than 0.5. Linux, AIX, DU, Tru64 send a break of duration
		milliseconds. FreeBSD and NetBSD and HP-UX and MacOS ignore the value
		of duration. Under Solaris and UnixWare, tcsendbreak() with nonzero
		duration behaves like tcdrain()."
		- http://linux.die.net/man/3/tcsendbreak
	*/

	if (ioctl( serial->fd, enabled ? TIOCSBRK : TIOCCBRK) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: ioctl %s failed (errno=%d)\n", __FUNCTION__,
				"TIOCMGET", errno);
		#endif
		return -errno;
	}

	return 0;
}
int xbee_ser_write( xbee_serial_t *serial, const void FAR *buffer,
	int length)
{
	DWORD dwWrote;
	BOOL success;

	XBEE_SER_CHECK( serial);
	if (! buffer || length < 0)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: return -EINVAL (buffer=%p, length=%d)\n",
				__FUNCTION__, buffer, length);
		#endif
		return -EINVAL;
	}

	success = WriteFile( serial->hCom, buffer, length, &dwWrote, NULL);
	#ifdef XBEE_SERIAL_VERBOSE
		printf( "%s: wrote %d of %d bytes (err=%lu)\n", __FUNCTION__,
			(int) dwWrote, length, success ? 0 : GetLastError());
		hex_dump( buffer, length, HEX_DUMP_FLAG_TAB);
	#endif

	if (! success)
	{
		return -EIO;
	}

	return (int) dwWrote;
}
/*** EndHeader */
int xbee_ser_rx_flush( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	xSerialRxFlush( serial );
	return 0;
}
int xbee_ser_read( xbee_serial_t *serial, void FAR *buffer, int bufsize)
{
	DWORD dwRead;
	BOOL success;

	XBEE_SER_CHECK( serial);
	if (! buffer || bufsize < 0)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: return -EINVAL (buffer=%p, bufsize=%d)\n",
				__FUNCTION__, buffer, bufsize);
		#endif
		return -EINVAL;
	}

	success = ReadFile( serial->hCom, buffer, bufsize, &dwRead, NULL);
	#ifdef XBEE_SERIAL_VERBOSE
		if (! success)
		{
			printf( "%s: ReadFile error %lu\n", __FUNCTION__, GetLastError());
		}
		if (dwRead)
		{
			printf( "%s: read %d bytes\n", __FUNCTION__, (int) dwRead);
			hex_dump( buffer, (int) dwRead, HEX_DUMP_FLAG_TAB);
		}
	#endif

	if (! success)
	{
		return -EIO;
	}

	return (int) dwRead;
}
int xbee_ser_rx_flush( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	tcflush( serial->fd, TCIFLUSH);

	return 0;
}
/*** EndHeader */
int xbee_ser_close( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	vSerialClose (serial);

	return 0;
}
int xbee_ser_rx_flush( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	PurgeComm( serial->hCom, PURGE_RXCLEAR | PURGE_RXABORT);

	return 0;
}
/*** EndHeader */
int xbee_ser_break( xbee_serial_t *serial, bool_t enabled)
{
	XBEE_SER_CHECK( serial);

	if (enabled)
	{
		switch ( serial->usart )
		{
			case USART0:
				/* Disable the Tx */
				UCSR0B &= ~_BV(UDRIE0);
				UCSR0B &= ~_BV(TXEN0);
				/* Pull it low to send Break */
				DDRD |= _BV(DDD1);
				PORTD &= ~_BV(PIN1);
				break;

	#if defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
			case USART1:
				/* Disable the Tx */
				UCSR1B &= ~_BV(UDRIE1);
				UCSR1B &= ~ _BV(TXEN1);
				/* Pull it low to send Break */
				DDRD |= _BV(DDD3);
				PORTD &= ~_BV(PIN3);
				break;
	#endif

			default:
				return -EINVAL;
				break;
		}
	}
	else
	{
		switch ( serial->usart )
		{
			case USART0:
				/* Enable the Tx. */
				UCSR0B |=  _BV(TXEN0) ;
				break;

		#if defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
			case USART1:
				/* Enable the Tx. */
				UCSR1B |= _BV(TXEN1);
				break;
		#endif

			default:
				return -EINVAL;
				break;
		}
	}

	return 0;
}
int xbee_ser_close( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	CloseHandle( serial->hCom);
	serial->hCom = NULL;

	return 0;
}
/*** EndHeader */
int xbee_ser_rx_used( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

// return bytes used in rx buffer -- will this be difficult on some platforms
// (like PC) where we can't peek at the stream?  It may be necessary to create
// a small buffer for the program to buffer up to 512 bytes from COM port.
	return (int)( serial->xRxedChars.count );
}
/*** EndHeader */
int xbee_ser_putchar( xbee_serial_t *serial, uint8_t ch)
{
	bool_t error;

	XBEE_SER_CHECK( serial);

	error = xSerialPutChar( serial, (UBaseType_t)ch);

	if (error == FALSE)
		return 0;
	else
		return -ENOSPC;
}
/*** EndHeader */
int xbee_ser_open( xbee_serial_t *serial, uint32_t baudrate)
{
	XBEE_SER_CHECK( serial);

	if (xbee_ser_invalid(serial))
	{
		return -EIO;
	}
	else
	{
		return 0;
	}
}
int xbee_ser_rx_used( xbee_serial_t *serial)
{
	COMSTAT	stat;

	XBEE_SER_CHECK( serial);

	if (ClearCommError( serial->hCom, NULL, &stat))
	{
		return (int) stat.cbInQue;
	}

	return 0;
}
/*** EndHeader */
int xbee_ser_getchar( xbee_serial_t *serial)
{
	UBaseType_t ch;
	bool_t error;

	XBEE_SER_CHECK( serial);

	error = xSerialGetChar( serial, &ch);

	if (error == FALSE)
		return (int)ch;
	else
		return -ENODATA;
}
int xbee_ser_get_cts( xbee_serial_t *serial)
{
	DWORD	dwModemStatus;

	XBEE_SER_CHECK( serial);

	if (!GetCommModemStatus( serial->hCom, &dwModemStatus))
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: GetCommModemStatus error %lu\n", __FUNCTION__,
					GetLastError());
		#endif
		return -EIO;
	}
	return (dwModemStatus & MS_CTS_ON) ? 1 : 0;
}
int xbee_ser_get_cts( xbee_serial_t *serial)
{
	int status;

	XBEE_SER_CHECK( serial);

	if (ioctl( serial->fd, TIOCMGET, &status) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: ioctl %s failed (errno=%d)\n", __FUNCTION__,
				"TIOCMGET", errno);
		#endif
		return -errno;
	}

	return (status & TIOCM_CTS) ? 1 : 0;
}
int xbee_ser_close( xbee_serial_t *serial)
{
	int result = 0;

	XBEE_SER_CHECK( serial);

	if (close( serial->fd) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: close(%d) failed (errno=%d)\n", __FUNCTION__,
				serial->fd, errno);
		#endif
		result = -errno;
	}
	serial->fd = -1;

	return result;
}
int xbee_ser_rx_used( xbee_serial_t *serial)
{
	int bytes;

	XBEE_SER_CHECK( serial);

	if (ioctl( serial->fd,
#ifdef FIONREAD
		FIONREAD,
#else
		TIOCINQ,							// for Cygwin
#endif
		&bytes) == -1)
	{
		return -errno;
	}

	return bytes;
}
/*** EndHeader */
int xbee_ser_read( xbee_serial_t *serial, void FAR *buffer, int bufsize)
{
	int16_t read;
	UBaseType_t *buff = (UBaseType_t *)buffer;

	XBEE_SER_CHECK( serial );

	if (! buffer || bufsize < 0)
	{
		return -EINVAL;
	}

	for( read = 0; read < bufsize; ++read )
	{
		if( !(xSerialGetChar( serial, &buff[read] )))	// if there's an error, because we have no bytes
				return -EIO;							// return an error
	}

	return read;										// otherwise return bytes read.
}
/*** EndHeader */
int xbee_ser_write( xbee_serial_t *serial, const void FAR *buffer, int length)
{
	int16_t written;
	UBaseType_t *buff = (UBaseType_t *)buffer;

	XBEE_SER_CHECK( serial );

	if (! buffer || length < 0)
	{
		return -EINVAL;
	}

	for( written = 0; written < length; ++written )
	{
		if( !(xSerialPutChar( serial, buff[written] )))	// if there's an error
				return -EIO;							// return an error
	}

	return written;										// otherwise return bytes written.
}
int xbee_ser_set_rts( xbee_serial_t *serial, int asserted)
{
	BOOL success;

	XBEE_SER_CHECK( serial);

	// disable flow control so our manual setting will stick
	xbee_ser_flowcontrol( serial, 0);

	success = EscapeCommFunction( serial->hCom, asserted ? SETRTS : CLRRTS);

	#ifdef XBEE_SERIAL_VERBOSE
		if (success == 0)
		{
			printf( "%s: EscapeCommFunction error %lu\n", __FUNCTION__,
					GetLastError());
		}
	#endif

	return success ? 0 : -EIO;
}
int xbee_ser_set_rts( xbee_serial_t *serial, int asserted)
{
	int status;

	XBEE_SER_CHECK( serial);

	// disable flow control so our manual setting will stick
	xbee_ser_flowcontrol( serial, 0);

	if (ioctl( serial->fd, TIOCMGET, &status) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: ioctl %s failed (errno=%d)\n", __FUNCTION__,
				"TIOCMGET", errno);
		#endif
		return -errno;
	}

	if (asserted)
	{
		status |= TIOCM_RTS;
	}
	else
	{
		status &= ~TIOCM_RTS;
	}

	if (ioctl( serial->fd, TIOCMSET, &status) == -1)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: ioctl %s failed (errno=%d)\n", __FUNCTION__,
				"TIOCMSET", errno);
		#endif
		return -errno;
	}

	return 0;
}
int xbee_ser_read( xbee_serial_t *serial, void FAR *buffer, int bufsize)
{
	int result;

	XBEE_SER_CHECK( serial);

	if (! buffer || bufsize < 0)
	{
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: buffer=%p, bufsize=%d; return -EINVAL\n", __FUNCTION__,
				buffer, bufsize);
		#endif
		return -EINVAL;
	}

	result = read( serial->fd, buffer, bufsize);
	if (result == -1)
	{
		if (errno == EAGAIN)
		{
			return 0;
		}
		#ifdef XBEE_SERIAL_VERBOSE
			printf( "%s: error %d trying to read %d bytes\n", __FUNCTION__,
				errno, bufsize);
		#endif
		return -errno;
	}

	#ifdef XBEE_SERIAL_VERBOSE
		printf( "%s: read %d bytes\n", __FUNCTION__, result);
		hex_dump( buffer, result, HEX_DUMP_FLAG_TAB);
	#endif

	return result;
}
int xbee_ser_rx_free( xbee_serial_t *serial)
{
	XBEE_SER_CHECK( serial);

	return XBEE_SER_RX_BUFSIZE - xbee_ser_rx_used( serial);
}