1 /*
2 * serialport_win32.h
3 * PHD Guiding
4 *
5 * Created by Bret McKee
6 * Copyright (c) 2013 Bret McKee
7 * All rights reserved.
8 *
9 * This source code is distributed under the following "BSD" license
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * Neither the name of Bret McKee, Dad Dog Development, nor the names of its
18 * Craig Stark, Stark Labs nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36 #include "phd.h"
37
38 #ifdef __WINDOWS__
39
GetSerialPortList(void)40 wxArrayString SerialPortWin32::GetSerialPortList(void)
41 {
42 wxArrayString ret;
43 char *pBuffer = NULL;
44
45 try
46 {
47 int bufferSize = 4096;
48 DWORD res = 0;
49
50 do
51 {
52 bufferSize *= 2;
53 delete [] pBuffer;
54 pBuffer = new char[bufferSize];
55 if (pBuffer == NULL)
56 {
57 throw ERROR_INFO("new failed in GetSerialPortList");
58 }
59 res = QueryDosDeviceA(NULL, pBuffer, bufferSize);
60 } while (res == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
61
62 if (res == 0)
63 {
64 throw ERROR_INFO("QueryDosDevice failed");
65 }
66
67 for (char *pEntry=pBuffer;*pEntry; pEntry += strlen(pEntry) + 1)
68 {
69 if (strncmp(pEntry, "COM", 3) == 0)
70 {
71 ret.Add(pEntry);
72 }
73 }
74 }
75 catch (const wxString& Msg)
76 {
77 POSSIBLY_UNUSED(Msg);
78 }
79
80 delete [] pBuffer;
81
82 return ret;
83 }
84
SerialPortWin32(void)85 SerialPortWin32::SerialPortWin32(void)
86 {
87 m_handle = INVALID_HANDLE_VALUE;
88 }
89
~SerialPortWin32(void)90 SerialPortWin32::~SerialPortWin32(void)
91 {
92 if (m_handle != INVALID_HANDLE_VALUE)
93 {
94 CloseHandle(m_handle);
95 }
96 }
97
Connect(const wxString & portName,int baud,int dataBits,int stopBits,PARITY Parity,bool useRTS,bool useDTR)98 bool SerialPortWin32::Connect(const wxString& portName, int baud, int dataBits, int stopBits, PARITY Parity, bool useRTS, bool useDTR)
99 {
100 bool bError = false;
101
102 try
103 {
104 wxString portPath = "\\\\.\\" + portName;
105 m_handle = CreateFile(portPath,
106 GENERIC_READ | GENERIC_WRITE,
107 0, // must be opened with exclusive-access
108 NULL, // no security attributes
109 OPEN_EXISTING, // must use OPEN_EXISTING
110 0, // not overlapped I/O
111 NULL // hTemplate must be NULL for comm devices
112 );
113 if (m_handle == INVALID_HANDLE_VALUE)
114 {
115 throw ERROR_INFO("SerialPortWin32: CreateFile("+portName+") failed");
116 }
117
118 DCB dcb;
119
120 if (!GetCommState(m_handle, &dcb))
121 {
122 throw ERROR_INFO("SerialPortWin32: GetCommState failed");
123 }
124
125 dcb.BaudRate = baud;
126 dcb.ByteSize = dataBits;
127
128 switch (stopBits)
129 {
130 case 1:
131 dcb.StopBits = ONESTOPBIT;
132 break;
133 case 2:
134 dcb.StopBits = TWOSTOPBITS;
135 break;
136 default:
137 throw ERROR_INFO("SerialPortWin32: invalid stopBits");
138 break;
139 }
140
141 // no need to map the parity enum --- ours matches theirs
142 dcb.Parity = Parity;
143
144 dcb.fDtrControl = useDTR ? DTR_CONTROL_HANDSHAKE : DTR_CONTROL_ENABLE;
145 dcb.fRtsControl = useRTS ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_ENABLE;
146
147 if (!SetCommState(m_handle, &dcb))
148 {
149 throw ERROR_INFO("SerialPortWin32: GetCommState failed");
150 }
151 }
152 catch (const wxString& Msg)
153 {
154 POSSIBLY_UNUSED(Msg);
155 bError = true;
156 }
157
158 return bError;
159 }
160
Disconnect(void)161 bool SerialPortWin32::Disconnect(void)
162 {
163 bool bError = false;
164
165 try
166 {
167 if (!CloseHandle(m_handle))
168 {
169 throw ERROR_INFO("SerialPortWin32: CloseHandle failed");
170 }
171 }
172 catch (const wxString& Msg)
173 {
174 POSSIBLY_UNUSED(Msg);
175 bError = true;
176 }
177
178 m_handle = INVALID_HANDLE_VALUE;
179
180 return bError;
181 }
182
SetReceiveTimeout(int timeoutMs)183 bool SerialPortWin32::SetReceiveTimeout(int timeoutMs)
184 {
185 bool bError = false;
186
187 try
188 {
189 COMMTIMEOUTS timeouts;
190
191 timeouts.ReadIntervalTimeout = 0;
192 timeouts.ReadTotalTimeoutMultiplier = 0;
193 timeouts.ReadTotalTimeoutConstant = timeoutMs;
194 timeouts.WriteTotalTimeoutMultiplier = 0;
195 timeouts.WriteTotalTimeoutConstant = 0;
196
197 if (!SetCommTimeouts(m_handle, &timeouts))
198 {
199 throw ERROR_INFO("SerialPortWin32: unable to set serial port timeouts");
200 }
201 }
202 catch (const wxString& Msg)
203 {
204 POSSIBLY_UNUSED(Msg);
205 bError = true;
206 }
207
208 return bError;
209 }
210
Send(const unsigned char * pData,unsigned count)211 bool SerialPortWin32::Send(const unsigned char *pData, unsigned count)
212 {
213 bool bError = false;
214
215 try
216 {
217 DWORD nBytesWritten = 0;
218
219 Debug.AddBytes("Sending", pData, count);
220
221 if (!WriteFile(m_handle, pData, count, &nBytesWritten, NULL))
222 {
223 throw ERROR_INFO("SerialPortWin32: WriteFile failed");
224 }
225
226 if (nBytesWritten != count)
227 {
228 throw ERROR_INFO("SerialPortWin32: nBytesWritten != count");
229 }
230
231 }
232 catch (const wxString& Msg)
233 {
234 POSSIBLY_UNUSED(Msg);
235 bError = true;
236 }
237
238 return bError;
239 }
240
Receive(unsigned char * pData,unsigned count)241 bool SerialPortWin32::Receive(unsigned char *pData, unsigned count)
242 {
243 bool bError = false;
244
245 try
246 {
247 DWORD receiveCount;
248
249 if (!ReadFile(m_handle, pData, count, &receiveCount, NULL))
250 {
251 throw ERROR_INFO("SerialPortWin32: Readfile Failed");
252 }
253
254 if (receiveCount != count)
255 {
256 throw ERROR_INFO("SerialPortWin32: recieveCount != count");
257 }
258
259 Debug.AddBytes("Received", pData, receiveCount);
260 }
261 catch (const wxString& Msg)
262 {
263 POSSIBLY_UNUSED(Msg);
264 bError = true;
265 }
266
267 return bError;
268 }
269
EscapeFunction(DWORD command)270 bool SerialPortWin32::EscapeFunction(DWORD command)
271 {
272 bool bError = false;
273
274 try
275 {
276 Debug.Write(wxString::Format("EscapeFunction(0x%x)\n", command));
277
278 if (!EscapeCommFunction(m_handle, command))
279 {
280 throw ERROR_INFO("SerialPortWin32: EscapeCommFunction failed");
281 }
282 }
283 catch (const wxString& Msg)
284 {
285 POSSIBLY_UNUSED(Msg);
286 bError = true;
287 }
288
289 return bError;
290 }
291
SetRTS(bool asserted)292 bool SerialPortWin32::SetRTS(bool asserted)
293 {
294 return SerialPortWin32::EscapeFunction(asserted?SETRTS:CLRRTS);
295 }
296
SetDTR(bool asserted)297 bool SerialPortWin32::SetDTR(bool asserted)
298 {
299 return SerialPortWin32::EscapeFunction(asserted?SETDTR:CLRDTR);
300 }
301
302 #endif // _WINDOWS_
303