cec: bumped interface version to 4 stay in sync with the lib version. added changelog...
[deb_libcec.git] / src / lib / platform / windows / serialport.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
33 #include "../serialport.h"
34 #include "../baudrate.h"
35 #include "../timeutils.h"
36
37 using namespace std;
38 using namespace CEC;
39
40 void FormatWindowsError(int iErrorCode, string &strMessage)
41 {
42 if (iErrorCode != ERROR_SUCCESS)
43 {
44 char strAddMessage[1024];
45 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, iErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), strAddMessage, 1024, NULL);
46 strMessage.append(": ");
47 strMessage.append(strAddMessage);
48 }
49 }
50
51 CSerialPort::CSerialPort(void) :
52 m_handle(INVALID_HANDLE_VALUE),
53 m_bIsOpen(false),
54 m_iBaudrate(0),
55 m_iDatabits(0),
56 m_iStopbits(0),
57 m_iParity(0)
58 {
59 }
60
61 CSerialPort::~CSerialPort(void)
62 {
63 Close();
64 }
65
66 bool CSerialPort::Open(string name, int baudrate, int databits, int stopbits, int parity)
67 {
68 m_handle = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
69 if (m_handle == INVALID_HANDLE_VALUE)
70 {
71 m_error = "Unable to open COM port";
72 FormatWindowsError(GetLastError(), m_error);
73 return false;
74 }
75
76 COMMCONFIG commConfig = {0};
77 DWORD dwSize = sizeof(commConfig);
78 commConfig.dwSize = dwSize;
79 if (GetDefaultCommConfig(name.c_str(), &commConfig,&dwSize))
80 {
81 if (!SetCommConfig(m_handle, &commConfig,dwSize))
82 {
83 m_error = "unable to set default config";
84 FormatWindowsError(GetLastError(), m_error);
85 }
86 }
87 else
88 {
89 m_error = "unable to get default config";
90 FormatWindowsError(GetLastError(), m_error);
91 }
92
93 if (!SetupComm(m_handle, 64, 64))
94 {
95 m_error = "unable to set up the com port";
96 FormatWindowsError(GetLastError(), m_error);
97 }
98
99 m_iDatabits = databits;
100 m_iStopbits = stopbits;
101 m_iParity = parity;
102 if (!SetBaudRate(baudrate))
103 {
104 m_error = "unable to set baud rate";
105 FormatWindowsError(GetLastError(), m_error);
106 Close();
107 return false;
108 }
109
110 if (!SetTimeouts(false))
111 {
112 m_error = "unable to set timeouts";
113 FormatWindowsError(GetLastError(), m_error);
114 Close();
115 return false;
116 }
117
118 m_bIsOpen = true;
119 return m_bIsOpen;
120 }
121
122 bool CSerialPort::SetTimeouts(bool bBlocking)
123 {
124 if (m_handle == INVALID_HANDLE_VALUE)
125 return false;
126
127 COMMTIMEOUTS cto;
128 if (!GetCommTimeouts(m_handle, &cto))
129 {
130 m_error = "GetCommTimeouts failed";
131 FormatWindowsError(GetLastError(), m_error);
132 return false;
133 }
134
135 if (bBlocking)
136 {
137 cto.ReadIntervalTimeout = 0;
138 cto.ReadTotalTimeoutConstant = 0;
139 cto.ReadTotalTimeoutMultiplier = 0;
140 }
141 else
142 {
143 cto.ReadIntervalTimeout = MAXDWORD;
144 cto.ReadTotalTimeoutConstant = 0;
145 cto.ReadTotalTimeoutMultiplier = 0;
146 }
147
148 if (!SetCommTimeouts(m_handle, &cto))
149 {
150 m_error = "SetCommTimeouts failed";
151 FormatWindowsError(GetLastError(), m_error);
152 return false;
153 }
154
155 return true;
156 }
157
158 void CSerialPort::Close(void)
159 {
160 if (m_bIsOpen)
161 {
162 CloseHandle(m_handle);
163 m_bIsOpen = false;
164 }
165 }
166
167 int CSerialPort::Write(uint8_t* data, int len)
168 {
169 DWORD iBytesWritten = 0;
170 if (!m_bIsOpen)
171 return -1;
172
173 if (!WriteFile(m_handle, data, len, &iBytesWritten, NULL))
174 {
175 m_error = "Error while writing to COM port";
176 FormatWindowsError(GetLastError(), m_error);
177 return -1;
178 }
179
180 return (int) iBytesWritten;
181 }
182
183 int CSerialPort::Read(uint8_t* data, int len, int iTimeoutMs /* = -1 */)
184 {
185 DWORD iBytesRead = 0;
186 if (m_handle == 0)
187 {
188 m_error = "Error while reading from COM port: invalid handle";
189 return -1;
190 }
191
192 if(!ReadFile(m_handle, data, len, &iBytesRead, NULL) != 0)
193 {
194 m_error = "unable to read from device";
195 FormatWindowsError(GetLastError(), m_error);
196 iBytesRead = -1;
197 }
198
199 return (int) iBytesRead;
200 }
201
202 bool CSerialPort::SetBaudRate(int baudrate)
203 {
204 m_iBaudrate = baudrate;
205
206 DCB dcb;
207 memset(&dcb,0,sizeof(dcb));
208 dcb.DCBlength = sizeof(dcb);
209 dcb.BaudRate = IntToBaudrate(m_iBaudrate);
210 dcb.fBinary = true;
211 dcb.fDtrControl = DTR_CONTROL_DISABLE;
212 dcb.fRtsControl = RTS_CONTROL_DISABLE;
213 dcb.fOutxCtsFlow = false;
214 dcb.fOutxDsrFlow = false;
215 dcb.fOutX = false;
216 dcb.fInX = false;
217 dcb.fAbortOnError = true;
218
219 if (m_iParity == PAR_NONE)
220 dcb.Parity = NOPARITY;
221 else if (m_iParity == PAR_EVEN)
222 dcb.Parity = EVENPARITY;
223 else
224 dcb.Parity = ODDPARITY;
225
226 if (m_iStopbits == 2)
227 dcb.StopBits = TWOSTOPBITS;
228 else
229 dcb.StopBits = ONESTOPBIT;
230
231 dcb.ByteSize = m_iDatabits;
232
233 if(!SetCommState(m_handle,&dcb))
234 {
235 m_error = "SetCommState failed";
236 FormatWindowsError(GetLastError(), m_error);
237 return false;
238 }
239
240 return true;
241 }
242
243 bool CSerialPort::IsOpen() const
244 {
245 return m_bIsOpen;
246 }