1/*
2 * Copyright (C) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "at_modem.h"
17#include "vendor_adapter.h"
18#include "vendor_report.h"
19#include "vendor_util.h"
20
21struct ResponseAck {
22    ResponseInfo *responseInfo;
23    uint8_t *respDataPointer;
24    int32_t respDataLen;
25};
26
27static int32_t ResponseModemReport(
28    int32_t slotId, const ReqDataInfo *requestInfo, int32_t err, struct ResponseAck *respDataAck)
29{
30    if (requestInfo == NULL) {
31        TELEPHONY_LOGE("requestInfo is nullptr!");
32        return HRIL_ERR_GENERIC_FAILURE;
33    }
34    if (respDataAck == NULL) {
35        TELEPHONY_LOGE("respDataAck is nullptr!");
36        return HRIL_ERR_GENERIC_FAILURE;
37    }
38    struct ReportInfo reportInfo;
39    reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);
40    OnModemReport(slotId, reportInfo, (const uint8_t *)(respDataAck->respDataPointer), respDataAck->respDataLen);
41    if (respDataAck->responseInfo != NULL) {
42        FreeResponseInfo(respDataAck->responseInfo);
43    }
44    return err;
45}
46
47static int32_t GetResponseErrorCode(ResponseInfo *pResponseInfo)
48{
49    char *pLine = NULL;
50    int32_t ret = HRIL_ERR_GENERIC_FAILURE;
51    if (pResponseInfo && pResponseInfo->result) {
52        pLine = pResponseInfo->result;
53        SkipATPrefix(&pLine);
54        NextInt(&pLine, &ret);
55    }
56
57    if (ret == -1) {
58        ret = HRIL_ERR_INVALID_RESPONSE;
59    }
60    TELEPHONY_LOGD("modem response error code: %{public}d", ret);
61    return ret;
62}
63
64void ReqSetRadioState(const ReqDataInfo *requestInfo, int32_t function, int32_t reset)
65{
66    if (requestInfo == NULL) {
67        return;
68    }
69    struct ReportInfo reportInfo;
70    int32_t ret = SetRadioState(function, reset);
71    if (ret == HRIL_ERR_SUCCESS) {
72        reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_SUCCESS, HRIL_RESPONSE, 0);
73    } else {
74        TELEPHONY_LOGE("ReqSetRadioState failed");
75        if (ret == HRIL_ERR_REPEAT_STATUS) {
76            reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_REPEAT_STATUS, HRIL_RESPONSE, 0);
77        } else {
78            reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_GENERIC_FAILURE, HRIL_RESPONSE, 0);
79        }
80    }
81    OnModemReport(requestInfo->slotId, reportInfo, NULL, 0);
82}
83
84static void ErrorHandler(const ReqDataInfo *requestInfo, ResponseInfo *pResponse)
85{
86    if (requestInfo == NULL) {
87        return;
88    }
89    struct ReportInfo reportInfo;
90    reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_GENERIC_FAILURE, HRIL_RESPONSE, 0);
91    OnModemReport(requestInfo->slotId, reportInfo, NULL, 0);
92    FreeResponseInfo(pResponse);
93}
94
95void ReqGetRadioState(const ReqDataInfo *requestInfo)
96{
97    if (requestInfo == NULL) {
98        return;
99    }
100    const long long timeOut = DEFAULT_TIMEOUT;
101    char *pLine = NULL;
102    int32_t radioState = -1;
103    ResponseInfo *pResponse = NULL;
104    struct ReportInfo reportInfo;
105
106    int32_t ret = SendCommandLock("AT+CFUN?", "+CFUN", timeOut, &pResponse);
107    if (ret != 0 || pResponse == NULL || !pResponse->success) {
108        TELEPHONY_LOGE("AT+CFUN send failed");
109        return ErrorHandler(requestInfo, pResponse);
110    }
111    if (pResponse->head != NULL) {
112        pLine = pResponse->head->data;
113    }
114
115    ret = SkipATPrefix(&pLine);
116    if (ret != 0) {
117        return ErrorHandler(requestInfo, pResponse);
118    }
119    ret = NextInt(&pLine, &radioState);
120    if (ret != 0) {
121        return ErrorHandler(requestInfo, pResponse);
122    }
123
124    reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_SUCCESS, HRIL_RESPONSE, 0);
125    OnModemReport(requestInfo->slotId, reportInfo, (const uint8_t *)&radioState, sizeof(int32_t));
126    FreeResponseInfo(pResponse);
127    return;
128}
129
130void ReqGetImei(const ReqDataInfo *requestInfo)
131{
132    if (requestInfo == NULL) {
133        return;
134    }
135    int32_t err = HRIL_ERR_SUCCESS;
136    ResponseInfo *responseInfo = NULL;
137    TELEPHONY_LOGD("enter to [%{public}s]:%{public}d", __func__, __LINE__);
138    int32_t ret = SendCommandLock("AT+CGSN", NULL, DEFAULT_TIMEOUT, &responseInfo);
139    struct ResponseAck respDataAck = { responseInfo, NULL, 0 };
140    if (responseInfo == NULL) {
141        TELEPHONY_LOGE("responseInfo is null");
142        ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_NULL_POINT, &respDataAck);
143        return;
144    }
145    respDataAck.responseInfo = responseInfo;
146    if (ret != 0 || !responseInfo->success) {
147        err = GetResponseErrorCode(responseInfo);
148        TELEPHONY_LOGE("send AT CMD failed!");
149        ResponseModemReport(requestInfo->slotId, requestInfo, err, &respDataAck);
150        return;
151    }
152    if (responseInfo->head == NULL) {
153        TELEPHONY_LOGE("no data!");
154        ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_INVALID_RESPONSE, &respDataAck);
155        return;
156    }
157    char *imeiSn = responseInfo->head->data;
158    if ((imeiSn == NULL) || (strlen(imeiSn) == 0)) {
159        TELEPHONY_LOGE("ReqGetImei: ResponseInfo is Invalid!");
160        ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_INVALID_RESPONSE, &respDataAck);
161        return;
162    }
163    respDataAck.respDataPointer = (uint8_t *)imeiSn;
164    respDataAck.respDataLen = strlen(imeiSn);
165    ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_SUCCESS, &respDataAck);
166}
167
168void ReqGetImeiSv(const ReqDataInfo *requestInfo)
169{
170    if (requestInfo == NULL) {
171        return;
172    }
173    ResponseInfo *responseInfo = NULL;
174    struct ReportInfo reportInfo;
175    reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_SUCCESS, HRIL_RESPONSE, 0);
176    OnModemReport(requestInfo->slotId, reportInfo, NULL, 0);
177    FreeResponseInfo(responseInfo);
178}
179
180void ReqGetMeid(const ReqDataInfo *requestInfo)
181{
182    if (requestInfo == NULL) {
183        return;
184    }
185    int32_t err = HRIL_ERR_SUCCESS;
186    ResponseInfo *responseInfo = NULL;
187    TELEPHONY_LOGD("enter to [%{public}s]:%{public}d", __func__, __LINE__);
188    int32_t ret = SendCommandLock("AT+MEID", NULL, DEFAULT_TIMEOUT, &responseInfo);
189    struct ResponseAck respDataAck = { responseInfo, NULL, 0 };
190    if (responseInfo == NULL) {
191        ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_NULL_POINT, &respDataAck);
192        return;
193    }
194    respDataAck.responseInfo = responseInfo;
195    if (ret != 0 || !responseInfo->success) {
196        err = GetResponseErrorCode(responseInfo);
197        TELEPHONY_LOGE("send AT CMD failed!");
198        ResponseModemReport(requestInfo->slotId, requestInfo, err, &respDataAck);
199        return;
200    }
201    if (responseInfo->head == NULL) {
202        TELEPHONY_LOGE("no data!");
203        ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_INVALID_RESPONSE, &respDataAck);
204        return;
205    }
206    char *meidSn = responseInfo->head->data;
207    if ((meidSn == NULL) || (strlen(meidSn) == 0)) {
208        ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_INVALID_RESPONSE, &respDataAck);
209        return;
210    }
211    respDataAck.respDataPointer = (uint8_t *)meidSn;
212    respDataAck.respDataLen = strlen(meidSn);
213    ResponseModemReport(requestInfo->slotId, requestInfo, HRIL_ERR_SUCCESS, &respDataAck);
214}
215
216static HRilRadioTech ConvertVoiceTechToRadioTech(HRilVoiceSubMode subMode)
217{
218    switch (subMode) {
219        case HRIL_ACT_GSM:
220        case HRIL_ACT_GPRS:
221        case HRIL_ACT_EDGE:
222            return RADIO_TECHNOLOGY_GSM;
223        case HRIL_ACT_HSPA:
224        case HRIL_ACT_HSDPA:
225        case HRIL_ACT_HSUPA:
226            return RADIO_TECHNOLOGY_HSPA;
227        case HRIL_ACT_HSPAP:
228        case HRIL_ACT_DC_HSPAP:
229            return RADIO_TECHNOLOGY_HSPAP;
230        case HRIL_ACT_WCDMA:
231            return RADIO_TECHNOLOGY_WCDMA;
232        case HRIL_ACT_LTE:
233            return RADIO_TECHNOLOGY_LTE;
234        case HRIL_ACT_IS95A:
235        case HRIL_ACT_IS95B:
236        case HRIL_ACT_CDMA2000_1X:
237        case HRIL_ACT_HYBRID_CDMA2000_1X:
238            return RADIO_TECHNOLOGY_1XRTT;
239        case HRIL_ACT_EVDO_REL0:
240        case HRIL_ACT_EVDO_RELA:
241        case HRIL_ACT_EVDO_RELB:
242        case HRIL_ACT_HYBRID_EVDO_REL0:
243        case HRIL_ACT_HYBRID_EVDO_RELA:
244        case HRIL_ACT_HYBRID_EVDO_RELB:
245            return RADIO_TECHNOLOGY_EVDO;
246        case HRIL_ACT_TDSCDMA:
247            return RADIO_TECHNOLOGY_TD_SCDMA;
248        case HRIL_ACT_LTE_CA:
249            return RADIO_TECHNOLOGY_LTE_CA;
250        case HRIL_ACT_802_16E:
251            return RADIO_TECHNOLOGY_IWLAN;
252        case HRIL_ACT_NR:
253            return RADIO_TECHNOLOGY_NR;
254        default:
255            return RADIO_TECHNOLOGY_UNKNOWN;
256    }
257}
258
259int32_t ProcessVoiceRadioInfo(const char *s, const HRilVoiceRadioInfo *hrilVoiceRadioInfo)
260{
261    int32_t srvStatus = 0;
262    int32_t srvDomain = 0;
263    int32_t roamStatus = 0;
264    int32_t simStatus = 0;
265    int32_t lockStatus = 0;
266    int32_t sysMode = 0;
267    int32_t actType = 0;
268    char *str = (char *)s;
269    HRilVoiceRadioInfo *voiceRadioInfo = (HRilVoiceRadioInfo *)hrilVoiceRadioInfo;
270    if ((str == NULL) || (voiceRadioInfo == NULL)) {
271        TELEPHONY_LOGE("ProcessVoiceRadioInfo s or voiceRadioInfo param is null");
272        return HRIL_ERR_NULL_POINT;
273    } else {
274        (void)memset_s(voiceRadioInfo, sizeof(HRilVoiceRadioInfo), 0, sizeof(HRilVoiceRadioInfo));
275        TELEPHONY_LOGD("result: %{public}s", str);
276        int32_t err = SkipATPrefix(&str);
277        if (err < 0) {
278            TELEPHONY_LOGE("skip failed: [%{public}s]", str);
279            return HRIL_ERR_INVALID_RESPONSE;
280        }
281        int32_t commaNum = FindCommaCharNum(str);
282        const int32_t VOICE_COMMA_NUM = 8;
283        if (commaNum != VOICE_COMMA_NUM) {
284            TELEPHONY_LOGE("ProcessVoiceRadioInfo failed commaNum: [%{public}d]", commaNum);
285            return HRIL_ERR_INVALID_RESPONSE;
286        }
287        NextIntNotSkipNextComma(&str, &srvStatus);
288        voiceRadioInfo->srvStatus = srvStatus;
289        NextIntNotSkipNextComma(&str, &srvDomain);
290        voiceRadioInfo->srvDomain = srvDomain;
291        NextIntNotSkipNextComma(&str, &roamStatus);
292        voiceRadioInfo->roamStatus = roamStatus;
293        NextIntNotSkipNextComma(&str, &simStatus);
294        voiceRadioInfo->simStatus = simStatus;
295        if (NextIntNotSkipNextComma(&str, &lockStatus) < 0) {
296            voiceRadioInfo->lockStatus = 0;
297        } else {
298            voiceRadioInfo->lockStatus = lockStatus;
299        }
300        NextIntNotSkipNextComma(&str, &sysMode);
301        voiceRadioInfo->sysMode = sysMode;
302        NextStr(&str, &(voiceRadioInfo->sysModeName));
303        NextIntNotSkipNextComma(&str, &actType);
304        voiceRadioInfo->actType = ConvertVoiceTechToRadioTech((HRilVoiceSubMode)actType);
305        NextStr(&str, &(voiceRadioInfo->actName));
306        return HRIL_ERR_SUCCESS;
307    }
308}
309
310void ReqGetVoiceRadioTechnology(const ReqDataInfo *requestInfo)
311{
312    if (requestInfo == NULL) {
313        return;
314    }
315    int32_t err = HRIL_ERR_SUCCESS;
316    struct ReportInfo reportInfo;
317    ResponseInfo *responseInfo = NULL;
318    char *result = NULL;
319    int32_t ret = SendCommandLock("AT^SYSINFOEX", "^SYSINFOEX:", DEFAULT_TIMEOUT, &responseInfo);
320    if (responseInfo == NULL) {
321        TELEPHONY_LOGE("responseInfo is nullptr!");
322        reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_NULL_POINT, HRIL_RESPONSE, 0);
323        OnModemReport(requestInfo->slotId, reportInfo, NULL, 0);
324        return;
325    }
326    if (ret != 0 || !responseInfo->success) {
327        err = GetResponseErrorCode(responseInfo);
328        TELEPHONY_LOGE("send AT CMD failed!");
329    }
330    HRilVoiceRadioInfo voiceRadioInfo = {0};
331    if (responseInfo->head != NULL) {
332        result = responseInfo->head->data;
333    }
334    ret = ProcessVoiceRadioInfo(result, &voiceRadioInfo);
335    if (ret != 0) {
336        TELEPHONY_LOGE("ProcessVoiceRadioInfo format  unexpected: %{public}s", result);
337        reportInfo = CreateReportInfo(requestInfo, HRIL_ERR_INVALID_RESPONSE, HRIL_RESPONSE, 0);
338        OnModemReport(requestInfo->slotId, reportInfo, NULL, 0);
339        FreeResponseInfo(responseInfo);
340        return;
341    }
342    reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);
343    OnModemReport(requestInfo->slotId, reportInfo, (const uint8_t *)&voiceRadioInfo, sizeof(HRilVoiceRadioInfo));
344    FreeResponseInfo(responseInfo);
345}
346