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