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 "device/serial/data_sender.h"
10 #include "base/message_loop/message_loop.h"
14 // Represents a send that is not yet fulfilled.
15 class DataSender::PendingSend
{
17 PendingSend(const base::StringPiece
& data
,
18 const DataSentCallback
& callback
,
19 const SendErrorCallback
& error_callback
,
22 // Reports |fatal_error_value_| to |receive_error_callback_|.
23 void DispatchFatalError();
25 // Attempts to send any data not yet sent to |sink|.
29 // Invoked to report that |num_bytes| of data have been sent and then an
30 // error, |error| was encountered. Subtracts the number of bytes that were
31 // part of this send from |num_bytes|. If this send was not completed before
32 // the error, this calls |error_callback_| to report the error. Otherwise,
33 // this calls |callback_|. Returns the number of bytes sent but not acked.
34 void OnDataSent(uint32_t num_bytes
, int32_t error
);
37 const base::StringPiece data_
;
39 // The callback to report success.
40 const DataSentCallback callback_
;
42 // The callback to report errors.
43 const SendErrorCallback error_callback_
;
45 // The DataSender that owns this PendingSend.
49 DataSender::DataSender(mojo::InterfacePtr
<serial::DataSink
> sink
,
51 int32_t fatal_error_value
)
53 fatal_error_value_(fatal_error_value
),
55 sink_
.set_connection_error_handler(
56 base::Bind(&DataSender::OnConnectionError
, base::Unretained(this)));
59 DataSender::~DataSender() {
63 bool DataSender::Send(const base::StringPiece
& data
,
64 const DataSentCallback
& callback
,
65 const SendErrorCallback
& error_callback
) {
66 DCHECK(!callback
.is_null() && !error_callback
.is_null());
67 if (!pending_cancel_
.is_null() || shut_down_
)
70 linked_ptr
<PendingSend
> pending_send(
71 new PendingSend(data
, callback
, error_callback
, this));
72 pending_send
->SendData();
73 sends_awaiting_ack_
.push(pending_send
);
77 bool DataSender::Cancel(int32_t error
, const CancelCallback
& callback
) {
78 DCHECK(!callback
.is_null());
79 if (!pending_cancel_
.is_null() || shut_down_
)
81 if (sends_awaiting_ack_
.empty()) {
82 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
86 pending_cancel_
= callback
;
91 void DataSender::SendComplete() {
95 DCHECK(!sends_awaiting_ack_
.empty());
96 sends_awaiting_ack_
.pop();
97 if (sends_awaiting_ack_
.empty())
101 void DataSender::SendFailed(int32_t error
) {
105 DCHECK(!sends_awaiting_ack_
.empty());
106 sends_awaiting_ack_
.pop();
107 if (!sends_awaiting_ack_
.empty())
113 void DataSender::OnConnectionError() {
117 void DataSender::RunCancelCallback() {
118 DCHECK(sends_awaiting_ack_
.empty());
119 if (pending_cancel_
.is_null())
122 base::MessageLoop::current()->PostTask(FROM_HERE
,
123 base::Bind(pending_cancel_
));
124 pending_cancel_
.Reset();
127 void DataSender::ShutDown() {
129 while (!sends_awaiting_ack_
.empty()) {
130 sends_awaiting_ack_
.front()->DispatchFatalError();
131 sends_awaiting_ack_
.pop();
136 DataSender::PendingSend::PendingSend(const base::StringPiece
& data
,
137 const DataSentCallback
& callback
,
138 const SendErrorCallback
& error_callback
,
142 error_callback_(error_callback
),
146 void DataSender::PendingSend::OnDataSent(uint32_t num_bytes
, int32_t error
) {
148 base::MessageLoop::current()->PostTask(
149 FROM_HERE
, base::Bind(error_callback_
, num_bytes
, error
));
150 sender_
->SendFailed(error
);
152 DCHECK(num_bytes
== data_
.size());
153 base::MessageLoop::current()->PostTask(FROM_HERE
,
154 base::Bind(callback_
, num_bytes
));
155 sender_
->SendComplete();
159 void DataSender::PendingSend::DispatchFatalError() {
160 base::MessageLoop::current()->PostTask(
161 FROM_HERE
, base::Bind(error_callback_
, 0, sender_
->fatal_error_value_
));
164 void DataSender::PendingSend::SendData() {
165 uint32_t num_bytes_to_send
= static_cast<uint32_t>(data_
.size());
166 mojo::Array
<uint8_t> bytes(num_bytes_to_send
);
167 memcpy(&bytes
[0], data_
.data(), num_bytes_to_send
);
168 sender_
->sink_
->OnData(
170 base::Bind(&DataSender::PendingSend::OnDataSent
, base::Unretained(this)));
173 } // namespace device