blob: ad578b0b5483fa7257d8cd3b0ea0dc265b9d8b31 [file] [log] [blame]
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001// Copyright (c) 2012 The Chromium OS 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.
4
5#include "shill/cellular_capability_classic.h"
6
7#include <base/bind.h>
8#include <chromeos/dbus/service_constants.h>
9
10#include "shill/cellular.h"
11#include "shill/error.h"
12#include "shill/property_accessor.h"
13#include "shill/proxy_factory.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070014#include "shill/scope_logger.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040015
16using base::Bind;
17using base::Callback;
18using base::Closure;
19using std::string;
20
21namespace shill {
22
23const char CellularCapabilityClassic::kConnectPropertyApn[] = "apn";
24const char CellularCapabilityClassic::kConnectPropertyApnUsername[] =
25 "username";
26const char CellularCapabilityClassic::kConnectPropertyApnPassword[] =
27 "password";
28const char CellularCapabilityClassic::kConnectPropertyHomeOnly[] = "home_only";
29const char CellularCapabilityClassic::kConnectPropertyPhoneNumber[] = "number";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -040030const char CellularCapabilityClassic::kModemPropertyEnabled[] = "Enabled";
31
32static Cellular::ModemState ConvertClassicToModemState(uint32 classic_state) {
33 ModemClassicState cstate =
34 static_cast<ModemClassicState>(classic_state);
35 switch (cstate) {
36 case kModemClassicStateUnknown:
37 return Cellular::kModemStateUnknown;
38 case kModemClassicStateDisabled:
39 return Cellular::kModemStateDisabled;
40 case kModemClassicStateDisabling:
41 return Cellular::kModemStateDisabling;
42 case kModemClassicStateEnabling:
43 return Cellular::kModemStateEnabling;
44 case kModemClassicStateEnabled:
45 return Cellular::kModemStateEnabled;
46 case kModemClassicStateSearching:
47 return Cellular::kModemStateSearching;
48 case kModemClassicStateRegistered:
49 return Cellular::kModemStateRegistered;
50 case kModemClassicStateDisconnecting:
51 return Cellular::kModemStateDisconnecting;
52 case kModemClassicStateConnecting:
53 return Cellular::kModemStateConnecting;
54 case kModemClassicStateConnected:
55 return Cellular::kModemStateConnected;
56 default:
57 return Cellular::kModemStateUnknown;
58 };
59}
Jason Glasgow82f9ab32012-04-04 14:27:19 -040060
61CellularCapabilityClassic::CellularCapabilityClassic(
62 Cellular *cellular,
63 ProxyFactory *proxy_factory)
64 : CellularCapability(cellular, proxy_factory),
mukesh agrawal6b34a842012-05-30 11:16:01 -070065 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -040066 weak_ptr_factory_(this) {
67 PropertyStore *store = cellular->mutable_store();
68 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
69 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
70 &scanning_supported_);
71 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
72 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
73 &firmware_revision_);
74 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
75 &hardware_revision_);
76 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
77 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
78 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
79 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
80 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
81 store->RegisterConstString(flimflam::kMinProperty, &min_);
82 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
83}
84
85CellularCapabilityClassic::~CellularCapabilityClassic() {}
86
87void CellularCapabilityClassic::InitProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070088 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040089 proxy_.reset(proxy_factory()->CreateModemProxy(
90 cellular()->dbus_path(), cellular()->dbus_owner()));
91 simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
92 cellular()->dbus_path(), cellular()->dbus_owner()));
93 proxy_->set_state_changed_callback(
94 Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
95 weak_ptr_factory_.GetWeakPtr()));
96}
97
98void CellularCapabilityClassic::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070099 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400100 proxy_.reset();
101 simple_proxy_.reset();
102}
103
104void CellularCapabilityClassic::FinishEnable(const ResultCallback &callback) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400105 // Normally, running the callback is the last thing done in a method.
106 // In this case, we do it first, because we want to make sure that
107 // the device is marked as Enabled before the registration state is
108 // handled. See comment in Cellular::HandleNewRegistrationState.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400109 callback.Run(Error());
110 GetRegistrationState();
111 GetSignalQuality();
112}
113
114void CellularCapabilityClassic::FinishDisable(const ResultCallback &callback) {
115 ReleaseProxies();
116 callback.Run(Error());
117}
118
119void CellularCapabilityClassic::OnUnsupportedOperation(
120 const char *operation,
121 Error *error) {
122 string message("The ");
123 message.append(operation).append(" operation is not supported.");
124 Error::PopulateAndLog(error, Error::kNotSupported, message);
125}
126
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400127void CellularCapabilityClassic::RunNextStep(CellularTaskList *tasks) {
128 CHECK(!tasks->empty());
129 SLOG(Cellular, 2) << __func__ << ": " << tasks->size() << " remaining tasks";
130 Closure task = (*tasks)[0];
131 tasks->erase(tasks->begin());
132 cellular()->dispatcher()->PostTask(task);
133}
134
135void CellularCapabilityClassic::StepCompletedCallback(
136 const ResultCallback &callback,
137 bool ignore_error,
138 CellularTaskList *tasks,
139 const Error &error) {
140 if ((ignore_error || error.IsSuccess()) && !tasks->empty()) {
141 RunNextStep(tasks);
142 return;
143 }
144 delete tasks;
Ben Chan3ecdf822012-08-06 12:29:23 -0700145 if (!callback.is_null())
146 callback.Run(error);
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400147}
148
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400149// always called from an async context
150void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700151 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400152 CHECK(!callback.is_null());
153 Error error;
154 proxy_->Enable(true, &error, callback, kTimeoutEnable);
155 if (error.IsFailure())
156 callback.Run(error);
157}
158
159// always called from an async context
160void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700161 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400162 CHECK(!callback.is_null());
163 Error error;
Thieu Lec8d2d962012-05-15 14:31:18 -0700164 proxy_->Enable(false, &error, callback, kTimeoutEnable);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400165 if (error.IsFailure())
166 callback.Run(error);
167}
168
169// always called from an async context
170void CellularCapabilityClassic::GetModemStatus(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700171 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400172 CHECK(!callback.is_null());
173 DBusPropertyMapCallback cb = Bind(
174 &CellularCapabilityClassic::OnGetModemStatusReply,
175 weak_ptr_factory_.GetWeakPtr(), callback);
176 Error error;
177 simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
178 if (error.IsFailure())
179 callback.Run(error);
180}
181
182// always called from an async context
183void CellularCapabilityClassic::GetModemInfo(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700184 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400185 CHECK(!callback.is_null());
186 ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
187 weak_ptr_factory_.GetWeakPtr(), callback);
188 Error error;
189 proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
190 if (error.IsFailure())
191 callback.Run(error);
192}
193
194void CellularCapabilityClassic::StopModem(Error *error,
195 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700196 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400197
198 CellularTaskList *tasks = new CellularTaskList();
199 ResultCallback cb =
200 Bind(&CellularCapabilityClassic::StepCompletedCallback,
201 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
202 ResultCallback cb_ignore_error =
203 Bind(&CellularCapabilityClassic::StepCompletedCallback,
204 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400205 // TODO(ers): We can skip the call to Disconnect if the modem has
206 // told us that the modem state is Disabled or Registered.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400207 tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
208 weak_ptr_factory_.GetWeakPtr(),
209 static_cast<Error *>(NULL), cb_ignore_error));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400210 // TODO(ers): We can skip the call to Disable if the modem has
211 // told us that the modem state is Disabled.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400212 tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
213 weak_ptr_factory_.GetWeakPtr(), cb));
214 tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
215 weak_ptr_factory_.GetWeakPtr(), cb));
216
217 RunNextStep(tasks);
218}
219
220void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
221 Error *error,
222 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700223 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400224 simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400225}
226
227void CellularCapabilityClassic::Disconnect(Error *error,
228 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700229 SLOG(Cellular, 2) << __func__;
Thieu Le3d275392012-07-20 15:32:58 -0700230 if (proxy_.get())
231 proxy_->Disconnect(error, callback, kTimeoutDefault);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400232}
233
234void CellularCapabilityClassic::Activate(const string &/*carrier*/,
235 Error *error,
236 const ResultCallback &/*callback*/) {
237 OnUnsupportedOperation(__func__, error);
238}
239
240void CellularCapabilityClassic::RegisterOnNetwork(
241 const string &/*network_id*/,
242 Error *error, const ResultCallback &/*callback*/) {
243 OnUnsupportedOperation(__func__, error);
244}
245
246void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
247 bool /*require*/,
248 Error *error,
249 const ResultCallback &/*callback*/) {
250 OnUnsupportedOperation(__func__, error);
251}
252
253void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
254 Error *error,
255 const ResultCallback &/*callback*/) {
256 OnUnsupportedOperation(__func__, error);
257}
258
259void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
260 const string &/*pin*/,
261 Error *error,
262 const ResultCallback &/*callback*/) {
263 OnUnsupportedOperation(__func__, error);
264}
265
266void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
267 const string &/*new_pin*/,
268 Error *error,
269 const ResultCallback &/*callback*/) {
270 OnUnsupportedOperation(__func__, error);
271}
272
273void CellularCapabilityClassic::Scan(Error *error,
274 const ResultCallback &callback) {
275 OnUnsupportedOperation(__func__, error);
276}
277
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400278void CellularCapabilityClassic::OnDBusPropertiesChanged(
279 const std::string &interface,
280 const DBusPropertiesMap &changed_properties,
281 const std::vector<std::string> &invalidated_properties) {
282 bool enabled;
283 // This solves a bootstrapping problem: If the modem is not yet
284 // enabled, there are no proxy objects associated with the capability
285 // object, so modem signals like StateChanged aren't seen. By monitoring
286 // changes to the Enabled property via the ModemManager, we're able to
287 // get the initialization process started, which will result in the
288 // creation of the proxy objects.
289 //
290 // The first time we see the change to Enabled (when the modem state
291 // is Unknown), we simply update the state, and rely on the Manager to
292 // enable the device when it is registered with the Manager. On subsequent
293 // changes to Enabled, we need to explicitly enable the device ourselves.
294 if (DBusProperties::GetBool(changed_properties,
295 kModemPropertyEnabled, &enabled)) {
296 Cellular::ModemState prev_modem_state = cellular()->modem_state();
297 if (enabled)
298 cellular()->set_modem_state(Cellular::kModemStateEnabled);
299 else
300 cellular()->set_modem_state(Cellular::kModemStateDisabled);
301 if (enabled && cellular()->state() == Cellular::kStateDisabled &&
302 prev_modem_state != Cellular::kModemStateUnknown &&
303 prev_modem_state != Cellular::kModemStateEnabled) {
304 cellular()->SetEnabled(true);
305 }
306 }
307}
308
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400309void CellularCapabilityClassic::OnGetModemStatusReply(
310 const ResultCallback &callback,
311 const DBusPropertiesMap &props,
312 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700313 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
314 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400315 if (error.IsSuccess()) {
316 DBusProperties::GetString(props, "carrier", &carrier_);
317 DBusProperties::GetString(props, "meid", &meid_);
318 DBusProperties::GetString(props, "imei", &imei_);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400319 DBusProperties::GetString(props, kModemPropertyIMSI, &imsi_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400320 DBusProperties::GetString(props, "esn", &esn_);
321 DBusProperties::GetString(props, "mdn", &mdn_);
322 DBusProperties::GetString(props, "min", &min_);
323 DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400324 UpdateStatus(props);
325 }
326 callback.Run(error);
327}
328
329void CellularCapabilityClassic::OnGetModemInfoReply(
330 const ResultCallback &callback,
331 const ModemHardwareInfo &info,
332 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700333 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400334 if (error.IsSuccess()) {
335 manufacturer_ = info._1;
336 model_id_ = info._2;
337 hardware_revision_ = info._3;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700338 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
339 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400340 }
341 callback.Run(error);
342}
343
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400344void CellularCapabilityClassic::OnModemStateChangedSignal(
345 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700346 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
347 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400348 cellular()->OnModemStateChanged(ConvertClassicToModemState(old_state),
349 ConvertClassicToModemState(new_state),
350 reason);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400351}
352
353} // namespace shill