libnfc 1.4.2
uart_win32.c
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library
00003  * 
00004  * Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
00005  * 
00006  * This program is free software: you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License as published by the
00008  * Free Software Foundation, either version 3 of the License, or (at your
00009  * option) any later version.
00010  * 
00011  * This program is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00014  * more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  *
00019  */
00020 
00026 typedef struct {
00027   HANDLE  hPort;                // Serial port handle
00028   DCB     dcb;                  // Device control settings
00029   COMMTIMEOUTS ct;              // Serial port time-out configuration
00030 } serial_port_windows;
00031 
00032 serial_port
00033 uart_open (const char *pcPortName)
00034 {
00035   char    acPortName[255];
00036   serial_port_windows *sp = malloc (sizeof (serial_port_windows));
00037 
00038   // Copy the input "com?" to "\\.\COM?" format
00039   sprintf (acPortName, "\\\\.\\%s", pcPortName);
00040   _strupr (acPortName);
00041 
00042   // Try to open the serial port
00043   sp->hPort = CreateFileA (acPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
00044   if (sp->hPort == INVALID_HANDLE_VALUE) {
00045     uart_close (sp);
00046     return INVALID_SERIAL_PORT;
00047   }
00048   // Prepare the device control
00049   memset (&sp->dcb, 0, sizeof (DCB));
00050   sp->dcb.DCBlength = sizeof (DCB);
00051   if (!BuildCommDCBA ("baud=9600 data=8 parity=N stop=1", &sp->dcb)) {
00052     uart_close (sp);
00053     return INVALID_SERIAL_PORT;
00054   }
00055   // Update the active serial port
00056   if (!SetCommState (sp->hPort, &sp->dcb)) {
00057     uart_close (sp);
00058     return INVALID_SERIAL_PORT;
00059   }
00060 
00061   sp->ct.ReadIntervalTimeout = 30;
00062   sp->ct.ReadTotalTimeoutMultiplier = 0;
00063   sp->ct.ReadTotalTimeoutConstant = 30;
00064   sp->ct.WriteTotalTimeoutMultiplier = 30;
00065   sp->ct.WriteTotalTimeoutConstant = 0;
00066 
00067   if (!SetCommTimeouts (sp->hPort, &sp->ct)) {
00068     uart_close (sp);
00069     return INVALID_SERIAL_PORT;
00070   }
00071 
00072   PurgeComm (sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
00073 
00074   return sp;
00075 }
00076 
00077 void
00078 uart_close (const serial_port sp)
00079 {
00080   if (((serial_port_windows *) sp)->hPort != INVALID_HANDLE_VALUE) {
00081     CloseHandle (((serial_port_windows *) sp)->hPort);
00082   }
00083   free (sp);
00084 }
00085 
00086 // TODO Remove PN53x related timeout
00087 void
00088 uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
00089 {
00090   serial_port_windows *spw;
00091 
00092   DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
00093   // Set port speed (Input and Output)
00094   switch (uiPortSpeed) {
00095   case 9600:
00096   case 19200:
00097   case 38400:
00098   case 57600:
00099   case 115200:
00100   case 230400:
00101   case 460800:
00102     break;
00103   default:
00104     ERR("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);
00105     return;
00106   };
00107   spw = (serial_port_windows *) sp;
00108 
00109   // Set timeouts
00110   //printf ("UART_SPEED_T0_TIME (%d) = %d\n", uiPortSpeed, UART_SPEED_T0_TIME(uiPortSpeed));
00111   int iTimeout = 200;
00112   spw->ct.ReadIntervalTimeout = 2;
00113   spw->ct.ReadTotalTimeoutMultiplier = 0;
00114   spw->ct.ReadTotalTimeoutConstant = iTimeout;
00115   spw->ct.WriteTotalTimeoutMultiplier = iTimeout;
00116   spw->ct.WriteTotalTimeoutConstant = 0;
00117 
00118   if (!SetCommTimeouts (spw->hPort, &spw->ct)) {
00119     ERR ("Unable to apply new timeout settings.");
00120     return;
00121   }
00122 
00123   // Set baud rate
00124   spw->dcb.BaudRate = uiPortSpeed;
00125   if (!SetCommState (spw->hPort, &spw->dcb)) {
00126     ERR ("Unable to apply new speed settings.");
00127     return;
00128   }
00129   PurgeComm (spw->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
00130 }
00131 
00132 uint32_t
00133 uart_get_speed (const serial_port sp)
00134 {
00135   const serial_port_windows *spw = (serial_port_windows *) sp;
00136   if (!GetCommState (spw->hPort, (serial_port) & spw->dcb))
00137     return spw->dcb.BaudRate;
00138 
00139   return 0;
00140 }
00141 
00142 int
00143 uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
00144 {
00145   if (!ReadFile (((serial_port_windows *) sp)->hPort, pbtRx, (DWORD)(*pszRx), (LPDWORD) pszRx, NULL)) {
00146     return DEIO;
00147   }
00148   if (!*pszRx)
00149     return DEIO;
00150   return 0;
00151 }
00152 
00153 int
00154 uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
00155 {
00156   DWORD   dwTxLen = 0;
00157   if (!WriteFile (((serial_port_windows *) sp)->hPort, pbtTx, szTx, &dwTxLen, NULL)) {
00158     return DEIO;
00159   }
00160   if (!dwTxLen)
00161     return DEIO;
00162   return 0;
00163 }
00164