Home | History | Annotate | Download | only in serial
      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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    190 bool SerialConnection::Flush() const {
    191   return PurgeComm(file_.GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR) != 0;
    192 }
    193 
    194 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 
    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 
    224 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 
    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