1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/api/serial/serial_api.h"
7 #include "base/values.h"
8 #include "chrome/browser/extensions/extension_system.h"
9 #include "chrome/browser/extensions/api/serial/serial_connection.h"
10 #include "chrome/browser/extensions/api/serial/serial_port_enumerator.h"
11 #include "content/public/browser/browser_thread.h"
13 using content::BrowserThread;
15 namespace serial = extensions::api::serial;
17 namespace extensions {
19 const char kConnectionIdKey[] = "connectionId";
20 const char kDataKey[] = "data";
21 const char kBytesReadKey[] = "bytesRead";
22 const char kBytesWrittenKey[] = "bytesWritten";
23 const char kBitrateKey[] = "bitrate";
24 const char kDataBitKey[] = "dataBit";
25 const char kParityKey[] = "parityBit";
26 const char kStopBitKey[] = "stopBit";
27 const char kSuccessKey[] = "success";
28 const char kDcdKey[] = "dcd";
29 const char kCtsKey[] = "cts";
31 const char kErrorGetControlSignalsFailed[] = "Failed to get control signals.";
32 const char kErrorSetControlSignalsFailed[] = "Failed to set control signals.";
33 const char kSerialReadInvalidBytesToRead[] = "Number of bytes to read must "
34 "be a positive number less than 1,048,576.";
36 SerialAsyncApiFunction::SerialAsyncApiFunction()
40 SerialAsyncApiFunction::~SerialAsyncApiFunction() {
43 bool SerialAsyncApiFunction::PrePrepare() {
44 manager_ = ApiResourceManager<SerialConnection>::Get(GetProfile());
49 SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
50 int api_resource_id) {
51 return manager_->Get(extension_->id(), api_resource_id);
54 void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
55 manager_->Remove(extension_->id(), api_resource_id);
58 SerialGetPortsFunction::SerialGetPortsFunction() {}
60 bool SerialGetPortsFunction::Prepare() {
61 set_work_thread_id(BrowserThread::FILE);
65 void SerialGetPortsFunction::Work() {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
68 base::ListValue* ports = new base::ListValue();
69 SerialPortEnumerator::StringSet port_names =
70 SerialPortEnumerator::GenerateValidSerialPortNames();
71 SerialPortEnumerator::StringSet::const_iterator i = port_names.begin();
72 while (i != port_names.end()) {
73 ports->Append(new base::StringValue(*i++));
79 bool SerialGetPortsFunction::Respond() {
83 // It's a fool's errand to come up with a default bitrate, because we don't get
84 // to control both sides of the communication. Unless the other side has
85 // implemented auto-bitrate detection (rare), if we pick the wrong rate, then
86 // you're gonna have a bad time. Close doesn't count.
88 // But we'd like to pick something that has a chance of working, and 9600 is a
89 // good balance between popularity and speed. So 9600 it is.
90 SerialOpenFunction::SerialOpenFunction()
91 : bitrate_(9600), databit_(serial::DATA_BIT_EIGHTBIT),
92 parity_(serial::PARITY_BIT_NOPARITY),
93 stopbit_(serial::STOP_BIT_ONESTOPBIT) {
96 SerialOpenFunction::~SerialOpenFunction() {
99 bool SerialOpenFunction::Prepare() {
100 set_work_thread_id(BrowserThread::FILE);
102 params_ = api::serial::Open::Params::Create(*args_);
103 EXTENSION_FUNCTION_VALIDATE(params_.get());
105 if (params_->options.get()) {
106 scoped_ptr<base::DictionaryValue> options = params_->options->ToValue();
107 if (options->HasKey(kBitrateKey))
108 EXTENSION_FUNCTION_VALIDATE(options->GetInteger(kBitrateKey, &bitrate_));
109 if (options->HasKey(kDataBitKey)) {
111 options->GetString(kDataBitKey, &data);
113 databit_ = serial::ParseDataBit(data);
115 if (options->HasKey(kParityKey)) {
117 options->GetString(kParityKey, &parity);
119 parity_ = serial::ParseParityBit(parity);
121 if (options->HasKey(kStopBitKey)) {
123 options->GetString(kStopBitKey, &stopbit);
124 if (!stopbit.empty())
125 stopbit_ = serial::ParseStopBit(stopbit);
132 void SerialOpenFunction::AsyncWorkStart() {
136 void SerialOpenFunction::Work() {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
138 const SerialPortEnumerator::StringSet name_set(
139 SerialPortEnumerator::GenerateValidSerialPortNames());
140 if (DoesPortExist(params_->port)) {
141 SerialConnection* serial_connection = CreateSerialConnection(
148 CHECK(serial_connection);
149 int id = manager_->Add(serial_connection);
152 bool open_result = serial_connection->Open();
154 serial_connection->Close();
155 RemoveSerialConnection(id);
159 base::DictionaryValue* result = new base::DictionaryValue();
160 result->SetInteger(kConnectionIdKey, id);
162 AsyncWorkCompleted();
164 base::DictionaryValue* result = new base::DictionaryValue();
165 result->SetInteger(kConnectionIdKey, -1);
167 AsyncWorkCompleted();
171 SerialConnection* SerialOpenFunction::CreateSerialConnection(
172 const std::string& port,
174 serial::DataBit databit,
175 serial::ParityBit parity,
176 serial::StopBit stopbit,
177 const std::string& owner_extension_id) {
178 return new SerialConnection(port, bitrate, databit, parity, stopbit,
182 bool SerialOpenFunction::DoesPortExist(const std::string& port) {
183 const SerialPortEnumerator::StringSet name_set(
184 SerialPortEnumerator::GenerateValidSerialPortNames());
185 return SerialPortEnumerator::DoesPortExist(name_set, params_->port);
188 bool SerialOpenFunction::Respond() {
192 SerialCloseFunction::SerialCloseFunction() {
195 SerialCloseFunction::~SerialCloseFunction() {
198 bool SerialCloseFunction::Prepare() {
199 set_work_thread_id(BrowserThread::FILE);
201 params_ = api::serial::Close::Params::Create(*args_);
202 EXTENSION_FUNCTION_VALIDATE(params_.get());
207 void SerialCloseFunction::Work() {
208 bool close_result = false;
209 SerialConnection* serial_connection = GetSerialConnection(
210 params_->connection_id);
211 if (serial_connection) {
212 serial_connection->Close();
213 RemoveSerialConnection(params_->connection_id);
217 SetResult(new base::FundamentalValue(close_result));
220 bool SerialCloseFunction::Respond() {
224 SerialReadFunction::SerialReadFunction() {
227 SerialReadFunction::~SerialReadFunction() {
230 bool SerialReadFunction::Prepare() {
231 set_work_thread_id(BrowserThread::FILE);
233 params_ = api::serial::Read::Params::Create(*args_);
234 EXTENSION_FUNCTION_VALIDATE(params_.get());
235 if (params_->bytes_to_read <= 0 || params_->bytes_to_read >= 1024 * 1024) {
236 error_ = kSerialReadInvalidBytesToRead;
243 void SerialReadFunction::Work() {
245 scoped_refptr<net::IOBufferWithSize> io_buffer(
246 new net::IOBufferWithSize(params_->bytes_to_read));
247 SerialConnection* serial_connection(GetSerialConnection(
248 params_->connection_id));
250 if (serial_connection)
251 bytes_read = serial_connection->Read(io_buffer);
253 base::DictionaryValue* result = new base::DictionaryValue();
255 // The API is defined to require a 'data' value, so we will always
256 // create a BinaryValue, even if it's zero-length.
259 result->SetInteger(kBytesReadKey, bytes_read);
260 result->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer(
261 io_buffer->data(), bytes_read));
265 bool SerialReadFunction::Respond() {
269 SerialWriteFunction::SerialWriteFunction()
270 : io_buffer_(NULL), io_buffer_size_(0) {
273 SerialWriteFunction::~SerialWriteFunction() {
276 bool SerialWriteFunction::Prepare() {
277 set_work_thread_id(BrowserThread::FILE);
279 params_ = api::serial::Write::Params::Create(*args_);
280 EXTENSION_FUNCTION_VALIDATE(params_.get());
282 io_buffer_size_ = params_->data.size();
283 io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
288 void SerialWriteFunction::Work() {
289 int bytes_written = -1;
290 SerialConnection* serial_connection = GetSerialConnection(
291 params_->connection_id);
292 if (serial_connection)
293 bytes_written = serial_connection->Write(io_buffer_, io_buffer_size_);
295 error_ = kSerialConnectionNotFoundError;
297 base::DictionaryValue* result = new base::DictionaryValue();
298 result->SetInteger(kBytesWrittenKey, bytes_written);
302 bool SerialWriteFunction::Respond() {
306 SerialFlushFunction::SerialFlushFunction() {
309 SerialFlushFunction::~SerialFlushFunction() {
312 bool SerialFlushFunction::Prepare() {
313 set_work_thread_id(BrowserThread::FILE);
315 params_ = api::serial::Flush::Params::Create(*args_);
316 EXTENSION_FUNCTION_VALIDATE(params_.get());
320 void SerialFlushFunction::Work() {
321 bool flush_result = false;
322 SerialConnection* serial_connection = GetSerialConnection(
323 params_->connection_id);
324 if (serial_connection) {
325 serial_connection->Flush();
329 SetResult(new base::FundamentalValue(flush_result));
332 bool SerialFlushFunction::Respond() {
336 SerialGetControlSignalsFunction::SerialGetControlSignalsFunction()
337 : api_response_(false) {
340 SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {
343 bool SerialGetControlSignalsFunction::Prepare() {
344 set_work_thread_id(BrowserThread::FILE);
346 params_ = api::serial::GetControlSignals::Params::Create(*args_);
347 EXTENSION_FUNCTION_VALIDATE(params_.get());
352 void SerialGetControlSignalsFunction::Work() {
353 base::DictionaryValue *result = new base::DictionaryValue();
354 SerialConnection* serial_connection = GetSerialConnection(
355 params_->connection_id);
356 if (serial_connection) {
357 SerialConnection::ControlSignals control_signals = { 0 };
358 if (serial_connection->GetControlSignals(control_signals)) {
359 api_response_ = true;
360 result->SetBoolean(kDcdKey, control_signals.dcd);
361 result->SetBoolean(kCtsKey, control_signals.cts);
363 error_ = kErrorGetControlSignalsFailed;
366 error_ = kSerialConnectionNotFoundError;
367 result->SetBoolean(kSuccessKey, false);
373 bool SerialGetControlSignalsFunction::Respond() {
374 return api_response_;
377 SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {
380 SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {
383 bool SerialSetControlSignalsFunction::Prepare() {
384 set_work_thread_id(BrowserThread::FILE);
386 params_ = api::serial::SetControlSignals::Params::Create(*args_);
387 EXTENSION_FUNCTION_VALIDATE(params_.get());
392 void SerialSetControlSignalsFunction::Work() {
393 SerialConnection* serial_connection = GetSerialConnection(
394 params_->connection_id);
395 if (serial_connection) {
396 SerialConnection::ControlSignals control_signals = { 0 };
397 control_signals.should_set_dtr = params_->options.dtr.get() != NULL;
398 if (control_signals.should_set_dtr)
399 control_signals.dtr = *(params_->options.dtr);
400 control_signals.should_set_rts = params_->options.rts.get() != NULL;
401 if (control_signals.should_set_rts)
402 control_signals.rts = *(params_->options.rts);
403 if (serial_connection->SetControlSignals(control_signals)) {
404 SetResult(new base::FundamentalValue(true));
406 error_ = kErrorSetControlSignalsFailed;
407 SetResult(new base::FundamentalValue(false));
410 error_ = kSerialConnectionNotFoundError;
411 SetResult(new base::FundamentalValue(false));
415 bool SerialSetControlSignalsFunction::Respond() {
419 } // namespace extensions