blob: 3f33da4686c5f29439c8992c26599ea0d0aad330 [file] [log] [blame]
// 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(profile());
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