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 dummy 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 
59 /**
60  * Logs a CHRE WWAN cell info result.
61  *
62  * @param cell the cell info to log.
63  */
logChreWwanInfo(const chreWwanCellInfo * cell)64 void logChreWwanInfo(const chreWwanCellInfo *cell) {
65   LOGI("Found cell at time %" PRIu64, cell->timeStamp);
66   LOGI("  timestamp type %" PRIu8, cell->timeStampType);
67   LOGI("  registered %" PRIu8, cell->registered);
68 
69   switch (cell->cellInfoType) {
70     case CHRE_WWAN_CELL_INFO_TYPE_LTE:
71       LOGI("  LTE cell detected");
72       LOGI("    mcc %" PRId32, cell->CellInfo.lte.cellIdentityLte.mcc);
73       LOGI("    mnc %" PRId32, cell->CellInfo.lte.cellIdentityLte.mnc);
74       LOGI("    ci %" PRId32, cell->CellInfo.lte.cellIdentityLte.ci);
75       LOGI("    pci %" PRId32, cell->CellInfo.lte.cellIdentityLte.pci);
76       LOGI("    tac %" PRId32, cell->CellInfo.lte.cellIdentityLte.tac);
77       LOGI("    earfcn %" PRId32, cell->CellInfo.lte.cellIdentityLte.earfcn);
78       break;
79     case CHRE_WWAN_CELL_INFO_TYPE_GSM:
80       LOGI("  GSM cell detected");
81       LOGI("    mcc %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.mcc);
82       LOGI("    mnc %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.mnc);
83       LOGI("    lac %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.lac);
84       LOGI("    cid %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.cid);
85       LOGI("    arfcn %" PRId32, cell->CellInfo.gsm.cellIdentityGsm.arfcn);
86       LOGI("    bsic %" PRIu8, cell->CellInfo.gsm.cellIdentityGsm.bsic);
87       break;
88     case CHRE_WWAN_CELL_INFO_TYPE_WCDMA:
89       LOGI("  WCDMA cell detected");
90       LOGI("    mcc %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.mcc);
91       LOGI("    mnc %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.mnc);
92       LOGI("    lac %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.lac);
93       LOGI("    cid %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.cid);
94       LOGI("    psc %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.psc);
95       LOGI("    uarfcn %" PRId32, cell->CellInfo.wcdma.cellIdentityWcdma.uarfcn);
96       break;
97     default:
98       // TODO: Support logging all cell types.
99       LOGI("  unsupported cell info %" PRIu8, cell->cellInfoType);
100       break;
101   };
102 }
103 
104 /**
105  * Handles a WWAN cell info result.
106  *
107  * @param result a WWAN cell info result.
108  */
handleCellInfoResult(const chreWwanCellInfoResult * result)109 void handleCellInfoResult(const chreWwanCellInfoResult *result) {
110   if (result->errorCode != CHRE_ERROR_NONE) {
111     LOGE("Failed to request WWAN cell info with %" PRIu8, result->errorCode);
112   } else {
113     LOGD("Received cell info result with version %" PRIu8, result->version);
114 
115     for (uint8_t i = 0; i < result->cellInfoCount; i++) {
116       logChreWwanInfo(&result->cells[i]);
117     }
118   }
119 }
120 
121 }  // namespace
122 
123 
nanoappStart()124 bool nanoappStart() {
125   LOGI("App started as instance %" PRIu32, chreGetInstanceId());
126 
127   const char *wwanCapabilitiesStr;
128   uint32_t wwanCapabilities = chreWwanGetCapabilities();
129   switch (wwanCapabilities) {
130     case CHRE_WWAN_GET_CELL_INFO:
131       wwanCapabilitiesStr = "GET_CELL_INFO";
132       break;
133     case CHRE_WWAN_CAPABILITIES_NONE:
134       wwanCapabilitiesStr = "NONE";
135       break;
136     default:
137       wwanCapabilitiesStr = "INVALID";
138   }
139 
140   LOGI("Detected WWAN support as: %s (%" PRIu32 ")",
141        wwanCapabilitiesStr, wwanCapabilities);
142 
143   if (wwanCapabilities & CHRE_WWAN_GET_CELL_INFO) {
144     gCellInfoTimerHandle = chreTimerSet(kCellInfoInterval.toRawNanoseconds(),
145                                         &gCellInfoTimerHandle /* data */,
146                                         false /* oneShot */);
147     if (gCellInfoTimerHandle == CHRE_TIMER_INVALID) {
148       LOGE("Failed to set a periodic cell info timer");
149     } else {
150       LOGI("Set a timer to request periodic cell info");
151     }
152   }
153 
154   return true;
155 }
156 
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)157 void nanoappHandleEvent(uint32_t senderInstanceId,
158                         uint16_t eventType,
159                         const void *eventData) {
160   switch (eventType) {
161     case CHRE_EVENT_TIMER:
162       handleTimerEvent(eventData);
163       break;
164     case CHRE_EVENT_WWAN_CELL_INFO_RESULT:
165       handleCellInfoResult(
166           static_cast<const chreWwanCellInfoResult *>(eventData));
167       break;
168     default:
169       LOGW("Unhandled event type %" PRIu16, eventType);
170   }
171 }
172 
nanoappEnd()173 void nanoappEnd() {
174   LOGI("Stopped");
175 }
176 
177 #ifdef CHRE_NANOAPP_INTERNAL
178 }  // anonymous namespace
179 }  // namespace chre
180 
181 #include "chre/util/nanoapp/app_id.h"
182 #include "chre/platform/static_nanoapp_init.h"
183 
184 CHRE_STATIC_NANOAPP_INIT(WwanWorld, chre::kWwanWorldAppId, 0);
185 #endif  // CHRE_NANOAPP_INTERNAL
186