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_api.h" 6 7#include <algorithm> 8#include <vector> 9 10#include "base/values.h" 11#include "content/public/browser/browser_thread.h" 12#include "device/serial/serial_device_enumerator.h" 13#include "extensions/browser/api/serial/serial_connection.h" 14#include "extensions/browser/api/serial/serial_event_dispatcher.h" 15#include "extensions/common/api/serial.h" 16 17using content::BrowserThread; 18 19namespace extensions { 20 21namespace core_api { 22 23namespace { 24 25// It's a fool's errand to come up with a default bitrate, because we don't get 26// to control both sides of the communication. Unless the other side has 27// implemented auto-bitrate detection (rare), if we pick the wrong rate, then 28// you're gonna have a bad time. Close doesn't count. 29// 30// But we'd like to pick something that has a chance of working, and 9600 is a 31// good balance between popularity and speed. So 9600 it is. 32const int kDefaultBufferSize = 4096; 33const int kDefaultBitrate = 9600; 34const serial::DataBits kDefaultDataBits = serial::DATA_BITS_EIGHT; 35const serial::ParityBit kDefaultParityBit = serial::PARITY_BIT_NO; 36const serial::StopBits kDefaultStopBits = serial::STOP_BITS_ONE; 37const int kDefaultReceiveTimeout = 0; 38const int kDefaultSendTimeout = 0; 39 40const char kErrorConnectFailed[] = "Failed to connect to the port."; 41const char kErrorSerialConnectionNotFound[] = "Serial connection not found."; 42const char kErrorGetControlSignalsFailed[] = "Failed to get control signals."; 43 44template <class T> 45void SetDefaultScopedPtrValue(scoped_ptr<T>& ptr, const T& value) { 46 if (!ptr.get()) 47 ptr.reset(new T(value)); 48} 49 50} // namespace 51 52SerialAsyncApiFunction::SerialAsyncApiFunction() : manager_(NULL) { 53} 54 55SerialAsyncApiFunction::~SerialAsyncApiFunction() { 56} 57 58bool SerialAsyncApiFunction::PrePrepare() { 59 manager_ = ApiResourceManager<SerialConnection>::Get(browser_context()); 60 DCHECK(manager_); 61 return true; 62} 63 64bool SerialAsyncApiFunction::Respond() { 65 return error_.empty(); 66} 67 68SerialConnection* SerialAsyncApiFunction::GetSerialConnection( 69 int api_resource_id) { 70 return manager_->Get(extension_->id(), api_resource_id); 71} 72 73void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) { 74 manager_->Remove(extension_->id(), api_resource_id); 75} 76 77SerialGetDevicesFunction::SerialGetDevicesFunction() { 78} 79 80bool SerialGetDevicesFunction::Prepare() { 81 set_work_thread_id(BrowserThread::FILE); 82 return true; 83} 84 85void SerialGetDevicesFunction::Work() { 86 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 87 88 scoped_ptr<device::SerialDeviceEnumerator> enumerator = 89 device::SerialDeviceEnumerator::Create(); 90 mojo::Array<device::serial::DeviceInfoPtr> devices = enumerator->GetDevices(); 91 results_ = serial::GetDevices::Results::Create( 92 devices.To<std::vector<linked_ptr<serial::DeviceInfo> > >()); 93} 94 95SerialConnectFunction::SerialConnectFunction() { 96} 97 98SerialConnectFunction::~SerialConnectFunction() { 99} 100 101bool SerialConnectFunction::Prepare() { 102 params_ = serial::Connect::Params::Create(*args_); 103 EXTENSION_FUNCTION_VALIDATE(params_.get()); 104 105 // Fill in any omitted options to ensure a known initial configuration. 106 if (!params_->options.get()) 107 params_->options.reset(new serial::ConnectionOptions()); 108 serial::ConnectionOptions* options = params_->options.get(); 109 110 SetDefaultScopedPtrValue(options->persistent, false); 111 SetDefaultScopedPtrValue(options->buffer_size, kDefaultBufferSize); 112 SetDefaultScopedPtrValue(options->bitrate, kDefaultBitrate); 113 SetDefaultScopedPtrValue(options->cts_flow_control, false); 114 SetDefaultScopedPtrValue(options->receive_timeout, kDefaultReceiveTimeout); 115 SetDefaultScopedPtrValue(options->send_timeout, kDefaultSendTimeout); 116 117 if (options->data_bits == serial::DATA_BITS_NONE) 118 options->data_bits = kDefaultDataBits; 119 if (options->parity_bit == serial::PARITY_BIT_NONE) 120 options->parity_bit = kDefaultParityBit; 121 if (options->stop_bits == serial::STOP_BITS_NONE) 122 options->stop_bits = kDefaultStopBits; 123 124 serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context()); 125 DCHECK(serial_event_dispatcher_); 126 127 return true; 128} 129 130void SerialConnectFunction::AsyncWorkStart() { 131 DCHECK_CURRENTLY_ON(BrowserThread::IO); 132 connection_ = CreateSerialConnection(params_->path, extension_->id()); 133 connection_->Open(base::Bind(&SerialConnectFunction::OnConnected, this)); 134} 135 136void SerialConnectFunction::OnConnected(bool success) { 137 DCHECK(connection_); 138 139 if (success) { 140 if (!connection_->Configure(*params_->options.get())) { 141 delete connection_; 142 connection_ = NULL; 143 } 144 } else { 145 delete connection_; 146 connection_ = NULL; 147 } 148 149 BrowserThread::PostTask( 150 BrowserThread::IO, 151 FROM_HERE, 152 base::Bind(&SerialConnectFunction::FinishConnect, this)); 153} 154 155void SerialConnectFunction::FinishConnect() { 156 DCHECK_CURRENTLY_ON(BrowserThread::IO); 157 if (!connection_) { 158 error_ = kErrorConnectFailed; 159 } else { 160 int id = manager_->Add(connection_); 161 serial::ConnectionInfo info; 162 info.connection_id = id; 163 if (connection_->GetInfo(&info)) { 164 serial_event_dispatcher_->PollConnection(extension_->id(), id); 165 results_ = serial::Connect::Results::Create(info); 166 } else { 167 RemoveSerialConnection(id); 168 error_ = kErrorConnectFailed; 169 } 170 } 171 AsyncWorkCompleted(); 172} 173 174SerialConnection* SerialConnectFunction::CreateSerialConnection( 175 const std::string& port, 176 const std::string& extension_id) const { 177 return new SerialConnection(port, extension_id); 178} 179 180SerialUpdateFunction::SerialUpdateFunction() { 181} 182 183SerialUpdateFunction::~SerialUpdateFunction() { 184} 185 186bool SerialUpdateFunction::Prepare() { 187 params_ = serial::Update::Params::Create(*args_); 188 EXTENSION_FUNCTION_VALIDATE(params_.get()); 189 190 return true; 191} 192 193void SerialUpdateFunction::Work() { 194 SerialConnection* connection = GetSerialConnection(params_->connection_id); 195 if (!connection) { 196 error_ = kErrorSerialConnectionNotFound; 197 return; 198 } 199 bool success = connection->Configure(params_->options); 200 results_ = serial::Update::Results::Create(success); 201} 202 203SerialDisconnectFunction::SerialDisconnectFunction() { 204} 205 206SerialDisconnectFunction::~SerialDisconnectFunction() { 207} 208 209bool SerialDisconnectFunction::Prepare() { 210 params_ = serial::Disconnect::Params::Create(*args_); 211 EXTENSION_FUNCTION_VALIDATE(params_.get()); 212 213 return true; 214} 215 216void SerialDisconnectFunction::Work() { 217 SerialConnection* connection = GetSerialConnection(params_->connection_id); 218 if (!connection) { 219 error_ = kErrorSerialConnectionNotFound; 220 return; 221 } 222 RemoveSerialConnection(params_->connection_id); 223 results_ = serial::Disconnect::Results::Create(true); 224} 225 226SerialSendFunction::SerialSendFunction() { 227} 228 229SerialSendFunction::~SerialSendFunction() { 230} 231 232bool SerialSendFunction::Prepare() { 233 params_ = serial::Send::Params::Create(*args_); 234 EXTENSION_FUNCTION_VALIDATE(params_.get()); 235 236 return true; 237} 238 239void SerialSendFunction::AsyncWorkStart() { 240 SerialConnection* connection = GetSerialConnection(params_->connection_id); 241 if (!connection) { 242 error_ = kErrorSerialConnectionNotFound; 243 AsyncWorkCompleted(); 244 return; 245 } 246 247 if (!connection->Send( 248 params_->data, 249 base::Bind(&SerialSendFunction::OnSendComplete, this))) { 250 OnSendComplete(0, serial::SEND_ERROR_PENDING); 251 } 252} 253 254void SerialSendFunction::OnSendComplete(int bytes_sent, 255 serial::SendError error) { 256 serial::SendInfo send_info; 257 send_info.bytes_sent = bytes_sent; 258 send_info.error = error; 259 results_ = serial::Send::Results::Create(send_info); 260 AsyncWorkCompleted(); 261} 262 263SerialFlushFunction::SerialFlushFunction() { 264} 265 266SerialFlushFunction::~SerialFlushFunction() { 267} 268 269bool SerialFlushFunction::Prepare() { 270 params_ = serial::Flush::Params::Create(*args_); 271 EXTENSION_FUNCTION_VALIDATE(params_.get()); 272 return true; 273} 274 275void SerialFlushFunction::Work() { 276 SerialConnection* connection = GetSerialConnection(params_->connection_id); 277 if (!connection) { 278 error_ = kErrorSerialConnectionNotFound; 279 return; 280 } 281 282 bool success = connection->Flush(); 283 results_ = serial::Flush::Results::Create(success); 284} 285 286SerialSetPausedFunction::SerialSetPausedFunction() { 287} 288 289SerialSetPausedFunction::~SerialSetPausedFunction() { 290} 291 292bool SerialSetPausedFunction::Prepare() { 293 params_ = serial::SetPaused::Params::Create(*args_); 294 EXTENSION_FUNCTION_VALIDATE(params_.get()); 295 296 serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context()); 297 DCHECK(serial_event_dispatcher_); 298 return true; 299} 300 301void SerialSetPausedFunction::Work() { 302 SerialConnection* connection = GetSerialConnection(params_->connection_id); 303 if (!connection) { 304 error_ = kErrorSerialConnectionNotFound; 305 return; 306 } 307 308 if (params_->paused != connection->paused()) { 309 connection->set_paused(params_->paused); 310 if (!params_->paused) { 311 serial_event_dispatcher_->PollConnection(extension_->id(), 312 params_->connection_id); 313 } 314 } 315 316 results_ = serial::SetPaused::Results::Create(); 317} 318 319SerialGetInfoFunction::SerialGetInfoFunction() { 320} 321 322SerialGetInfoFunction::~SerialGetInfoFunction() { 323} 324 325bool SerialGetInfoFunction::Prepare() { 326 params_ = serial::GetInfo::Params::Create(*args_); 327 EXTENSION_FUNCTION_VALIDATE(params_.get()); 328 329 return true; 330} 331 332void SerialGetInfoFunction::Work() { 333 SerialConnection* connection = GetSerialConnection(params_->connection_id); 334 if (!connection) { 335 error_ = kErrorSerialConnectionNotFound; 336 return; 337 } 338 339 serial::ConnectionInfo info; 340 info.connection_id = params_->connection_id; 341 connection->GetInfo(&info); 342 results_ = serial::GetInfo::Results::Create(info); 343} 344 345SerialGetConnectionsFunction::SerialGetConnectionsFunction() { 346} 347 348SerialGetConnectionsFunction::~SerialGetConnectionsFunction() { 349} 350 351bool SerialGetConnectionsFunction::Prepare() { 352 return true; 353} 354 355void SerialGetConnectionsFunction::Work() { 356 std::vector<linked_ptr<serial::ConnectionInfo> > infos; 357 const base::hash_set<int>* connection_ids = 358 manager_->GetResourceIds(extension_->id()); 359 if (connection_ids) { 360 for (base::hash_set<int>::const_iterator it = connection_ids->begin(); 361 it != connection_ids->end(); 362 ++it) { 363 int connection_id = *it; 364 SerialConnection* connection = GetSerialConnection(connection_id); 365 if (connection) { 366 linked_ptr<serial::ConnectionInfo> info(new serial::ConnectionInfo()); 367 info->connection_id = connection_id; 368 connection->GetInfo(info.get()); 369 infos.push_back(info); 370 } 371 } 372 } 373 results_ = serial::GetConnections::Results::Create(infos); 374} 375 376SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() { 377} 378 379SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() { 380} 381 382bool SerialGetControlSignalsFunction::Prepare() { 383 params_ = serial::GetControlSignals::Params::Create(*args_); 384 EXTENSION_FUNCTION_VALIDATE(params_.get()); 385 386 return true; 387} 388 389void SerialGetControlSignalsFunction::Work() { 390 SerialConnection* connection = GetSerialConnection(params_->connection_id); 391 if (!connection) { 392 error_ = kErrorSerialConnectionNotFound; 393 return; 394 } 395 396 serial::DeviceControlSignals signals; 397 if (!connection->GetControlSignals(&signals)) { 398 error_ = kErrorGetControlSignalsFailed; 399 return; 400 } 401 402 results_ = serial::GetControlSignals::Results::Create(signals); 403} 404 405SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() { 406} 407 408SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() { 409} 410 411bool SerialSetControlSignalsFunction::Prepare() { 412 params_ = serial::SetControlSignals::Params::Create(*args_); 413 EXTENSION_FUNCTION_VALIDATE(params_.get()); 414 415 return true; 416} 417 418void SerialSetControlSignalsFunction::Work() { 419 SerialConnection* connection = GetSerialConnection(params_->connection_id); 420 if (!connection) { 421 error_ = kErrorSerialConnectionNotFound; 422 return; 423 } 424 425 bool success = connection->SetControlSignals(params_->signals); 426 results_ = serial::SetControlSignals::Results::Create(success); 427} 428 429} // namespace core_api 430 431} // namespace extensions 432 433namespace mojo { 434 435// static 436linked_ptr<extensions::core_api::serial::DeviceInfo> TypeConverter< 437 linked_ptr<extensions::core_api::serial::DeviceInfo>, 438 device::serial::DeviceInfoPtr>::Convert(const device::serial::DeviceInfoPtr& 439 device) { 440 linked_ptr<extensions::core_api::serial::DeviceInfo> info( 441 new extensions::core_api::serial::DeviceInfo); 442 info->path = device->path; 443 if (device->has_vendor_id) 444 info->vendor_id.reset(new int(static_cast<int>(device->vendor_id))); 445 if (device->has_product_id) 446 info->product_id.reset(new int(static_cast<int>(device->product_id))); 447 if (device->display_name) 448 info->display_name.reset(new std::string(device->display_name)); 449 return info; 450} 451 452} // namespace mojo 453