| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/extensions/api/serial/serial_api.h" |
| |
| #include <algorithm> |
| |
| #include "base/values.h" |
| #include "chrome/browser/extensions/extension_system.h" |
| #include "chrome/browser/extensions/api/serial/serial_connection.h" |
| #include "chrome/browser/extensions/api/serial/serial_event_dispatcher.h" |
| #include "chrome/browser/extensions/api/serial/serial_port_enumerator.h" |
| #include "chrome/common/extensions/api/serial.h" |
| #include "content/public/browser/browser_thread.h" |
| |
| using content::BrowserThread; |
| |
| namespace extensions { |
| |
| namespace api { |
| |
| namespace { |
| |
| // It's a fool's errand to come up with a default bitrate, because we don't get |
| // to control both sides of the communication. Unless the other side has |
| // implemented auto-bitrate detection (rare), if we pick the wrong rate, then |
| // you're gonna have a bad time. Close doesn't count. |
| // |
| // But we'd like to pick something that has a chance of working, and 9600 is a |
| // good balance between popularity and speed. So 9600 it is. |
| const int kDefaultBufferSize = 4096; |
| const int kDefaultBitrate = 9600; |
| const serial::DataBits kDefaultDataBits = serial::DATA_BITS_EIGHT; |
| const serial::ParityBit kDefaultParityBit = serial::PARITY_BIT_NO; |
| const serial::StopBits kDefaultStopBits = serial::STOP_BITS_ONE; |
| const int kDefaultReceiveTimeout = 0; |
| const int kDefaultSendTimeout = 0; |
| |
| const char kErrorConnectFailed[] = "Failed to connect to the port."; |
| const char kErrorSerialConnectionNotFound[] = "Serial connection not found."; |
| const char kErrorGetControlSignalsFailed[] = "Failed to get control signals."; |
| |
| template <class T> |
| void SetDefaultScopedPtrValue(scoped_ptr<T>& ptr, const T& value) { |
| if (!ptr.get()) |
| ptr.reset(new T(value)); |
| } |
| |
| } // namespace |
| |
| SerialAsyncApiFunction::SerialAsyncApiFunction() |
| : manager_(NULL) { |
| } |
| |
| SerialAsyncApiFunction::~SerialAsyncApiFunction() {} |
| |
| bool SerialAsyncApiFunction::PrePrepare() { |
| manager_ = ApiResourceManager<SerialConnection>::Get(GetProfile()); |
| DCHECK(manager_); |
| return true; |
| } |
| |
| bool SerialAsyncApiFunction::Respond() { |
| return error_.empty(); |
| } |
| |
| SerialConnection* SerialAsyncApiFunction::GetSerialConnection( |
| int api_resource_id) { |
| return manager_->Get(extension_->id(), api_resource_id); |
| } |
| |
| void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) { |
| manager_->Remove(extension_->id(), api_resource_id); |
| } |
| |
| SerialGetDevicesFunction::SerialGetDevicesFunction() {} |
| |
| bool SerialGetDevicesFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| return true; |
| } |
| |
| void SerialGetDevicesFunction::Work() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| |
| std::vector<linked_ptr<serial::DeviceInfo> > devices; |
| SerialPortEnumerator::StringSet port_names = |
| SerialPortEnumerator::GenerateValidSerialPortNames(); |
| for (SerialPortEnumerator::StringSet::const_iterator iter = |
| port_names.begin(); |
| iter != port_names.end(); |
| ++iter) { |
| linked_ptr<serial::DeviceInfo> info(new serial::DeviceInfo); |
| info->path = *iter; |
| devices.push_back(info); |
| } |
| results_ = serial::GetDevices::Results::Create(devices); |
| } |
| |
| SerialConnectFunction::SerialConnectFunction() {} |
| |
| SerialConnectFunction::~SerialConnectFunction() {} |
| |
| bool SerialConnectFunction::Prepare() { |
| params_ = serial::Connect::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| // Fill in any omitted options to ensure a known initial configuration. |
| if (!params_->options.get()) |
| params_->options.reset(new serial::ConnectionOptions()); |
| serial::ConnectionOptions* options = params_->options.get(); |
| |
| SetDefaultScopedPtrValue(options->persistent, false); |
| SetDefaultScopedPtrValue(options->buffer_size, kDefaultBufferSize); |
| SetDefaultScopedPtrValue(options->bitrate, kDefaultBitrate); |
| SetDefaultScopedPtrValue(options->cts_flow_control, false); |
| SetDefaultScopedPtrValue(options->receive_timeout, kDefaultReceiveTimeout); |
| SetDefaultScopedPtrValue(options->send_timeout, kDefaultSendTimeout); |
| |
| if (options->data_bits == serial::DATA_BITS_NONE) |
| options->data_bits = kDefaultDataBits; |
| if (options->parity_bit == serial::PARITY_BIT_NONE) |
| options->parity_bit = kDefaultParityBit; |
| if (options->stop_bits == serial::STOP_BITS_NONE) |
| options->stop_bits = kDefaultStopBits; |
| |
| serial_event_dispatcher_ = SerialEventDispatcher::Get(GetProfile()); |
| DCHECK(serial_event_dispatcher_); |
| |
| return true; |
| } |
| |
| void SerialConnectFunction::AsyncWorkStart() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| connection_ = CreateSerialConnection(params_->path, extension_->id()); |
| connection_->Open(base::Bind(&SerialConnectFunction::OnConnected, this)); |
| } |
| |
| void SerialConnectFunction::OnConnected(bool success) { |
| DCHECK(connection_); |
| |
| if (success) { |
| if (!connection_->Configure(*params_->options.get())) { |
| connection_->Close(); |
| delete connection_; |
| connection_ = NULL; |
| } |
| } else { |
| delete connection_; |
| connection_ = NULL; |
| } |
| |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::Bind(&SerialConnectFunction::FinishConnect, |
| this)); |
| } |
| |
| void SerialConnectFunction::FinishConnect() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| if (!connection_) { |
| error_ = kErrorConnectFailed; |
| } else { |
| int id = manager_->Add(connection_); |
| serial::ConnectionInfo info; |
| info.connection_id = id; |
| if (connection_->GetInfo(&info)) { |
| serial_event_dispatcher_->PollConnection(extension_->id(), id); |
| results_ = serial::Connect::Results::Create(info); |
| } else { |
| connection_->Close(); |
| RemoveSerialConnection(id); |
| error_ = kErrorConnectFailed; |
| } |
| } |
| AsyncWorkCompleted(); |
| } |
| |
| SerialConnection* SerialConnectFunction::CreateSerialConnection( |
| const std::string& port, const std::string& extension_id) const { |
| return new SerialConnection(port, extension_id); |
| } |
| |
| SerialUpdateFunction::SerialUpdateFunction() {} |
| |
| SerialUpdateFunction::~SerialUpdateFunction() {} |
| |
| bool SerialUpdateFunction::Prepare() { |
| params_ = serial::Update::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialUpdateFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| bool success = connection->Configure(params_->options); |
| results_ = serial::Update::Results::Create(success); |
| } |
| |
| SerialDisconnectFunction::SerialDisconnectFunction() {} |
| |
| SerialDisconnectFunction::~SerialDisconnectFunction() {} |
| |
| bool SerialDisconnectFunction::Prepare() { |
| params_ = serial::Disconnect::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialDisconnectFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| connection->Close(); |
| RemoveSerialConnection(params_->connection_id); |
| results_ = serial::Disconnect::Results::Create(true); |
| } |
| |
| SerialSendFunction::SerialSendFunction() {} |
| |
| SerialSendFunction::~SerialSendFunction() {} |
| |
| bool SerialSendFunction::Prepare() { |
| params_ = serial::Send::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialSendFunction::AsyncWorkStart() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| if (!connection->Send(params_->data, |
| base::Bind(&SerialSendFunction::OnSendComplete, |
| this))) { |
| OnSendComplete(0, serial::SEND_ERROR_PENDING); |
| } |
| } |
| |
| void SerialSendFunction::OnSendComplete(int bytes_sent, |
| serial::SendError error) { |
| serial::SendInfo send_info; |
| send_info.bytes_sent = bytes_sent; |
| send_info.error = error; |
| results_ = serial::Send::Results::Create(send_info); |
| AsyncWorkCompleted(); |
| } |
| |
| SerialFlushFunction::SerialFlushFunction() {} |
| |
| SerialFlushFunction::~SerialFlushFunction() {} |
| |
| bool SerialFlushFunction::Prepare() { |
| params_ = serial::Flush::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| return true; |
| } |
| |
| void SerialFlushFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| |
| bool success = connection->Flush(); |
| results_ = serial::Flush::Results::Create(success); |
| } |
| |
| SerialSetPausedFunction::SerialSetPausedFunction() {} |
| |
| SerialSetPausedFunction::~SerialSetPausedFunction() {} |
| |
| bool SerialSetPausedFunction::Prepare() { |
| params_ = serial::SetPaused::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| serial_event_dispatcher_ = SerialEventDispatcher::Get(GetProfile()); |
| DCHECK(serial_event_dispatcher_); |
| return true; |
| } |
| |
| void SerialSetPausedFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| |
| if (params_->paused != connection->paused()) { |
| connection->set_paused(params_->paused); |
| if (!params_->paused) { |
| serial_event_dispatcher_->PollConnection(extension_->id(), |
| params_->connection_id); |
| } |
| } |
| |
| results_ = serial::SetPaused::Results::Create(); |
| } |
| |
| SerialGetInfoFunction::SerialGetInfoFunction() {} |
| |
| SerialGetInfoFunction::~SerialGetInfoFunction() {} |
| |
| bool SerialGetInfoFunction::Prepare() { |
| params_ = serial::GetInfo::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialGetInfoFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| |
| serial::ConnectionInfo info; |
| info.connection_id = params_->connection_id; |
| connection->GetInfo(&info); |
| results_ = serial::GetInfo::Results::Create(info); |
| } |
| |
| SerialGetConnectionsFunction::SerialGetConnectionsFunction() {} |
| |
| SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {} |
| |
| bool SerialGetConnectionsFunction::Prepare() { |
| return true; |
| } |
| |
| void SerialGetConnectionsFunction::Work() { |
| std::vector<linked_ptr<serial::ConnectionInfo> > infos; |
| const base::hash_set<int>* connection_ids = manager_->GetResourceIds( |
| extension_->id()); |
| if (connection_ids) { |
| for (base::hash_set<int>::const_iterator it = connection_ids->begin(); |
| it != connection_ids->end(); ++it) { |
| int connection_id = *it; |
| SerialConnection *connection = GetSerialConnection(connection_id); |
| if (connection) { |
| linked_ptr<serial::ConnectionInfo> info(new serial::ConnectionInfo()); |
| info->connection_id = connection_id; |
| connection->GetInfo(info.get()); |
| infos.push_back(info); |
| } |
| } |
| } |
| results_ = serial::GetConnections::Results::Create(infos); |
| } |
| |
| SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {} |
| |
| SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {} |
| |
| bool SerialGetControlSignalsFunction::Prepare() { |
| params_ = serial::GetControlSignals::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialGetControlSignalsFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| |
| serial::DeviceControlSignals signals; |
| if (!connection->GetControlSignals(&signals)) { |
| error_ = kErrorGetControlSignalsFailed; |
| return; |
| } |
| |
| results_ = serial::GetControlSignals::Results::Create(signals); |
| } |
| |
| SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {} |
| |
| SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {} |
| |
| bool SerialSetControlSignalsFunction::Prepare() { |
| params_ = serial::SetControlSignals::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialSetControlSignalsFunction::Work() { |
| SerialConnection* connection = GetSerialConnection(params_->connection_id); |
| if (!connection) { |
| error_ = kErrorSerialConnectionNotFound; |
| return; |
| } |
| |
| bool success = connection->SetControlSignals(params_->signals); |
| results_ = serial::SetControlSignals::Results::Create(success); |
| } |
| |
| } // namespace api |
| |
| } // namespace extensions |