1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/serial/serial_connection.h"
6
7 #include <windows.h>
8
9 #include <string>
10
11 namespace extensions {
12
13 namespace {
14
BitrateToSpeedConstant(int bitrate)15 int BitrateToSpeedConstant(int bitrate) {
16 #define BITRATE_TO_SPEED_CASE(x) case x: return CBR_ ## x;
17 switch (bitrate) {
18 BITRATE_TO_SPEED_CASE(110);
19 BITRATE_TO_SPEED_CASE(300);
20 BITRATE_TO_SPEED_CASE(600);
21 BITRATE_TO_SPEED_CASE(1200);
22 BITRATE_TO_SPEED_CASE(2400);
23 BITRATE_TO_SPEED_CASE(4800);
24 BITRATE_TO_SPEED_CASE(9600);
25 BITRATE_TO_SPEED_CASE(14400);
26 BITRATE_TO_SPEED_CASE(19200);
27 BITRATE_TO_SPEED_CASE(38400);
28 BITRATE_TO_SPEED_CASE(57600);
29 BITRATE_TO_SPEED_CASE(115200);
30 BITRATE_TO_SPEED_CASE(128000);
31 BITRATE_TO_SPEED_CASE(256000);
32 default:
33 // If the bitrate doesn't match that of one of the standard
34 // index constants, it may be provided as-is to the DCB
35 // structure, according to MSDN.
36 return bitrate;
37 }
38 #undef BITRATE_TO_SPEED_CASE
39 }
40
DataBitsEnumToConstant(api::serial::DataBits data_bits)41 int DataBitsEnumToConstant(api::serial::DataBits data_bits) {
42 switch (data_bits) {
43 case api::serial::DATA_BITS_SEVEN:
44 return 7;
45 case api::serial::DATA_BITS_EIGHT:
46 default:
47 return 8;
48 }
49 }
50
ParityBitEnumToConstant(api::serial::ParityBit parity_bit)51 int ParityBitEnumToConstant(api::serial::ParityBit parity_bit) {
52 switch (parity_bit) {
53 case api::serial::PARITY_BIT_EVEN:
54 return EVENPARITY;
55 case api::serial::PARITY_BIT_ODD:
56 return SPACEPARITY;
57 case api::serial::PARITY_BIT_NO:
58 default:
59 return NOPARITY;
60 }
61 }
62
StopBitsEnumToConstant(api::serial::StopBits stop_bits)63 int StopBitsEnumToConstant(api::serial::StopBits stop_bits) {
64 switch (stop_bits) {
65 case api::serial::STOP_BITS_TWO:
66 return TWOSTOPBITS;
67 case api::serial::STOP_BITS_ONE:
68 default:
69 return ONESTOPBIT;
70 }
71 }
72
SpeedConstantToBitrate(int speed)73 int SpeedConstantToBitrate(int speed) {
74 #define SPEED_TO_BITRATE_CASE(x) case CBR_ ## x: return x;
75 switch (speed) {
76 SPEED_TO_BITRATE_CASE(110);
77 SPEED_TO_BITRATE_CASE(300);
78 SPEED_TO_BITRATE_CASE(600);
79 SPEED_TO_BITRATE_CASE(1200);
80 SPEED_TO_BITRATE_CASE(2400);
81 SPEED_TO_BITRATE_CASE(4800);
82 SPEED_TO_BITRATE_CASE(9600);
83 SPEED_TO_BITRATE_CASE(14400);
84 SPEED_TO_BITRATE_CASE(19200);
85 SPEED_TO_BITRATE_CASE(38400);
86 SPEED_TO_BITRATE_CASE(57600);
87 SPEED_TO_BITRATE_CASE(115200);
88 SPEED_TO_BITRATE_CASE(128000);
89 SPEED_TO_BITRATE_CASE(256000);
90 default:
91 // If it's not one of the standard index constants,
92 // it should be an integral baud rate, according to
93 // MSDN.
94 return speed;
95 }
96 #undef SPEED_TO_BITRATE_CASE
97 }
98
DataBitsConstantToEnum(int data_bits)99 api::serial::DataBits DataBitsConstantToEnum(int data_bits) {
100 switch (data_bits) {
101 case 7:
102 return api::serial::DATA_BITS_SEVEN;
103 case 8:
104 default:
105 return api::serial::DATA_BITS_EIGHT;
106 }
107 }
108
ParityBitConstantToEnum(int parity_bit)109 api::serial::ParityBit ParityBitConstantToEnum(int parity_bit) {
110 switch (parity_bit) {
111 case EVENPARITY:
112 return api::serial::PARITY_BIT_EVEN;
113 case ODDPARITY:
114 return api::serial::PARITY_BIT_ODD;
115 case NOPARITY:
116 default:
117 return api::serial::PARITY_BIT_NO;
118 }
119 }
120
StopBitsConstantToEnum(int stop_bits)121 api::serial::StopBits StopBitsConstantToEnum(int stop_bits) {
122 switch (stop_bits) {
123 case TWOSTOPBITS:
124 return api::serial::STOP_BITS_TWO;
125 case ONESTOPBIT:
126 default:
127 return api::serial::STOP_BITS_ONE;
128 }
129 }
130
131 } // namespace
132
ConfigurePort(const api::serial::ConnectionOptions & options)133 bool SerialConnection::ConfigurePort(
134 const api::serial::ConnectionOptions& options) {
135 DCB config = { 0 };
136 config.DCBlength = sizeof(config);
137 if (!GetCommState(file_.GetPlatformFile(), &config)) {
138 return false;
139 }
140 if (options.bitrate.get())
141 config.BaudRate = BitrateToSpeedConstant(*options.bitrate);
142 if (options.data_bits != api::serial::DATA_BITS_NONE)
143 config.ByteSize = DataBitsEnumToConstant(options.data_bits);
144 if (options.parity_bit != api::serial::PARITY_BIT_NONE)
145 config.Parity = ParityBitEnumToConstant(options.parity_bit);
146 if (options.stop_bits != api::serial::STOP_BITS_NONE)
147 config.StopBits = StopBitsEnumToConstant(options.stop_bits);
148 if (options.cts_flow_control.get()) {
149 if (*options.cts_flow_control) {
150 config.fOutxCtsFlow = TRUE;
151 config.fRtsControl = RTS_CONTROL_HANDSHAKE;
152 } else {
153 config.fOutxCtsFlow = FALSE;
154 config.fRtsControl = RTS_CONTROL_ENABLE;
155 }
156 }
157 return SetCommState(file_.GetPlatformFile(), &config) != 0;
158 }
159
PostOpen()160 bool SerialConnection::PostOpen() {
161 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete
162 // immediately with any data that's available, even if there is none.
163 // This is OK because we never issue a read request until WaitCommEvent
164 // signals that data is available.
165 COMMTIMEOUTS timeouts = { 0 };
166 timeouts.ReadIntervalTimeout = MAXDWORD;
167 if (!::SetCommTimeouts(file_.GetPlatformFile(), &timeouts)) {
168 return false;
169 }
170
171 DCB config = { 0 };
172 config.DCBlength = sizeof(config);
173 if (!GetCommState(file_.GetPlatformFile(), &config)) {
174 return false;
175 }
176 // Setup some sane default state.
177 config.fBinary = TRUE;
178 config.fParity = FALSE;
179 config.fAbortOnError = TRUE;
180 config.fOutxCtsFlow = FALSE;
181 config.fOutxDsrFlow = FALSE;
182 config.fRtsControl = RTS_CONTROL_ENABLE;
183 config.fDtrControl = DTR_CONTROL_ENABLE;
184 config.fDsrSensitivity = FALSE;
185 config.fOutX = FALSE;
186 config.fInX = FALSE;
187 return SetCommState(file_.GetPlatformFile(), &config) != 0;
188 }
189
Flush() const190 bool SerialConnection::Flush() const {
191 return PurgeComm(file_.GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR) != 0;
192 }
193
GetControlSignals(api::serial::DeviceControlSignals * signals) const194 bool SerialConnection::GetControlSignals(
195 api::serial::DeviceControlSignals* signals) const {
196 DWORD status;
197 if (!GetCommModemStatus(file_.GetPlatformFile(), &status)) {
198 return false;
199 }
200 signals->dcd = (status & MS_RLSD_ON) != 0;
201 signals->cts = (status & MS_CTS_ON) != 0;
202 signals->dsr = (status & MS_DSR_ON) != 0;
203 signals->ri = (status & MS_RING_ON) != 0;
204 return true;
205 }
206
SetControlSignals(const api::serial::HostControlSignals & signals)207 bool SerialConnection::SetControlSignals(
208 const api::serial::HostControlSignals& signals) {
209 if (signals.dtr.get()) {
210 if (!EscapeCommFunction(file_.GetPlatformFile(),
211 *signals.dtr ? SETDTR : CLRDTR)) {
212 return false;
213 }
214 }
215 if (signals.rts.get()) {
216 if (!EscapeCommFunction(file_.GetPlatformFile(),
217 *signals.rts ? SETRTS : CLRRTS)) {
218 return false;
219 }
220 }
221 return true;
222 }
223
GetPortInfo(api::serial::ConnectionInfo * info) const224 bool SerialConnection::GetPortInfo(api::serial::ConnectionInfo* info) const {
225 DCB config = { 0 };
226 config.DCBlength = sizeof(config);
227 if (!GetCommState(file_.GetPlatformFile(), &config)) {
228 return false;
229 }
230 info->bitrate.reset(new int(SpeedConstantToBitrate(config.BaudRate)));
231 info->data_bits = DataBitsConstantToEnum(config.ByteSize);
232 info->parity_bit = ParityBitConstantToEnum(config.Parity);
233 info->stop_bits = StopBitsConstantToEnum(config.StopBits);
234 info->cts_flow_control.reset(new bool(config.fOutxCtsFlow != 0));
235 return true;
236 }
237
MaybeFixUpPortName(const std::string & port_name)238 std::string SerialConnection::MaybeFixUpPortName(
239 const std::string &port_name) {
240 // For COM numbers less than 9, CreateFile is called with a string such as
241 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added.
242 if (port_name.length() > std::string("COM9").length())
243 return std::string("\\\\.\\").append(port_name);
244
245 return port_name;
246 }
247
248 } // namespace extensions
249