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 11namespace extensions { 12 13namespace { 14 15int 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 41int 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 51int 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 63int 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 73int 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 99api::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 109api::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 121api::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 133bool 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 160bool 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 190bool SerialConnection::Flush() const { 191 return PurgeComm(file_.GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR) != 0; 192} 193 194bool 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 207bool 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 224bool 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 238std::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