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