1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file. 4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/browser/api/serial/serial_connection.h" 6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <string> 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/file_path.h" 10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/lazy_instance.h" 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/browser/api/api_resource_manager.h" 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/api/serial.h" 13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace extensions { 15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace { 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 18116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kDefaultBufferSize = 4096; 19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdochcore_api::serial::SendError ConvertSendErrorFromMojo( 21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::SendError input) { 22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::SEND_ERROR_NONE: 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::SEND_ERROR_NONE; 25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::SEND_ERROR_DISCONNECTED: 26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::SEND_ERROR_DISCONNECTED; 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::SEND_ERROR_PENDING: 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::SEND_ERROR_PENDING; 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::SEND_ERROR_TIMEOUT: 30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::SEND_ERROR_TIMEOUT; 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::SEND_ERROR_SYSTEM_ERROR: 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::SEND_ERROR_SYSTEM_ERROR; 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::SEND_ERROR_NONE; 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdochcore_api::serial::ReceiveError ConvertReceiveErrorFromMojo( 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::ReceiveError input) { 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::RECEIVE_ERROR_NONE: 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::RECEIVE_ERROR_NONE; 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::RECEIVE_ERROR_DISCONNECTED: 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::RECEIVE_ERROR_DISCONNECTED; 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::RECEIVE_ERROR_TIMEOUT: 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::RECEIVE_ERROR_TIMEOUT; 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::RECEIVE_ERROR_DEVICE_LOST: 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::RECEIVE_ERROR_DEVICE_LOST; 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::RECEIVE_ERROR_SYSTEM_ERROR: 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::RECEIVE_ERROR_SYSTEM_ERROR; 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::RECEIVE_ERROR_NONE; 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdochcore_api::serial::DataBits ConvertDataBitsFromMojo( 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::DataBits input) { 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::DATA_BITS_NONE: 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::DATA_BITS_NONE; 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::DATA_BITS_SEVEN: 60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::DATA_BITS_SEVEN; 61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::DATA_BITS_EIGHT: 62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::DATA_BITS_EIGHT; 63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::DATA_BITS_NONE; 65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdevice::serial::DataBits ConvertDataBitsToMojo( 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch core_api::serial::DataBits input) { 69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::DATA_BITS_NONE: 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::DATA_BITS_NONE; 72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::DATA_BITS_SEVEN: 73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::DATA_BITS_SEVEN; 74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::DATA_BITS_EIGHT: 75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::DATA_BITS_EIGHT; 76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::DATA_BITS_NONE; 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdochcore_api::serial::ParityBit ConvertParityBitFromMojo( 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::ParityBit input) { 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::PARITY_BIT_NONE: 84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::PARITY_BIT_NONE; 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::PARITY_BIT_ODD: 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::PARITY_BIT_ODD; 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::PARITY_BIT_NO: 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::PARITY_BIT_NO; 89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::PARITY_BIT_EVEN: 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::PARITY_BIT_EVEN; 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::PARITY_BIT_NONE; 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdevice::serial::ParityBit ConvertParityBitToMojo( 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch core_api::serial::ParityBit input) { 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::PARITY_BIT_NONE: 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::PARITY_BIT_NONE; 100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::PARITY_BIT_NO: 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::PARITY_BIT_NO; 102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::PARITY_BIT_ODD: 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::PARITY_BIT_ODD; 104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::PARITY_BIT_EVEN: 105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::PARITY_BIT_EVEN; 106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::PARITY_BIT_NONE; 108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdochcore_api::serial::StopBits ConvertStopBitsFromMojo( 111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::StopBits input) { 112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::STOP_BITS_NONE: 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::STOP_BITS_NONE; 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::STOP_BITS_ONE: 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::STOP_BITS_ONE; 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case device::serial::STOP_BITS_TWO: 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::STOP_BITS_TWO; 119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return core_api::serial::STOP_BITS_NONE; 121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdevice::serial::StopBits ConvertStopBitsToMojo( 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch core_api::serial::StopBits input) { 125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch switch (input) { 126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::STOP_BITS_NONE: 127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::STOP_BITS_NONE; 128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::STOP_BITS_ONE: 129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::STOP_BITS_ONE; 130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case core_api::serial::STOP_BITS_TWO: 131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::STOP_BITS_TWO; 132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return device::serial::STOP_BITS_NONE; 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class SendBuffer : public device::ReadOnlyBuffer { 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public: 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SendBuffer( 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string& data, 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::Callback<void(int, device::serial::SendError)>& callback) 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : data_(data), callback_(callback) {} 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual ~SendBuffer() {} 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual const char* GetData() OVERRIDE { return data_.c_str(); } 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual uint32_t GetSize() OVERRIDE { 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return static_cast<uint32_t>(data_.size()); 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void Done(uint32_t bytes_read) OVERRIDE { 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callback_.Run(bytes_read, device::serial::SEND_ERROR_NONE); 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void DoneWithError(uint32_t bytes_read, int32_t error) OVERRIDE { 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callback_.Run(bytes_read, static_cast<device::serial::SendError>(error)); 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private: 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string data_; 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::Callback<void(int, device::serial::SendError)> callback_; 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class ReceiveBuffer : public device::WritableBuffer { 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public: 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ReceiveBuffer( 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_refptr<net::IOBuffer> buffer, 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint32_t size, 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::Callback<void(int, device::serial::ReceiveError)>& callback) 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : buffer_(buffer), size_(size), callback_(callback) {} 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual ~ReceiveBuffer() {} 1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual char* GetData() OVERRIDE { return buffer_->data(); } 1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual uint32_t GetSize() OVERRIDE { return size_; } 1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void Done(uint32_t bytes_written) OVERRIDE { 1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callback_.Run(bytes_written, device::serial::RECEIVE_ERROR_NONE); 1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void DoneWithError(uint32_t bytes_written, int32_t error) OVERRIDE { 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callback_.Run(bytes_written, 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static_cast<device::serial::ReceiveError>(error)); 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private: 1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_refptr<net::IOBuffer> buffer_; 1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const uint32_t size_; 1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::Callback<void(int, device::serial::ReceiveError)> callback_; 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace 184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 185116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic base::LazyInstance< 186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> > > 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch g_factory = LAZY_INSTANCE_INITIALIZER; 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static 190116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtemplate <> 191116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> >* 192116680a4aac90f2aa7413d9095a592090648e557Ben MurdochApiResourceManager<SerialConnection>::GetFactoryInstance() { 193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return g_factory.Pointer(); 194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 196116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSerialConnection::SerialConnection(const std::string& port, 197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& owner_extension_id) 198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : ApiResource(owner_extension_id), 199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch port_(port), 200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch persistent_(false), 201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch buffer_size_(kDefaultBufferSize), 202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_timeout_(0), 203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_timeout_(0), 204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch paused_(false), 2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) io_handler_(device::SerialIoHandler::Create( 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::BrowserThread::GetMessageLoopProxyForThread( 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::BrowserThread::FILE))) { 208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 211116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSerialConnection::~SerialConnection() { 212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED); 213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED); 214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 216116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::IsPersistent() const { 217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return persistent(); 218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 220116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::set_buffer_size(int buffer_size) { 221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch buffer_size_ = buffer_size; 222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 224116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::set_receive_timeout(int receive_timeout) { 225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_timeout_ = receive_timeout; 226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 228116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::set_send_timeout(int send_timeout) { 229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_timeout_ = send_timeout; 230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 232116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::set_paused(bool paused) { 233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch paused_ = paused; 234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (paused) { 235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE); 236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 239116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::Open(const OpenCompleteCallback& callback) { 240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->Open(port_, callback); 242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 244116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::Receive(const ReceiveCompleteCallback& callback) { 245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!receive_complete_.is_null()) 247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_complete_ = callback; 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) receive_buffer_ = new net::IOBuffer(buffer_size_); 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) io_handler_->Read(scoped_ptr<device::WritableBuffer>(new ReceiveBuffer( 2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) receive_buffer_, 2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_size_, 2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&SerialConnection::OnAsyncReadComplete, AsWeakPtr())))); 254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_timeout_task_.reset(); 255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (receive_timeout_ > 0) { 256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_timeout_task_.reset(new TimeoutTask( 257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&SerialConnection::OnReceiveTimeout, AsWeakPtr()), 258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::TimeDelta::FromMilliseconds(receive_timeout_))); 259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 263116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::Send(const std::string& data, 264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const SendCompleteCallback& callback) { 265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!send_complete_.is_null()) 267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_complete_ = callback; 2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) io_handler_->Write(scoped_ptr<device::ReadOnlyBuffer>(new SendBuffer( 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data, base::Bind(&SerialConnection::OnAsyncWriteComplete, AsWeakPtr())))); 271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_timeout_task_.reset(); 272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (send_timeout_ > 0) { 273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_timeout_task_.reset(new TimeoutTask( 274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&SerialConnection::OnSendTimeout, AsWeakPtr()), 275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::TimeDelta::FromMilliseconds(send_timeout_))); 276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 280116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::Configure( 281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const core_api::serial::ConnectionOptions& options) { 282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (options.persistent.get()) 284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch set_persistent(*options.persistent); 285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (options.name.get()) 286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch set_name(*options.name); 287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (options.buffer_size.get()) 288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch set_buffer_size(*options.buffer_size); 289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (options.receive_timeout.get()) 290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch set_receive_timeout(*options.receive_timeout); 291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (options.send_timeout.get()) 292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch set_send_timeout(*options.send_timeout); 293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool success = io_handler_->ConfigurePort( 294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *device::serial::ConnectionOptions::From(options)); 295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE); 296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return success; 297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 299116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::SetIoHandlerForTest( 300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_refptr<device::SerialIoHandler> handler) { 301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_ = handler; 302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 304116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::GetInfo(core_api::serial::ConnectionInfo* info) const { 305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->paused = paused_; 307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->persistent = persistent_; 308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->name = name_; 309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->buffer_size = buffer_size_; 310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->receive_timeout = receive_timeout_; 311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->send_timeout = send_timeout_; 312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::ConnectionInfoPtr port_info = io_handler_->GetPortInfo(); 313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!port_info) 314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->bitrate.reset(new int(port_info->bitrate)); 317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->data_bits = ConvertDataBitsFromMojo(port_info->data_bits); 318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->parity_bit = ConvertParityBitFromMojo(port_info->parity_bit); 319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->stop_bits = ConvertStopBitsFromMojo(port_info->stop_bits); 320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch info->cts_flow_control.reset(new bool(port_info->cts_flow_control)); 321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 324116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::Flush() const { 325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return io_handler_->Flush(); 326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 328116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::GetControlSignals( 329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch core_api::serial::DeviceControlSignals* control_signals) const { 330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::DeviceControlSignalsPtr signals = 331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->GetControlSignals(); 332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!signals) 333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch control_signals->dcd = signals->dcd; 336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch control_signals->cts = signals->cts; 337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch control_signals->ri = signals->ri; 338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch control_signals->dsr = signals->dsr; 339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 342116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialConnection::SetControlSignals( 343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const core_api::serial::HostControlSignals& control_signals) { 344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return io_handler_->SetControlSignals( 345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *device::serial::HostControlSignals::From(control_signals)); 346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 348116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::OnReceiveTimeout() { 349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT); 351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 353116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::OnSendTimeout() { 354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch io_handler_->CancelWrite(device::serial::SEND_ERROR_TIMEOUT); 356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SerialConnection::OnAsyncReadComplete(int bytes_read, 359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::ReceiveError error) { 360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(!receive_complete_.is_null()); 362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ReceiveCompleteCallback callback = receive_complete_; 363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_complete_.Reset(); 364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch receive_timeout_task_.reset(); 3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callback.Run(std::string(receive_buffer_->data(), bytes_read), 3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ConvertReceiveErrorFromMojo(error)); 3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) receive_buffer_ = NULL; 368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 370116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::OnAsyncWriteComplete(int bytes_sent, 371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::SendError error) { 372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(!send_complete_.is_null()); 374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch SendCompleteCallback callback = send_complete_; 375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_complete_.Reset(); 376116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch send_timeout_task_.reset(); 377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch callback.Run(bytes_sent, ConvertSendErrorFromMojo(error)); 378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 380116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSerialConnection::TimeoutTask::TimeoutTask(const base::Closure& closure, 381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const base::TimeDelta& delay) 382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : weak_factory_(this), closure_(closure), delay_(delay) { 383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::MessageLoop::current()->PostDelayedTask( 384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FROM_HERE, 385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&TimeoutTask::Run, weak_factory_.GetWeakPtr()), 386116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delay_); 387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 388116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 389116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSerialConnection::TimeoutTask::~TimeoutTask() { 390116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 392116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialConnection::TimeoutTask::Run() const { 393116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch closure_.Run(); 394116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace extensions 397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 398116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace mojo { 399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static 401116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdevice::serial::HostControlSignalsPtr 402116680a4aac90f2aa7413d9095a592090648e557Ben MurdochTypeConverter<device::serial::HostControlSignalsPtr, 403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extensions::core_api::serial::HostControlSignals>:: 4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Convert(const extensions::core_api::serial::HostControlSignals& input) { 405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::HostControlSignalsPtr output( 406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::HostControlSignals::New()); 407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (input.dtr.get()) { 408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->has_dtr = true; 409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->dtr = *input.dtr; 410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (input.rts.get()) { 412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->has_rts = true; 413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->rts = *input.rts; 414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return output.Pass(); 416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static 419116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdevice::serial::ConnectionOptionsPtr 420116680a4aac90f2aa7413d9095a592090648e557Ben MurdochTypeConverter<device::serial::ConnectionOptionsPtr, 421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extensions::core_api::serial::ConnectionOptions>:: 4221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Convert(const extensions::core_api::serial::ConnectionOptions& input) { 423116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::ConnectionOptionsPtr output( 424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device::serial::ConnectionOptions::New()); 425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (input.bitrate.get() && *input.bitrate > 0) 426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->bitrate = *input.bitrate; 427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->data_bits = extensions::ConvertDataBitsToMojo(input.data_bits); 428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->parity_bit = extensions::ConvertParityBitToMojo(input.parity_bit); 429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->stop_bits = extensions::ConvertStopBitsToMojo(input.stop_bits); 430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (input.cts_flow_control.get()) { 431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->has_cts_flow_control = true; 432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch output->cts_flow_control = *input.cts_flow_control; 433116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 434116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return output.Pass(); 435116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 436116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace mojo 438