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