libnfc  1.4.2
uart_win32.c
1 /*-
2  * Public platform independent Near Field Communication (NFC) library
3  *
4  * Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>
18  *
19  */
20 
26 typedef struct {
27  HANDLE hPort; // Serial port handle
28  DCB dcb; // Device control settings
29  COMMTIMEOUTS ct; // Serial port time-out configuration
30 } serial_port_windows;
31 
32 serial_port
33 uart_open (const char *pcPortName)
34 {
35  char acPortName[255];
36  serial_port_windows *sp = malloc (sizeof (serial_port_windows));
37 
38  // Copy the input "com?" to "\\.\COM?" format
39  sprintf (acPortName, "\\\\.\\%s", pcPortName);
40  _strupr (acPortName);
41 
42  // Try to open the serial port
43  sp->hPort = CreateFileA (acPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
44  if (sp->hPort == INVALID_HANDLE_VALUE) {
45  uart_close (sp);
46  return INVALID_SERIAL_PORT;
47  }
48  // Prepare the device control
49  memset (&sp->dcb, 0, sizeof (DCB));
50  sp->dcb.DCBlength = sizeof (DCB);
51  if (!BuildCommDCBA ("baud=9600 data=8 parity=N stop=1", &sp->dcb)) {
52  uart_close (sp);
53  return INVALID_SERIAL_PORT;
54  }
55  // Update the active serial port
56  if (!SetCommState (sp->hPort, &sp->dcb)) {
57  uart_close (sp);
58  return INVALID_SERIAL_PORT;
59  }
60 
61  sp->ct.ReadIntervalTimeout = 30;
62  sp->ct.ReadTotalTimeoutMultiplier = 0;
63  sp->ct.ReadTotalTimeoutConstant = 30;
64  sp->ct.WriteTotalTimeoutMultiplier = 30;
65  sp->ct.WriteTotalTimeoutConstant = 0;
66 
67  if (!SetCommTimeouts (sp->hPort, &sp->ct)) {
68  uart_close (sp);
69  return INVALID_SERIAL_PORT;
70  }
71 
72  PurgeComm (sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
73 
74  return sp;
75 }
76 
77 void
78 uart_close (const serial_port sp)
79 {
80  if (((serial_port_windows *) sp)->hPort != INVALID_HANDLE_VALUE) {
81  CloseHandle (((serial_port_windows *) sp)->hPort);
82  }
83  free (sp);
84 }
85 
86 // TODO Remove PN53x related timeout
87 void
88 uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
89 {
90  serial_port_windows *spw;
91 
92  DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
93  // Set port speed (Input and Output)
94  switch (uiPortSpeed) {
95  case 9600:
96  case 19200:
97  case 38400:
98  case 57600:
99  case 115200:
100  case 230400:
101  case 460800:
102  break;
103  default:
104  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);
105  return;
106  };
107  spw = (serial_port_windows *) sp;
108 
109  // Set timeouts
110  //printf ("UART_SPEED_T0_TIME (%d) = %d\n", uiPortSpeed, UART_SPEED_T0_TIME(uiPortSpeed));
111  int iTimeout = 200;
112  spw->ct.ReadIntervalTimeout = 2;
113  spw->ct.ReadTotalTimeoutMultiplier = 0;
114  spw->ct.ReadTotalTimeoutConstant = iTimeout;
115  spw->ct.WriteTotalTimeoutMultiplier = iTimeout;
116  spw->ct.WriteTotalTimeoutConstant = 0;
117 
118  if (!SetCommTimeouts (spw->hPort, &spw->ct)) {
119  ERR ("Unable to apply new timeout settings.");
120  return;
121  }
122 
123  // Set baud rate
124  spw->dcb.BaudRate = uiPortSpeed;
125  if (!SetCommState (spw->hPort, &spw->dcb)) {
126  ERR ("Unable to apply new speed settings.");
127  return;
128  }
129  PurgeComm (spw->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
130 }
131 
132 uint32_t
133 uart_get_speed (const serial_port sp)
134 {
135  const serial_port_windows *spw = (serial_port_windows *) sp;
136  if (!GetCommState (spw->hPort, (serial_port) & spw->dcb))
137  return spw->dcb.BaudRate;
138 
139  return 0;
140 }
141 
142 int
143 uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
144 {
145  if (!ReadFile (((serial_port_windows *) sp)->hPort, pbtRx, (DWORD)(*pszRx), (LPDWORD) pszRx, NULL)) {
146  return DEIO;
147  }
148  if (!*pszRx)
149  return DEIO;
150  return 0;
151 }
152 
153 int
154 uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
155 {
156  DWORD dwTxLen = 0;
157  if (!WriteFile (((serial_port_windows *) sp)->hPort, pbtTx, szTx, &dwTxLen, NULL)) {
158  return DEIO;
159  }
160  if (!dwTxLen)
161  return DEIO;
162  return 0;
163 }
164