1 // Copyright 2014 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 "extensions/browser/api/serial/serial_connection.h" 6 7 #include <string> 8 9 #include "base/files/file_path.h" 10 #include "base/lazy_instance.h" 11 #include "extensions/browser/api/api_resource_manager.h" 12 #include "extensions/common/api/serial.h" 13 14 namespace extensions { 15 16 namespace { 17 18 const int kDefaultBufferSize = 4096; 19 20 core_api::serial::SendError ConvertSendErrorFromMojo( 21 device::serial::SendError input) { 22 switch (input) { 23 case device::serial::SEND_ERROR_NONE: 24 return core_api::serial::SEND_ERROR_NONE; 25 case device::serial::SEND_ERROR_DISCONNECTED: 26 return core_api::serial::SEND_ERROR_DISCONNECTED; 27 case device::serial::SEND_ERROR_PENDING: 28 return core_api::serial::SEND_ERROR_PENDING; 29 case device::serial::SEND_ERROR_TIMEOUT: 30 return core_api::serial::SEND_ERROR_TIMEOUT; 31 case device::serial::SEND_ERROR_SYSTEM_ERROR: 32 return core_api::serial::SEND_ERROR_SYSTEM_ERROR; 33 } 34 return core_api::serial::SEND_ERROR_NONE; 35 } 36 37 core_api::serial::ReceiveError ConvertReceiveErrorFromMojo( 38 device::serial::ReceiveError input) { 39 switch (input) { 40 case device::serial::RECEIVE_ERROR_NONE: 41 return core_api::serial::RECEIVE_ERROR_NONE; 42 case device::serial::RECEIVE_ERROR_DISCONNECTED: 43 return core_api::serial::RECEIVE_ERROR_DISCONNECTED; 44 case device::serial::RECEIVE_ERROR_TIMEOUT: 45 return core_api::serial::RECEIVE_ERROR_TIMEOUT; 46 case device::serial::RECEIVE_ERROR_DEVICE_LOST: 47 return core_api::serial::RECEIVE_ERROR_DEVICE_LOST; 48 case device::serial::RECEIVE_ERROR_SYSTEM_ERROR: 49 return core_api::serial::RECEIVE_ERROR_SYSTEM_ERROR; 50 } 51 return core_api::serial::RECEIVE_ERROR_NONE; 52 } 53 54 core_api::serial::DataBits ConvertDataBitsFromMojo( 55 device::serial::DataBits input) { 56 switch (input) { 57 case device::serial::DATA_BITS_NONE: 58 return core_api::serial::DATA_BITS_NONE; 59 case device::serial::DATA_BITS_SEVEN: 60 return core_api::serial::DATA_BITS_SEVEN; 61 case device::serial::DATA_BITS_EIGHT: 62 return core_api::serial::DATA_BITS_EIGHT; 63 } 64 return core_api::serial::DATA_BITS_NONE; 65 } 66 67 device::serial::DataBits ConvertDataBitsToMojo( 68 core_api::serial::DataBits input) { 69 switch (input) { 70 case core_api::serial::DATA_BITS_NONE: 71 return device::serial::DATA_BITS_NONE; 72 case core_api::serial::DATA_BITS_SEVEN: 73 return device::serial::DATA_BITS_SEVEN; 74 case core_api::serial::DATA_BITS_EIGHT: 75 return device::serial::DATA_BITS_EIGHT; 76 } 77 return device::serial::DATA_BITS_NONE; 78 } 79 80 core_api::serial::ParityBit ConvertParityBitFromMojo( 81 device::serial::ParityBit input) { 82 switch (input) { 83 case device::serial::PARITY_BIT_NONE: 84 return core_api::serial::PARITY_BIT_NONE; 85 case device::serial::PARITY_BIT_ODD: 86 return core_api::serial::PARITY_BIT_ODD; 87 case device::serial::PARITY_BIT_NO: 88 return core_api::serial::PARITY_BIT_NO; 89 case device::serial::PARITY_BIT_EVEN: 90 return core_api::serial::PARITY_BIT_EVEN; 91 } 92 return core_api::serial::PARITY_BIT_NONE; 93 } 94 95 device::serial::ParityBit ConvertParityBitToMojo( 96 core_api::serial::ParityBit input) { 97 switch (input) { 98 case core_api::serial::PARITY_BIT_NONE: 99 return device::serial::PARITY_BIT_NONE; 100 case core_api::serial::PARITY_BIT_NO: 101 return device::serial::PARITY_BIT_NO; 102 case core_api::serial::PARITY_BIT_ODD: 103 return device::serial::PARITY_BIT_ODD; 104 case core_api::serial::PARITY_BIT_EVEN: 105 return device::serial::PARITY_BIT_EVEN; 106 } 107 return device::serial::PARITY_BIT_NONE; 108 } 109 110 core_api::serial::StopBits ConvertStopBitsFromMojo( 111 device::serial::StopBits input) { 112 switch (input) { 113 case device::serial::STOP_BITS_NONE: 114 return core_api::serial::STOP_BITS_NONE; 115 case device::serial::STOP_BITS_ONE: 116 return core_api::serial::STOP_BITS_ONE; 117 case device::serial::STOP_BITS_TWO: 118 return core_api::serial::STOP_BITS_TWO; 119 } 120 return core_api::serial::STOP_BITS_NONE; 121 } 122 123 device::serial::StopBits ConvertStopBitsToMojo( 124 core_api::serial::StopBits input) { 125 switch (input) { 126 case core_api::serial::STOP_BITS_NONE: 127 return device::serial::STOP_BITS_NONE; 128 case core_api::serial::STOP_BITS_ONE: 129 return device::serial::STOP_BITS_ONE; 130 case core_api::serial::STOP_BITS_TWO: 131 return device::serial::STOP_BITS_TWO; 132 } 133 return device::serial::STOP_BITS_NONE; 134 } 135 136 class SendBuffer : public device::ReadOnlyBuffer { 137 public: 138 SendBuffer( 139 const std::string& data, 140 const base::Callback<void(int, device::serial::SendError)>& callback) 141 : data_(data), callback_(callback) {} 142 virtual ~SendBuffer() {} 143 virtual const char* GetData() OVERRIDE { return data_.c_str(); } 144 virtual uint32_t GetSize() OVERRIDE { 145 return static_cast<uint32_t>(data_.size()); 146 } 147 virtual void Done(uint32_t bytes_read) OVERRIDE { 148 callback_.Run(bytes_read, device::serial::SEND_ERROR_NONE); 149 } 150 virtual void DoneWithError(uint32_t bytes_read, int32_t error) OVERRIDE { 151 callback_.Run(bytes_read, static_cast<device::serial::SendError>(error)); 152 } 153 154 private: 155 const std::string data_; 156 const base::Callback<void(int, device::serial::SendError)> callback_; 157 }; 158 159 class ReceiveBuffer : public device::WritableBuffer { 160 public: 161 ReceiveBuffer( 162 scoped_refptr<net::IOBuffer> buffer, 163 uint32_t size, 164 const base::Callback<void(int, device::serial::ReceiveError)>& callback) 165 : buffer_(buffer), size_(size), callback_(callback) {} 166 virtual ~ReceiveBuffer() {} 167 virtual char* GetData() OVERRIDE { return buffer_->data(); } 168 virtual uint32_t GetSize() OVERRIDE { return size_; } 169 virtual void Done(uint32_t bytes_written) OVERRIDE { 170 callback_.Run(bytes_written, device::serial::RECEIVE_ERROR_NONE); 171 } 172 virtual void DoneWithError(uint32_t bytes_written, int32_t error) OVERRIDE { 173 callback_.Run(bytes_written, 174 static_cast<device::serial::ReceiveError>(error)); 175 } 176 177 private: 178 scoped_refptr<net::IOBuffer> buffer_; 179 const uint32_t size_; 180 const base::Callback<void(int, device::serial::ReceiveError)> callback_; 181 }; 182 183 } // namespace 184 185 static base::LazyInstance< 186 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> > > 187 g_factory = LAZY_INSTANCE_INITIALIZER; 188 189 // static 190 template <> 191 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> >* 192 ApiResourceManager<SerialConnection>::GetFactoryInstance() { 193 return g_factory.Pointer(); 194 } 195 196 SerialConnection::SerialConnection(const std::string& port, 197 const std::string& owner_extension_id) 198 : ApiResource(owner_extension_id), 199 port_(port), 200 persistent_(false), 201 buffer_size_(kDefaultBufferSize), 202 receive_timeout_(0), 203 send_timeout_(0), 204 paused_(false), 205 io_handler_(device::SerialIoHandler::Create( 206 content::BrowserThread::GetMessageLoopProxyForThread( 207 content::BrowserThread::FILE))) { 208 DCHECK_CURRENTLY_ON(BrowserThread::IO); 209 } 210 211 SerialConnection::~SerialConnection() { 212 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED); 213 io_handler_->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED); 214 } 215 216 bool SerialConnection::IsPersistent() const { 217 return persistent(); 218 } 219 220 void SerialConnection::set_buffer_size(int buffer_size) { 221 buffer_size_ = buffer_size; 222 } 223 224 void SerialConnection::set_receive_timeout(int receive_timeout) { 225 receive_timeout_ = receive_timeout; 226 } 227 228 void SerialConnection::set_send_timeout(int send_timeout) { 229 send_timeout_ = send_timeout; 230 } 231 232 void SerialConnection::set_paused(bool paused) { 233 paused_ = paused; 234 if (paused) { 235 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE); 236 } 237 } 238 239 void SerialConnection::Open(const OpenCompleteCallback& callback) { 240 DCHECK_CURRENTLY_ON(BrowserThread::IO); 241 io_handler_->Open(port_, callback); 242 } 243 244 bool SerialConnection::Receive(const ReceiveCompleteCallback& callback) { 245 DCHECK_CURRENTLY_ON(BrowserThread::IO); 246 if (!receive_complete_.is_null()) 247 return false; 248 receive_complete_ = callback; 249 receive_buffer_ = new net::IOBuffer(buffer_size_); 250 io_handler_->Read(scoped_ptr<device::WritableBuffer>(new ReceiveBuffer( 251 receive_buffer_, 252 buffer_size_, 253 base::Bind(&SerialConnection::OnAsyncReadComplete, AsWeakPtr())))); 254 receive_timeout_task_.reset(); 255 if (receive_timeout_ > 0) { 256 receive_timeout_task_.reset(new TimeoutTask( 257 base::Bind(&SerialConnection::OnReceiveTimeout, AsWeakPtr()), 258 base::TimeDelta::FromMilliseconds(receive_timeout_))); 259 } 260 return true; 261 } 262 263 bool SerialConnection::Send(const std::string& data, 264 const SendCompleteCallback& callback) { 265 DCHECK_CURRENTLY_ON(BrowserThread::IO); 266 if (!send_complete_.is_null()) 267 return false; 268 send_complete_ = callback; 269 io_handler_->Write(scoped_ptr<device::ReadOnlyBuffer>(new SendBuffer( 270 data, base::Bind(&SerialConnection::OnAsyncWriteComplete, AsWeakPtr())))); 271 send_timeout_task_.reset(); 272 if (send_timeout_ > 0) { 273 send_timeout_task_.reset(new TimeoutTask( 274 base::Bind(&SerialConnection::OnSendTimeout, AsWeakPtr()), 275 base::TimeDelta::FromMilliseconds(send_timeout_))); 276 } 277 return true; 278 } 279 280 bool SerialConnection::Configure( 281 const core_api::serial::ConnectionOptions& options) { 282 DCHECK_CURRENTLY_ON(BrowserThread::IO); 283 if (options.persistent.get()) 284 set_persistent(*options.persistent); 285 if (options.name.get()) 286 set_name(*options.name); 287 if (options.buffer_size.get()) 288 set_buffer_size(*options.buffer_size); 289 if (options.receive_timeout.get()) 290 set_receive_timeout(*options.receive_timeout); 291 if (options.send_timeout.get()) 292 set_send_timeout(*options.send_timeout); 293 bool success = io_handler_->ConfigurePort( 294 *device::serial::ConnectionOptions::From(options)); 295 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE); 296 return success; 297 } 298 299 void SerialConnection::SetIoHandlerForTest( 300 scoped_refptr<device::SerialIoHandler> handler) { 301 io_handler_ = handler; 302 } 303 304 bool SerialConnection::GetInfo(core_api::serial::ConnectionInfo* info) const { 305 DCHECK_CURRENTLY_ON(BrowserThread::IO); 306 info->paused = paused_; 307 info->persistent = persistent_; 308 info->name = name_; 309 info->buffer_size = buffer_size_; 310 info->receive_timeout = receive_timeout_; 311 info->send_timeout = send_timeout_; 312 device::serial::ConnectionInfoPtr port_info = io_handler_->GetPortInfo(); 313 if (!port_info) 314 return false; 315 316 info->bitrate.reset(new int(port_info->bitrate)); 317 info->data_bits = ConvertDataBitsFromMojo(port_info->data_bits); 318 info->parity_bit = ConvertParityBitFromMojo(port_info->parity_bit); 319 info->stop_bits = ConvertStopBitsFromMojo(port_info->stop_bits); 320 info->cts_flow_control.reset(new bool(port_info->cts_flow_control)); 321 return true; 322 } 323 324 bool SerialConnection::Flush() const { 325 return io_handler_->Flush(); 326 } 327 328 bool SerialConnection::GetControlSignals( 329 core_api::serial::DeviceControlSignals* control_signals) const { 330 device::serial::DeviceControlSignalsPtr signals = 331 io_handler_->GetControlSignals(); 332 if (!signals) 333 return false; 334 335 control_signals->dcd = signals->dcd; 336 control_signals->cts = signals->cts; 337 control_signals->ri = signals->ri; 338 control_signals->dsr = signals->dsr; 339 return true; 340 } 341 342 bool SerialConnection::SetControlSignals( 343 const core_api::serial::HostControlSignals& control_signals) { 344 return io_handler_->SetControlSignals( 345 *device::serial::HostControlSignals::From(control_signals)); 346 } 347 348 void SerialConnection::OnReceiveTimeout() { 349 DCHECK_CURRENTLY_ON(BrowserThread::IO); 350 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT); 351 } 352 353 void SerialConnection::OnSendTimeout() { 354 DCHECK_CURRENTLY_ON(BrowserThread::IO); 355 io_handler_->CancelWrite(device::serial::SEND_ERROR_TIMEOUT); 356 } 357 358 void SerialConnection::OnAsyncReadComplete(int bytes_read, 359 device::serial::ReceiveError error) { 360 DCHECK_CURRENTLY_ON(BrowserThread::IO); 361 DCHECK(!receive_complete_.is_null()); 362 ReceiveCompleteCallback callback = receive_complete_; 363 receive_complete_.Reset(); 364 receive_timeout_task_.reset(); 365 callback.Run(std::string(receive_buffer_->data(), bytes_read), 366 ConvertReceiveErrorFromMojo(error)); 367 receive_buffer_ = NULL; 368 } 369 370 void SerialConnection::OnAsyncWriteComplete(int bytes_sent, 371 device::serial::SendError error) { 372 DCHECK_CURRENTLY_ON(BrowserThread::IO); 373 DCHECK(!send_complete_.is_null()); 374 SendCompleteCallback callback = send_complete_; 375 send_complete_.Reset(); 376 send_timeout_task_.reset(); 377 callback.Run(bytes_sent, ConvertSendErrorFromMojo(error)); 378 } 379 380 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure& closure, 381 const base::TimeDelta& delay) 382 : weak_factory_(this), closure_(closure), delay_(delay) { 383 base::MessageLoop::current()->PostDelayedTask( 384 FROM_HERE, 385 base::Bind(&TimeoutTask::Run, weak_factory_.GetWeakPtr()), 386 delay_); 387 } 388 389 SerialConnection::TimeoutTask::~TimeoutTask() { 390 } 391 392 void SerialConnection::TimeoutTask::Run() const { 393 closure_.Run(); 394 } 395 396 } // namespace extensions 397 398 namespace mojo { 399 400 // static 401 device::serial::HostControlSignalsPtr 402 TypeConverter<device::serial::HostControlSignalsPtr, 403 extensions::core_api::serial::HostControlSignals>:: 404 Convert(const extensions::core_api::serial::HostControlSignals& input) { 405 device::serial::HostControlSignalsPtr output( 406 device::serial::HostControlSignals::New()); 407 if (input.dtr.get()) { 408 output->has_dtr = true; 409 output->dtr = *input.dtr; 410 } 411 if (input.rts.get()) { 412 output->has_rts = true; 413 output->rts = *input.rts; 414 } 415 return output.Pass(); 416 } 417 418 // static 419 device::serial::ConnectionOptionsPtr 420 TypeConverter<device::serial::ConnectionOptionsPtr, 421 extensions::core_api::serial::ConnectionOptions>:: 422 Convert(const extensions::core_api::serial::ConnectionOptions& input) { 423 device::serial::ConnectionOptionsPtr output( 424 device::serial::ConnectionOptions::New()); 425 if (input.bitrate.get() && *input.bitrate > 0) 426 output->bitrate = *input.bitrate; 427 output->data_bits = extensions::ConvertDataBitsToMojo(input.data_bits); 428 output->parity_bit = extensions::ConvertParityBitToMojo(input.parity_bit); 429 output->stop_bits = extensions::ConvertStopBitsToMojo(input.stop_bits); 430 if (input.cts_flow_control.get()) { 431 output->has_cts_flow_control = true; 432 output->cts_flow_control = *input.cts_flow_control; 433 } 434 return output.Pass(); 435 } 436 437 } // namespace mojo 438