2010-11-17 08:48:03 +00:00
/*-
* Public platform independent Near Field Communication ( NFC ) library
2012-05-29 00:33:22 +00:00
*
2010-11-17 08:48:03 +00:00
* Copyright ( C ) 2009 , 2010 , Roel Verdult , Romuald Conty
2012-05-29 00:33:22 +00:00
*
2010-11-17 08:48:03 +00:00
* This program is free software : you can redistribute it and / or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation , either version 3 of the License , or ( at your
* option ) any later version .
2012-05-29 00:33:22 +00:00
*
2010-11-17 08:48:03 +00:00
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>
*
*/
/**
2011-03-09 09:41:40 +00:00
* @ file uart_win32 . c
2010-11-17 08:48:03 +00:00
* @ brief Windows UART driver
*/
2011-09-21 06:54:53 +00:00
# include "log.h"
# define LOG_CATEGORY "libnfc.bus.uart_win32"
2011-03-09 09:41:40 +00:00
// Handle platform specific includes
# include "contrib/windows.h"
# define delay_ms( X ) Sleep( X )
2011-11-23 15:55:40 +00:00
struct serial_port_windows {
2010-11-17 08:48:03 +00:00
HANDLE hPort ; // Serial port handle
DCB dcb ; // Device control settings
COMMTIMEOUTS ct ; // Serial port time-out configuration
2011-11-23 15:55:40 +00:00
} ;
2010-11-17 08:48:03 +00:00
serial_port
2012-05-29 15:54:36 +00:00
uart_open ( const char * pcPortName )
2010-11-17 08:48:03 +00:00
{
char acPortName [ 255 ] ;
2012-05-29 15:54:36 +00:00
struct serial_port_windows * sp = malloc ( sizeof ( struct serial_port_windows ) ) ;
2010-11-17 08:48:03 +00:00
// Copy the input "com?" to "\\.\COM?" format
2012-05-29 15:54:36 +00:00
sprintf ( acPortName , " \\ \\ . \\ %s " , pcPortName ) ;
_strupr ( acPortName ) ;
2010-11-17 08:48:03 +00:00
// Try to open the serial port
2012-05-29 15:54:36 +00:00
sp - > hPort = CreateFileA ( acPortName , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , NULL ) ;
2010-11-17 08:48:03 +00:00
if ( sp - > hPort = = INVALID_HANDLE_VALUE ) {
2012-05-29 15:54:36 +00:00
uart_close ( sp ) ;
2010-11-17 08:48:03 +00:00
return INVALID_SERIAL_PORT ;
}
// Prepare the device control
2012-05-29 15:54:36 +00:00
memset ( & sp - > dcb , 0 , sizeof ( DCB ) ) ;
sp - > dcb . DCBlength = sizeof ( DCB ) ;
if ( ! BuildCommDCBA ( " baud=9600 data=8 parity=N stop=1 " , & sp - > dcb ) ) {
uart_close ( sp ) ;
2010-11-17 08:48:03 +00:00
return INVALID_SERIAL_PORT ;
}
// Update the active serial port
2012-05-29 15:54:36 +00:00
if ( ! SetCommState ( sp - > hPort , & sp - > dcb ) ) {
uart_close ( sp ) ;
2010-11-17 08:48:03 +00:00
return INVALID_SERIAL_PORT ;
}
sp - > ct . ReadIntervalTimeout = 30 ;
sp - > ct . ReadTotalTimeoutMultiplier = 0 ;
sp - > ct . ReadTotalTimeoutConstant = 30 ;
sp - > ct . WriteTotalTimeoutMultiplier = 30 ;
sp - > ct . WriteTotalTimeoutConstant = 0 ;
2012-05-29 15:54:36 +00:00
if ( ! SetCommTimeouts ( sp - > hPort , & sp - > ct ) ) {
uart_close ( sp ) ;
2010-11-17 08:48:03 +00:00
return INVALID_SERIAL_PORT ;
}
2012-05-29 15:54:36 +00:00
PurgeComm ( sp - > hPort , PURGE_RXABORT | PURGE_RXCLEAR ) ;
2010-11-17 08:48:03 +00:00
return sp ;
}
void
2012-05-29 15:54:36 +00:00
uart_close ( const serial_port sp )
2010-11-17 08:48:03 +00:00
{
2011-11-23 15:55:40 +00:00
if ( ( ( struct serial_port_windows * ) sp ) - > hPort ! = INVALID_HANDLE_VALUE ) {
2012-05-29 15:54:36 +00:00
CloseHandle ( ( ( struct serial_port_windows * ) sp ) - > hPort ) ;
2010-11-17 08:48:03 +00:00
}
2012-05-29 15:54:36 +00:00
free ( sp ) ;
2010-11-17 08:48:03 +00:00
}
2011-05-25 10:31:19 +00:00
void
2012-05-29 15:54:36 +00:00
uart_flush_input ( const serial_port sp )
2011-05-25 10:31:19 +00:00
{
2011-11-23 15:55:40 +00:00
PurgeComm ( ( ( struct serial_port_windows * ) sp ) - > hPort , PURGE_RXABORT | PURGE_RXCLEAR ) ;
2011-05-25 10:31:19 +00:00
}
2010-11-17 08:48:03 +00:00
void
2012-05-29 15:54:36 +00:00
uart_set_speed ( serial_port sp , const uint32_t uiPortSpeed )
2010-11-17 08:48:03 +00:00
{
2011-11-23 15:55:40 +00:00
struct serial_port_windows * spw ;
2010-11-17 08:48:03 +00:00
2012-05-29 15:54:36 +00:00
log_put ( LOG_CATEGORY , NFC_PRIORITY_TRACE , " Serial port speed requested to be set to %d bauds. " , uiPortSpeed ) ;
2010-11-17 08:48:03 +00:00
// Set port speed (Input and Output)
switch ( uiPortSpeed ) {
2012-05-29 15:52:51 +00:00
case 9600 :
case 19200 :
case 38400 :
case 57600 :
case 115200 :
case 230400 :
case 460800 :
break ;
default :
2012-05-29 15:54:36 +00:00
log_put ( LOG_CATEGORY , NFC_PRIORITY_ERROR , " Unable to set serial port speed to %d bauds. Speed value must be one of these constants: 9600 (default), 19200, 38400, 57600, 115200, 230400 or 460800. " , uiPortSpeed ) ;
2012-05-29 15:52:51 +00:00
return ;
2010-11-17 08:48:03 +00:00
} ;
2011-11-23 15:55:40 +00:00
spw = ( struct serial_port_windows * ) sp ;
2010-11-17 08:48:03 +00:00
// Set baud rate
spw - > dcb . BaudRate = uiPortSpeed ;
2012-05-29 15:54:36 +00:00
if ( ! SetCommState ( spw - > hPort , & spw - > dcb ) ) {
log_put ( LOG_CATEGORY , NFC_PRIORITY_ERROR , " %s " , " Unable to apply new speed settings. " ) ;
2010-11-17 08:48:03 +00:00
return ;
}
2012-05-29 15:54:36 +00:00
PurgeComm ( spw - > hPort , PURGE_RXABORT | PURGE_RXCLEAR ) ;
2010-11-17 08:48:03 +00:00
}
uint32_t
2012-05-29 15:54:36 +00:00
uart_get_speed ( const serial_port sp )
2010-11-17 08:48:03 +00:00
{
2011-11-23 15:55:40 +00:00
const struct serial_port_windows * spw = ( struct serial_port_windows * ) sp ;
2012-05-29 15:54:36 +00:00
if ( ! GetCommState ( spw - > hPort , ( serial_port ) & spw - > dcb ) )
2010-11-17 08:48:03 +00:00
return spw - > dcb . BaudRate ;
return 0 ;
}
int
2012-05-29 15:54:36 +00:00
uart_receive ( serial_port sp , uint8_t * pbtRx , const size_t szRx , void * abort_p , int timeout )
2010-11-17 08:48:03 +00:00
{
2011-05-10 13:26:57 +00:00
DWORD dwBytesToGet = ( DWORD ) szRx ;
DWORD dwBytesReceived = 0 ;
DWORD dwTotalBytesReceived = 0 ;
BOOL res ;
2011-09-30 14:02:51 +00:00
// XXX Put this part into uart_win32_timeouts () ?
2011-11-25 11:37:30 +00:00
DWORD timeout_ms = timeout ;
2011-09-30 14:02:51 +00:00
COMMTIMEOUTS timeouts ;
timeouts . ReadIntervalTimeout = 0 ;
timeouts . ReadTotalTimeoutMultiplier = 0 ;
2011-10-01 14:50:53 +00:00
timeouts . ReadTotalTimeoutConstant = timeout_ms ;
2011-09-30 14:02:51 +00:00
timeouts . WriteTotalTimeoutMultiplier = 0 ;
2011-10-01 14:50:53 +00:00
timeouts . WriteTotalTimeoutConstant = timeout_ms ;
2011-09-30 14:02:51 +00:00
2012-05-29 15:54:36 +00:00
if ( ! SetCommTimeouts ( ( ( struct serial_port_windows * ) sp ) - > hPort , & timeouts ) ) {
log_put ( LOG_CATEGORY , NFC_PRIORITY_ERROR , " Unable to apply new timeout settings. " ) ;
2012-03-01 11:37:16 +00:00
return NFC_EIO ;
2011-09-30 14:02:51 +00:00
}
2012-05-29 15:54:36 +00:00
log_put ( LOG_CATEGORY , NFC_PRIORITY_TRACE , " Timeouts are set to %u ms " , timeout_ms ) ;
2011-09-30 14:02:51 +00:00
// TODO Enhance the reception method
// - According to MSDN, it could be better to implement nfc_abort_command() mecanism using Cancello()
2011-05-09 11:14:43 +00:00
volatile bool * abort_flag_p = ( volatile bool * ) abort_p ;
do {
2012-05-29 15:54:36 +00:00
log_put ( LOG_CATEGORY , NFC_PRIORITY_TRACE , " ReadFile " ) ;
res = ReadFile ( ( ( struct serial_port_windows * ) sp ) - > hPort , pbtRx + dwTotalBytesReceived ,
dwBytesToGet ,
& dwBytesReceived , NULL ) ;
2011-05-10 13:26:57 +00:00
dwTotalBytesReceived + = dwBytesReceived ;
if ( ! res ) {
2011-09-30 14:02:51 +00:00
DWORD err = GetLastError ( ) ;
2012-05-29 15:54:36 +00:00
log_put ( LOG_CATEGORY , NFC_PRIORITY_ERROR , " ReadFile error: %u " , err ) ;
2012-03-01 11:37:16 +00:00
return NFC_EIO ;
2011-10-01 14:50:53 +00:00
} else if ( dwBytesReceived = = 0 ) {
2012-05-29 15:52:51 +00:00
return NFC_ETIMEOUT ;
}
2012-05-29 00:33:22 +00:00
2011-05-10 13:26:57 +00:00
if ( ( ( DWORD ) szRx ) > dwTotalBytesReceived ) {
dwBytesToGet - = dwBytesReceived ;
}
if ( abort_flag_p ! = NULL & & ( * abort_flag_p ) & & dwTotalBytesReceived = = 0 ) {
2012-03-01 11:37:16 +00:00
return NFC_EOPABORTED ;
2011-05-10 13:26:57 +00:00
}
} while ( ( ( DWORD ) szRx ) > dwTotalBytesReceived ) ;
2012-05-29 15:54:36 +00:00
LOG_HEX ( " RX " , pbtRx , szRx ) ;
2011-05-10 13:26:57 +00:00
2012-03-01 11:37:16 +00:00
return ( dwTotalBytesReceived = = ( DWORD ) szRx ) ? 0 : NFC_EIO ;
2010-11-17 08:48:03 +00:00
}
int
2012-05-29 15:54:36 +00:00
uart_send ( serial_port sp , const uint8_t * pbtTx , const size_t szTx , int timeout )
2010-11-17 08:48:03 +00:00
{
DWORD dwTxLen = 0 ;
2011-09-30 14:02:51 +00:00
COMMTIMEOUTS timeouts ;
timeouts . ReadIntervalTimeout = 0 ;
timeouts . ReadTotalTimeoutMultiplier = 0 ;
2011-11-25 11:37:30 +00:00
timeouts . ReadTotalTimeoutConstant = timeout ;
2011-09-30 14:02:51 +00:00
timeouts . WriteTotalTimeoutMultiplier = 0 ;
2011-11-25 11:37:30 +00:00
timeouts . WriteTotalTimeoutConstant = timeout ;
2011-09-30 14:02:51 +00:00
2012-05-29 15:54:36 +00:00
if ( ! SetCommTimeouts ( ( ( struct serial_port_windows * ) sp ) - > hPort , & timeouts ) ) {
log_put ( LOG_CATEGORY , NFC_PRIORITY_ERROR , " Unable to apply new timeout settings. " ) ;
2012-03-01 11:37:16 +00:00
return NFC_EIO ;
2011-09-30 14:02:51 +00:00
}
2012-05-29 15:54:36 +00:00
LOG_HEX ( " TX " , pbtTx , szTx ) ;
if ( ! WriteFile ( ( ( struct serial_port_windows * ) sp ) - > hPort , pbtTx , szTx , & dwTxLen , NULL ) ) {
2012-03-01 11:37:16 +00:00
return NFC_EIO ;
2010-11-17 08:48:03 +00:00
}
if ( ! dwTxLen )
2012-03-01 11:37:16 +00:00
return NFC_EIO ;
2010-11-17 08:48:03 +00:00
return 0 ;
}
2011-06-16 11:50:39 +00:00
BOOL is_port_available ( int nPort )
{
TCHAR szPort [ 15 ] ;
COMMCONFIG cc ;
DWORD dwCCSize ;
sprintf ( szPort , " COM%d " , nPort ) ;
// Check if this port is available
dwCCSize = sizeof ( cc ) ;
return GetDefaultCommConfig ( szPort , & cc , & dwCCSize ) ;
}
2011-03-09 09:41:40 +00:00
// Path to the serial port is OS-dependant.
// Try to guess what we should use.
2011-06-16 11:50:39 +00:00
# define MAX_SERIAL_PORT_WIN 255
2011-03-09 09:41:40 +00:00
char * *
2012-05-29 15:54:36 +00:00
uart_list_ports ( void )
2011-03-09 09:41:40 +00:00
{
2011-11-25 15:21:10 +00:00
char * * availablePorts = malloc ( ( 1 + MAX_SERIAL_PORT_WIN ) * sizeof ( char * ) ) ;
2011-06-16 11:50:39 +00:00
int curIndex = 0 ;
2011-03-30 14:19:53 +00:00
int i ;
2011-06-16 11:50:39 +00:00
for ( i = 1 ; i < = MAX_SERIAL_PORT_WIN ; i + + ) {
if ( is_port_available ( i ) ) {
availablePorts [ curIndex ] = ( char * ) malloc ( 10 ) ;
sprintf ( availablePorts [ curIndex ] , " COM%d " , i ) ;
// printf("found candidate port: %s\n", availablePorts[curIndex]);
curIndex + + ;
}
2011-03-30 14:19:53 +00:00
}
2011-06-16 11:50:39 +00:00
availablePorts [ curIndex ] = NULL ;
2011-03-30 14:19:53 +00:00
2011-03-09 09:41:40 +00:00
return availablePorts ;
}