blob: a33133db3fa96b283ae5b81fad3f6bcb6a15307e [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;
145 callback.Run(error);
146}
147
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400148// always called from an async context
149void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700150 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400151 CHECK(!callback.is_null());
152 Error error;
153 proxy_->Enable(true, &error, callback, kTimeoutEnable);
154 if (error.IsFailure())
155 callback.Run(error);
156}
157
158// always called from an async context
159void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700160 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400161 CHECK(!callback.is_null());
162 Error error;
Thieu Lec8d2d962012-05-15 14:31:18 -0700163 proxy_->Enable(false, &error, callback, kTimeoutEnable);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400164 if (error.IsFailure())
165 callback.Run(error);
166}
167
168// always called from an async context
169void CellularCapabilityClassic::GetModemStatus(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700170 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400171 CHECK(!callback.is_null());
172 DBusPropertyMapCallback cb = Bind(
173 &CellularCapabilityClassic::OnGetModemStatusReply,
174 weak_ptr_factory_.GetWeakPtr(), callback);
175 Error error;
176 simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
177 if (error.IsFailure())
178 callback.Run(error);
179}
180
181// always called from an async context
182void CellularCapabilityClassic::GetModemInfo(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700183 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400184 CHECK(!callback.is_null());
185 ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
186 weak_ptr_factory_.GetWeakPtr(), callback);
187 Error error;
188 proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
189 if (error.IsFailure())
190 callback.Run(error);
191}
192
193void CellularCapabilityClassic::StopModem(Error *error,
194 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700195 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400196
197 CellularTaskList *tasks = new CellularTaskList();
198 ResultCallback cb =
199 Bind(&CellularCapabilityClassic::StepCompletedCallback,
200 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
201 ResultCallback cb_ignore_error =
202 Bind(&CellularCapabilityClassic::StepCompletedCallback,
203 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400204 // TODO(ers): We can skip the call to Disconnect if the modem has
205 // told us that the modem state is Disabled or Registered.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400206 tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
207 weak_ptr_factory_.GetWeakPtr(),
208 static_cast<Error *>(NULL), cb_ignore_error));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400209 // TODO(ers): We can skip the call to Disable if the modem has
210 // told us that the modem state is Disabled.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400211 tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
212 weak_ptr_factory_.GetWeakPtr(), cb));
213 tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
214 weak_ptr_factory_.GetWeakPtr(), cb));
215
216 RunNextStep(tasks);
217}
218
219void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
220 Error *error,
221 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700222 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400223 simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400224}
225
226void CellularCapabilityClassic::Disconnect(Error *error,
227 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700228 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400229 proxy_->Disconnect(error, callback, kTimeoutDefault);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400230}
231
232void CellularCapabilityClassic::Activate(const string &/*carrier*/,
233 Error *error,
234 const ResultCallback &/*callback*/) {
235 OnUnsupportedOperation(__func__, error);
236}
237
238void CellularCapabilityClassic::RegisterOnNetwork(
239 const string &/*network_id*/,
240 Error *error, const ResultCallback &/*callback*/) {
241 OnUnsupportedOperation(__func__, error);
242}
243
244void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
245 bool /*require*/,
246 Error *error,
247 const ResultCallback &/*callback*/) {
248 OnUnsupportedOperation(__func__, error);
249}
250
251void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
252 Error *error,
253 const ResultCallback &/*callback*/) {
254 OnUnsupportedOperation(__func__, error);
255}
256
257void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
258 const string &/*pin*/,
259 Error *error,
260 const ResultCallback &/*callback*/) {
261 OnUnsupportedOperation(__func__, error);
262}
263
264void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
265 const string &/*new_pin*/,
266 Error *error,
267 const ResultCallback &/*callback*/) {
268 OnUnsupportedOperation(__func__, error);
269}
270
271void CellularCapabilityClassic::Scan(Error *error,
272 const ResultCallback &callback) {
273 OnUnsupportedOperation(__func__, error);
274}
275
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400276void CellularCapabilityClassic::OnDBusPropertiesChanged(
277 const std::string &interface,
278 const DBusPropertiesMap &changed_properties,
279 const std::vector<std::string> &invalidated_properties) {
280 bool enabled;
281 // This solves a bootstrapping problem: If the modem is not yet
282 // enabled, there are no proxy objects associated with the capability
283 // object, so modem signals like StateChanged aren't seen. By monitoring
284 // changes to the Enabled property via the ModemManager, we're able to
285 // get the initialization process started, which will result in the
286 // creation of the proxy objects.
287 //
288 // The first time we see the change to Enabled (when the modem state
289 // is Unknown), we simply update the state, and rely on the Manager to
290 // enable the device when it is registered with the Manager. On subsequent
291 // changes to Enabled, we need to explicitly enable the device ourselves.
292 if (DBusProperties::GetBool(changed_properties,
293 kModemPropertyEnabled, &enabled)) {
294 Cellular::ModemState prev_modem_state = cellular()->modem_state();
295 if (enabled)
296 cellular()->set_modem_state(Cellular::kModemStateEnabled);
297 else
298 cellular()->set_modem_state(Cellular::kModemStateDisabled);
299 if (enabled && cellular()->state() == Cellular::kStateDisabled &&
300 prev_modem_state != Cellular::kModemStateUnknown &&
301 prev_modem_state != Cellular::kModemStateEnabled) {
302 cellular()->SetEnabled(true);
303 }
304 }
305}
306
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400307void CellularCapabilityClassic::OnGetModemStatusReply(
308 const ResultCallback &callback,
309 const DBusPropertiesMap &props,
310 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700311 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
312 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400313 if (error.IsSuccess()) {
314 DBusProperties::GetString(props, "carrier", &carrier_);
315 DBusProperties::GetString(props, "meid", &meid_);
316 DBusProperties::GetString(props, "imei", &imei_);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400317 DBusProperties::GetString(props, kModemPropertyIMSI, &imsi_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400318 DBusProperties::GetString(props, "esn", &esn_);
319 DBusProperties::GetString(props, "mdn", &mdn_);
320 DBusProperties::GetString(props, "min", &min_);
321 DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400322 UpdateStatus(props);
323 }
324 callback.Run(error);
325}
326
327void CellularCapabilityClassic::OnGetModemInfoReply(
328 const ResultCallback &callback,
329 const ModemHardwareInfo &info,
330 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700331 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400332 if (error.IsSuccess()) {
333 manufacturer_ = info._1;
334 model_id_ = info._2;
335 hardware_revision_ = info._3;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700336 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
337 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400338 }
339 callback.Run(error);
340}
341
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400342void CellularCapabilityClassic::OnModemStateChangedSignal(
343 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700344 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
345 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400346 cellular()->OnModemStateChanged(ConvertClassicToModemState(old_state),
347 ConvertClassicToModemState(new_state),
348 reason);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400349}
350
351} // namespace shill