| // 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 "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_port_enumerator.h" |
| #include "content/public/browser/browser_thread.h" |
| |
| using content::BrowserThread; |
| |
| namespace serial = extensions::api::serial; |
| |
| namespace extensions { |
| |
| const char kConnectionIdKey[] = "connectionId"; |
| const char kDataKey[] = "data"; |
| const char kBytesReadKey[] = "bytesRead"; |
| const char kBytesWrittenKey[] = "bytesWritten"; |
| const char kBitrateKey[] = "bitrate"; |
| const char kDataBitKey[] = "dataBit"; |
| const char kParityKey[] = "parityBit"; |
| const char kStopBitKey[] = "stopBit"; |
| const char kSuccessKey[] = "success"; |
| const char kDcdKey[] = "dcd"; |
| const char kCtsKey[] = "cts"; |
| |
| const char kErrorGetControlSignalsFailed[] = "Failed to get control signals."; |
| const char kErrorSetControlSignalsFailed[] = "Failed to set control signals."; |
| const char kSerialReadInvalidBytesToRead[] = "Number of bytes to read must " |
| "be a positive number less than 1,048,576."; |
| |
| SerialAsyncApiFunction::SerialAsyncApiFunction() |
| : manager_(NULL) { |
| } |
| |
| SerialAsyncApiFunction::~SerialAsyncApiFunction() { |
| } |
| |
| bool SerialAsyncApiFunction::PrePrepare() { |
| manager_ = ApiResourceManager<SerialConnection>::Get(GetProfile()); |
| DCHECK(manager_); |
| return true; |
| } |
| |
| 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); |
| } |
| |
| SerialGetPortsFunction::SerialGetPortsFunction() {} |
| |
| bool SerialGetPortsFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| return true; |
| } |
| |
| void SerialGetPortsFunction::Work() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| |
| base::ListValue* ports = new base::ListValue(); |
| SerialPortEnumerator::StringSet port_names = |
| SerialPortEnumerator::GenerateValidSerialPortNames(); |
| SerialPortEnumerator::StringSet::const_iterator i = port_names.begin(); |
| while (i != port_names.end()) { |
| ports->Append(new base::StringValue(*i++)); |
| } |
| |
| SetResult(ports); |
| } |
| |
| bool SerialGetPortsFunction::Respond() { |
| return true; |
| } |
| |
| // 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. |
| SerialOpenFunction::SerialOpenFunction() |
| : bitrate_(9600), databit_(serial::DATA_BIT_EIGHTBIT), |
| parity_(serial::PARITY_BIT_NOPARITY), |
| stopbit_(serial::STOP_BIT_ONESTOPBIT) { |
| } |
| |
| SerialOpenFunction::~SerialOpenFunction() { |
| } |
| |
| bool SerialOpenFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::Open::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| if (params_->options.get()) { |
| scoped_ptr<base::DictionaryValue> options = params_->options->ToValue(); |
| if (options->HasKey(kBitrateKey)) |
| EXTENSION_FUNCTION_VALIDATE(options->GetInteger(kBitrateKey, &bitrate_)); |
| if (options->HasKey(kDataBitKey)) { |
| std::string data; |
| options->GetString(kDataBitKey, &data); |
| if (!data.empty()) |
| databit_ = serial::ParseDataBit(data); |
| } |
| if (options->HasKey(kParityKey)) { |
| std::string parity; |
| options->GetString(kParityKey, &parity); |
| if (!parity.empty()) |
| parity_ = serial::ParseParityBit(parity); |
| } |
| if (options->HasKey(kStopBitKey)) { |
| std::string stopbit; |
| options->GetString(kStopBitKey, &stopbit); |
| if (!stopbit.empty()) |
| stopbit_ = serial::ParseStopBit(stopbit); |
| } |
| } |
| |
| return true; |
| } |
| |
| void SerialOpenFunction::AsyncWorkStart() { |
| Work(); |
| } |
| |
| void SerialOpenFunction::Work() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| const SerialPortEnumerator::StringSet name_set( |
| SerialPortEnumerator::GenerateValidSerialPortNames()); |
| if (DoesPortExist(params_->port)) { |
| SerialConnection* serial_connection = CreateSerialConnection( |
| params_->port, |
| bitrate_, |
| databit_, |
| parity_, |
| stopbit_, |
| extension_->id()); |
| CHECK(serial_connection); |
| int id = manager_->Add(serial_connection); |
| CHECK(id); |
| |
| bool open_result = serial_connection->Open(); |
| if (!open_result) { |
| serial_connection->Close(); |
| RemoveSerialConnection(id); |
| id = -1; |
| } |
| |
| base::DictionaryValue* result = new base::DictionaryValue(); |
| result->SetInteger(kConnectionIdKey, id); |
| SetResult(result); |
| AsyncWorkCompleted(); |
| } else { |
| base::DictionaryValue* result = new base::DictionaryValue(); |
| result->SetInteger(kConnectionIdKey, -1); |
| SetResult(result); |
| AsyncWorkCompleted(); |
| } |
| } |
| |
| SerialConnection* SerialOpenFunction::CreateSerialConnection( |
| const std::string& port, |
| int bitrate, |
| serial::DataBit databit, |
| serial::ParityBit parity, |
| serial::StopBit stopbit, |
| const std::string& owner_extension_id) { |
| return new SerialConnection(port, bitrate, databit, parity, stopbit, |
| owner_extension_id); |
| } |
| |
| bool SerialOpenFunction::DoesPortExist(const std::string& port) { |
| const SerialPortEnumerator::StringSet name_set( |
| SerialPortEnumerator::GenerateValidSerialPortNames()); |
| return SerialPortEnumerator::DoesPortExist(name_set, params_->port); |
| } |
| |
| bool SerialOpenFunction::Respond() { |
| return true; |
| } |
| |
| SerialCloseFunction::SerialCloseFunction() { |
| } |
| |
| SerialCloseFunction::~SerialCloseFunction() { |
| } |
| |
| bool SerialCloseFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::Close::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialCloseFunction::Work() { |
| bool close_result = false; |
| SerialConnection* serial_connection = GetSerialConnection( |
| params_->connection_id); |
| if (serial_connection) { |
| serial_connection->Close(); |
| RemoveSerialConnection(params_->connection_id); |
| close_result = true; |
| } |
| |
| SetResult(new base::FundamentalValue(close_result)); |
| } |
| |
| bool SerialCloseFunction::Respond() { |
| return true; |
| } |
| |
| SerialReadFunction::SerialReadFunction() { |
| } |
| |
| SerialReadFunction::~SerialReadFunction() { |
| } |
| |
| bool SerialReadFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::Read::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| if (params_->bytes_to_read <= 0 || params_->bytes_to_read >= 1024 * 1024) { |
| error_ = kSerialReadInvalidBytesToRead; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void SerialReadFunction::Work() { |
| int bytes_read = -1; |
| scoped_refptr<net::IOBufferWithSize> io_buffer( |
| new net::IOBufferWithSize(params_->bytes_to_read)); |
| SerialConnection* serial_connection(GetSerialConnection( |
| params_->connection_id)); |
| |
| if (serial_connection) |
| bytes_read = serial_connection->Read(io_buffer); |
| |
| base::DictionaryValue* result = new base::DictionaryValue(); |
| |
| // The API is defined to require a 'data' value, so we will always |
| // create a BinaryValue, even if it's zero-length. |
| if (bytes_read < 0) |
| bytes_read = 0; |
| result->SetInteger(kBytesReadKey, bytes_read); |
| result->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer( |
| io_buffer->data(), bytes_read)); |
| SetResult(result); |
| } |
| |
| bool SerialReadFunction::Respond() { |
| return true; |
| } |
| |
| SerialWriteFunction::SerialWriteFunction() |
| : io_buffer_(NULL), io_buffer_size_(0) { |
| } |
| |
| SerialWriteFunction::~SerialWriteFunction() { |
| } |
| |
| bool SerialWriteFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::Write::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| io_buffer_size_ = params_->data.size(); |
| io_buffer_ = new net::WrappedIOBuffer(params_->data.data()); |
| |
| return true; |
| } |
| |
| void SerialWriteFunction::Work() { |
| int bytes_written = -1; |
| SerialConnection* serial_connection = GetSerialConnection( |
| params_->connection_id); |
| if (serial_connection) |
| bytes_written = serial_connection->Write(io_buffer_, io_buffer_size_); |
| else |
| error_ = kSerialConnectionNotFoundError; |
| |
| base::DictionaryValue* result = new base::DictionaryValue(); |
| result->SetInteger(kBytesWrittenKey, bytes_written); |
| SetResult(result); |
| } |
| |
| bool SerialWriteFunction::Respond() { |
| return true; |
| } |
| |
| SerialFlushFunction::SerialFlushFunction() { |
| } |
| |
| SerialFlushFunction::~SerialFlushFunction() { |
| } |
| |
| bool SerialFlushFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::Flush::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| return true; |
| } |
| |
| void SerialFlushFunction::Work() { |
| bool flush_result = false; |
| SerialConnection* serial_connection = GetSerialConnection( |
| params_->connection_id); |
| if (serial_connection) { |
| serial_connection->Flush(); |
| flush_result = true; |
| } |
| |
| SetResult(new base::FundamentalValue(flush_result)); |
| } |
| |
| bool SerialFlushFunction::Respond() { |
| return true; |
| } |
| |
| SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() |
| : api_response_(false) { |
| } |
| |
| SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() { |
| } |
| |
| bool SerialGetControlSignalsFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::GetControlSignals::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialGetControlSignalsFunction::Work() { |
| base::DictionaryValue *result = new base::DictionaryValue(); |
| SerialConnection* serial_connection = GetSerialConnection( |
| params_->connection_id); |
| if (serial_connection) { |
| SerialConnection::ControlSignals control_signals = { 0 }; |
| if (serial_connection->GetControlSignals(control_signals)) { |
| api_response_ = true; |
| result->SetBoolean(kDcdKey, control_signals.dcd); |
| result->SetBoolean(kCtsKey, control_signals.cts); |
| } else { |
| error_ = kErrorGetControlSignalsFailed; |
| } |
| } else { |
| error_ = kSerialConnectionNotFoundError; |
| result->SetBoolean(kSuccessKey, false); |
| } |
| |
| SetResult(result); |
| } |
| |
| bool SerialGetControlSignalsFunction::Respond() { |
| return api_response_; |
| } |
| |
| SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() { |
| } |
| |
| SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() { |
| } |
| |
| bool SerialSetControlSignalsFunction::Prepare() { |
| set_work_thread_id(BrowserThread::FILE); |
| |
| params_ = api::serial::SetControlSignals::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| |
| return true; |
| } |
| |
| void SerialSetControlSignalsFunction::Work() { |
| SerialConnection* serial_connection = GetSerialConnection( |
| params_->connection_id); |
| if (serial_connection) { |
| SerialConnection::ControlSignals control_signals = { 0 }; |
| control_signals.should_set_dtr = params_->options.dtr.get() != NULL; |
| if (control_signals.should_set_dtr) |
| control_signals.dtr = *(params_->options.dtr); |
| control_signals.should_set_rts = params_->options.rts.get() != NULL; |
| if (control_signals.should_set_rts) |
| control_signals.rts = *(params_->options.rts); |
| if (serial_connection->SetControlSignals(control_signals)) { |
| SetResult(new base::FundamentalValue(true)); |
| } else { |
| error_ = kErrorSetControlSignalsFailed; |
| SetResult(new base::FundamentalValue(false)); |
| } |
| } else { |
| error_ = kSerialConnectionNotFoundError; |
| SetResult(new base::FundamentalValue(false)); |
| } |
| } |
| |
| bool SerialSetControlSignalsFunction::Respond() { |
| return true; |
| } |
| |
| } // namespace extensions |