1 // Copyright 2014 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 "extensions/browser/api/serial/serial_event_dispatcher.h"
7 #include "base/lazy_instance.h"
8 #include "extensions/browser/api/serial/serial_connection.h"
9 #include "extensions/browser/event_router.h"
10 #include "extensions/browser/extensions_browser_client.h"
12 namespace extensions
{
18 bool ShouldPauseOnReceiveError(serial::ReceiveError error
) {
19 return error
== serial::RECEIVE_ERROR_DEVICE_LOST
||
20 error
== serial::RECEIVE_ERROR_SYSTEM_ERROR
||
21 error
== serial::RECEIVE_ERROR_DISCONNECTED
||
22 error
== serial::RECEIVE_ERROR_BREAK
||
23 error
== serial::RECEIVE_ERROR_FRAME_ERROR
||
24 error
== serial::RECEIVE_ERROR_OVERRUN
||
25 error
== serial::RECEIVE_ERROR_BUFFER_OVERFLOW
||
26 error
== serial::RECEIVE_ERROR_PARITY_ERROR
;
31 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<SerialEventDispatcher
> >
32 g_factory
= LAZY_INSTANCE_INITIALIZER
;
35 BrowserContextKeyedAPIFactory
<SerialEventDispatcher
>*
36 SerialEventDispatcher::GetFactoryInstance() {
37 return g_factory
.Pointer();
41 SerialEventDispatcher
* SerialEventDispatcher::Get(
42 content::BrowserContext
* context
) {
43 return BrowserContextKeyedAPIFactory
<SerialEventDispatcher
>::Get(context
);
46 SerialEventDispatcher::SerialEventDispatcher(content::BrowserContext
* context
)
47 : thread_id_(SerialConnection::kThreadId
), context_(context
) {
48 ApiResourceManager
<SerialConnection
>* manager
=
49 ApiResourceManager
<SerialConnection
>::Get(context_
);
50 DCHECK(manager
) << "No serial connection manager.";
51 connections_
= manager
->data_
;
54 SerialEventDispatcher::~SerialEventDispatcher() {
57 SerialEventDispatcher::ReceiveParams::ReceiveParams() {
60 SerialEventDispatcher::ReceiveParams::~ReceiveParams() {
63 void SerialEventDispatcher::PollConnection(const std::string
& extension_id
,
65 DCHECK_CURRENTLY_ON(thread_id_
);
68 params
.thread_id
= thread_id_
;
69 params
.browser_context_id
= context_
;
70 params
.extension_id
= extension_id
;
71 params
.connections
= connections_
;
72 params
.connection_id
= connection_id
;
78 void SerialEventDispatcher::StartReceive(const ReceiveParams
& params
) {
79 DCHECK_CURRENTLY_ON(params
.thread_id
);
81 SerialConnection
* connection
=
82 params
.connections
->Get(params
.extension_id
, params
.connection_id
);
85 DCHECK(params
.extension_id
== connection
->owner_extension_id());
87 if (connection
->paused())
90 connection
->Receive(base::Bind(&ReceiveCallback
, params
));
94 void SerialEventDispatcher::ReceiveCallback(const ReceiveParams
& params
,
95 const std::vector
<char>& data
,
96 serial::ReceiveError error
) {
97 DCHECK_CURRENTLY_ON(params
.thread_id
);
99 // Note that an error (e.g. timeout) does not necessarily mean that no data
100 // was read, so we may fire an onReceive regardless of any error code.
101 if (data
.size() > 0) {
102 serial::ReceiveInfo receive_info
;
103 receive_info
.connection_id
= params
.connection_id
;
104 receive_info
.data
= data
;
105 scoped_ptr
<base::ListValue
> args
= serial::OnReceive::Create(receive_info
);
106 scoped_ptr
<extensions::Event
> event(
107 new extensions::Event(extensions::events::SERIAL_ON_RECEIVE
,
108 serial::OnReceive::kEventName
, args
.Pass()));
109 PostEvent(params
, event
.Pass());
112 if (error
!= serial::RECEIVE_ERROR_NONE
) {
113 serial::ReceiveErrorInfo error_info
;
114 error_info
.connection_id
= params
.connection_id
;
115 error_info
.error
= error
;
116 scoped_ptr
<base::ListValue
> args
=
117 serial::OnReceiveError::Create(error_info
);
118 scoped_ptr
<extensions::Event
> event(
119 new extensions::Event(extensions::events::SERIAL_ON_RECEIVE_ERROR
,
120 serial::OnReceiveError::kEventName
, args
.Pass()));
121 PostEvent(params
, event
.Pass());
122 if (ShouldPauseOnReceiveError(error
)) {
123 SerialConnection
* connection
=
124 params
.connections
->Get(params
.extension_id
, params
.connection_id
);
126 connection
->set_paused(true);
130 // Queue up the next read operation.
131 BrowserThread::PostTask(
132 params
.thread_id
, FROM_HERE
, base::Bind(&StartReceive
, params
));
136 void SerialEventDispatcher::PostEvent(const ReceiveParams
& params
,
137 scoped_ptr
<extensions::Event
> event
) {
138 DCHECK_CURRENTLY_ON(params
.thread_id
);
140 BrowserThread::PostTask(BrowserThread::UI
,
142 base::Bind(&DispatchEvent
,
143 params
.browser_context_id
,
145 base::Passed(event
.Pass())));
149 void SerialEventDispatcher::DispatchEvent(void* browser_context_id
,
150 const std::string
& extension_id
,
151 scoped_ptr
<extensions::Event
> event
) {
152 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
154 content::BrowserContext
* context
=
155 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
156 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
159 EventRouter
* router
= EventRouter::Get(context
);
161 router
->DispatchEventToExtension(extension_id
, event
.Pass());
166 } // namespace extensions