1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <chre.h>
18 #include <cinttypes>
19
20 #include "chre/util/macros.h"
21 #include "chre/util/nanoapp/log.h"
22 #include "chre/util/time.h"
23
24 #define LOG_TAG "[WwanWorld]"
25
26 #ifdef CHRE_NANOAPP_INTERNAL
27 namespace chre {
28 namespace {
29 #endif // CHRE_NANOAPP_INTERNAL
30
31 //! A fake/unused cookie to pass into the cell info request.
32 const uint32_t kCellInfoCookie = 0x1337;
33
34 //! The interval for cell info requests.
35 const Nanoseconds kCellInfoInterval = Nanoseconds(Seconds(10));
36
37 //! A handle for the cyclic timer to request periodic cell info.
38 uint32_t gCellInfoTimerHandle;
39
40 namespace {
41
42 /**
43 * Handles a timer event.
44 *
45 * @param eventData The cookie passed to the timer request.
46 */
handleTimerEvent(const void * eventData)47 void handleTimerEvent(const void *eventData) {
48 const uint32_t *timerHandle = static_cast<const uint32_t *>(eventData);
49 if (*timerHandle == gCellInfoTimerHandle) {
50 if (chreWwanGetCellInfoAsync(&kCellInfoCookie)) {
51 LOGI("Requested cell info successfully");
52 } else {
53 LOGE("Failed to request cell info");
54 }
55 } else {
56 LOGE("Received invalid timer handle");
57 }
58 }
59
logNrCellInfo(const chreWwanCellInfoNr & nr)60 void logNrCellInfo(const chreWwanCellInfoNr &nr) {
61 LOGI(" NR cell detected");
62 LOGI(" mcc %" PRId32, nr.cellIdentityNr.mcc);
63 LOGI(" mnc %" PRId32, nr.cellIdentityNr.mnc);
64 LOGI(" nci %" PRId64, chreWwanUnpackNrNci(&nr.cellIdentityNr));
65 LOGI(" pci %" PRId32, nr.cellIdentityNr.pci);
66 LOGI(" tac %" PRId32, nr.cellIdentityNr.tac);
67 LOGI(" nrarfcn %" PRId32, nr.cellIdentityNr.nrarfcn);
68 LOGI(" ssRsrp %" PRId32 ", %" PRId32 " dBm", nr.signalStrengthNr.ssRsrp,
69 -1 * nr.signalStrengthNr.ssRsrp);
70 LOGI(" ssRsrq %" PRId32 ", %.1f dB", nr.signalStrengthNr.ssRsrq,
71 static_cast<float>(nr.signalStrengthNr.ssRsrp) / 2.0f);
72 LOGI(" ssSinr %" PRId32 ", %.1f dB", nr.signalStrengthNr.ssSinr,
73 static_cast<float>(nr.signalStrengthNr.ssSinr) / 2.0f);
74 LOGI(" csiRsrp %" PRId32 ", %" PRId32 " dBm", nr.signalStrengthNr.csiRsrp,
75 -1 * nr.signalStrengthNr.csiRsrp);
76 LOGI(" csiRsrq %" PRId32 ", %.1f dB", nr.signalStrengthNr.csiRsrq,
77 static_cast<float>(nr.signalStrengthNr.csiRsrp) / 2.0f);
78 LOGI(" csiSinr %" PRId32 ", %.1f dB", nr.signalStrengthNr.csiSinr,
79 static_cast<float>(nr.signalStrengthNr.csiSinr) / 2.0f);
80 }
81
82 /**
83 * Logs a CHRE WWAN cell info result.
84 *
85 * @param cell the cell info to log.
86 */
logChreWwanInfo(const chreWwanCellInfo * cell)87 void logChreWwanInfo(const chreWwanCellInfo *cell) {
88 LOGI("Found cell at time %" PRIu64, cell->timeStamp);
89 LOGI(" timestamp type %" PRIu8, cell->timeStampType);
90 LOGI(" registered %" PRIu8, cell->registered);
91
92 switch (cell->cellInfoType) {
93 case CHRE_WWAN_CELL_INFO_TYPE_GSM:
94 LOGI(" GSM cell detected");
95 LOGI(" mcc %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.mcc);
96 LOGI(" mnc %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.mnc);
97 LOGI(" lac %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.lac);
98 LOGI(" cid %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.cid);
99 LOGI(" arfcn %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.arfcn);
100 LOGI(" bsic %" PRIu8, cell->CellInfo.gsm.cellIdentityGsm.bsic);
101 break;
102 case CHRE_WWAN_CELL_INFO_TYPE_CDMA:
103 LOGW(" CDMA unsupported");
104 break;
105 case CHRE_WWAN_CELL_INFO_TYPE_LTE:
106 LOGI(" LTE cell detected");
107 LOGI(" mcc %" PRId32, cell->CellInfo.lte.cellIdentityLte.mcc);
108 LOGI(" mnc %" PRId32, cell->CellInfo.lte.cellIdentityLte.mnc);
109 LOGI(" ci %" PRId32, cell->CellInfo.lte.cellIdentityLte.ci);
110 LOGI(" pci %" PRId32, cell->CellInfo.lte.cellIdentityLte.pci);
111 LOGI(" tac %" PRId32, cell->CellInfo.lte.cellIdentityLte.tac);
112 LOGI(" earfcn %" PRId32, cell->CellInfo.lte.cellIdentityLte.earfcn);
113 break;
114 case CHRE_WWAN_CELL_INFO_TYPE_WCDMA:
115 LOGI(" WCDMA cell detected");
116 LOGI(" mcc %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.mcc);
117 LOGI(" mnc %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.mnc);
118 LOGI(" lac %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.lac);
119 LOGI(" cid %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.cid);
120 LOGI(" psc %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.psc);
121 LOGI(" uarfcn %" PRId32,
122 cell->CellInfo.wcdma.cellIdentityWcdma.uarfcn);
123 break;
124 case CHRE_WWAN_CELL_INFO_TYPE_TD_SCDMA:
125 LOGW(" TD-SCDMA unsupported");
126 break;
127 case CHRE_WWAN_CELL_INFO_TYPE_NR:
128 logNrCellInfo(cell->CellInfo.nr);
129 break;
130 default:
131 LOGE(" invalid cell info type %" PRIu8, cell->cellInfoType);
132 break;
133 };
134 }
135
136 /**
137 * Handles a WWAN cell info result.
138 *
139 * @param result a WWAN cell info result.
140 */
handleCellInfoResult(const chreWwanCellInfoResult * result)141 void handleCellInfoResult(const chreWwanCellInfoResult *result) {
142 if (result->errorCode != CHRE_ERROR_NONE) {
143 LOGE("Failed to request WWAN cell info with %" PRIu8, result->errorCode);
144 } else {
145 LOGD("Received %" PRIu8 " cell info results with version %" PRIu8,
146 result->cellInfoCount, result->version);
147
148 for (uint8_t i = 0; i < result->cellInfoCount; i++) {
149 logChreWwanInfo(&result->cells[i]);
150 }
151 }
152 }
153
154 } // namespace
155
nanoappStart()156 bool nanoappStart() {
157 LOGI("App started as instance %" PRIu32, chreGetInstanceId());
158
159 const char *wwanCapabilitiesStr;
160 uint32_t wwanCapabilities = chreWwanGetCapabilities();
161 switch (wwanCapabilities) {
162 case CHRE_WWAN_GET_CELL_INFO:
163 wwanCapabilitiesStr = "GET_CELL_INFO";
164 break;
165 case CHRE_WWAN_CAPABILITIES_NONE:
166 wwanCapabilitiesStr = "NONE";
167 break;
168 default:
169 wwanCapabilitiesStr = "INVALID";
170 }
171
172 LOGI("Detected WWAN support as: %s (%" PRIu32 ")", wwanCapabilitiesStr,
173 wwanCapabilities);
174
175 if (wwanCapabilities & CHRE_WWAN_GET_CELL_INFO) {
176 gCellInfoTimerHandle =
177 chreTimerSet(kCellInfoInterval.toRawNanoseconds(),
178 &gCellInfoTimerHandle /* data */, false /* oneShot */);
179 if (gCellInfoTimerHandle == CHRE_TIMER_INVALID) {
180 LOGE("Failed to set a periodic cell info timer");
181 } else {
182 LOGI("Set a timer to request periodic cell info");
183 }
184 }
185
186 return true;
187 }
188
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)189 void nanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
190 const void *eventData) {
191 UNUSED_VAR(senderInstanceId);
192
193 switch (eventType) {
194 case CHRE_EVENT_TIMER:
195 handleTimerEvent(eventData);
196 break;
197 case CHRE_EVENT_WWAN_CELL_INFO_RESULT:
198 handleCellInfoResult(
199 static_cast<const chreWwanCellInfoResult *>(eventData));
200 break;
201 default:
202 LOGW("Unhandled event type %" PRIu16, eventType);
203 }
204 }
205
nanoappEnd()206 void nanoappEnd() {
207 LOGI("Stopped");
208 }
209
210 #ifdef CHRE_NANOAPP_INTERNAL
211 } // anonymous namespace
212 } // namespace chre
213
214 #include "chre/platform/static_nanoapp_init.h"
215 #include "chre/util/nanoapp/app_id.h"
216 #include "chre/util/system/napp_permissions.h"
217
218 CHRE_STATIC_NANOAPP_INIT(WwanWorld, chre::kWwanWorldAppId, 0,
219 chre::NanoappPermissions::CHRE_PERMS_WWAN);
220 #endif // CHRE_NANOAPP_INTERNAL
221