[go: up one dir, main page]

Menu

[e0c929]: / src / at_misc.c  Maximize  Restore  History

Download this file

395 lines (329 with data), 10.3 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/*
** Ericsson AB, AT Library
** ST-Ericsson U300 RIL
**
** Copyright (C) Ericsson AB 2010
** Copyright (C) ST-Ericsson AB 2008-2009
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** Based on reference-ril by The Android Open Source Project.
**
** Modified for ST-Ericsson U300 modems.
** Author: Christian Bejram <christian.bejram@stericsson.com>
**
** Modified for Ericsson AB modems
** Author: Indrek Peri <Indrek.Peri@Ericsson.com>
*/
#define AT_ERROR_SIMULATION 1
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include "at_channel.h"
#include "at_misc.h"
#ifdef AT_ERROR_SIMULATION
#include <time.h>
struct es_tbl_elem {
char cmd[32];
int error;
};
#define AT_ERR_SIM_RANDOM 1
#define AT_ERR_SIM_TABLE 2
#define AT_ERR_SIM_NONE 3
static int g_err_sim_type = AT_ERR_SIM_NONE;
#define AT_ES_TBL_SZ 32
struct es_tbl_elem g_es_table[AT_ES_TBL_SZ];
static int g_es_seeded = 0;
static int g_es_call_count = 0;
static int g_es_modulus = 3;
static int g_es_table_read = 0; // read the table file
#endif // AT_ERROR_SIMULATION
/* Just check this file */
#ifdef __GNUC__
#pragma GCC diagnostic warning "-pedantic"
#endif
/** Returns 1 if line starts with prefix, 0 if it does not. */
int strStartsWith(const char *line, const char *prefix)
{
for (; *line != '\0' && *prefix != '\0'; line++, prefix++) {
if (*line != *prefix) {
return 0;
}
}
return *prefix == '\0';
}
struct ATResponse *at_response_new()
{
return (struct ATResponse *) calloc(1, sizeof(struct ATResponse));
}
void at_add_intermediate(const char *line, struct ATResponse *resp)
{
struct linked_list *tmp;
tmp = malloc(sizeof(struct linked_list));
if (!tmp) {
LOGE("Memory allocation failed");
return;
}
tmp->data = (void *) strdup(line);
tmp->next = resp->p_intermediates;
resp->p_intermediates = tmp;
}
/**
* Very simple function that extract and returns whats between ElementBeginTag
* and ElementEndTag.
*
* Optional ppszRemainingDocument that can return a pointer to the remaining
* of the document to be "scanned". This can be used if subsequent
* scanning/searching is desired.
*
* This function is used to extract the parameters from the XML result
* returned by U3xx during a PDP Context setup, and used to parse the
* tuples of operators returned from AT+COPS.
*
* const char* document - Document to be scanned
* const char* elementBeginTag - Begin tag to scan for, return whats
* between begin/end tags
* const char* elementEndTag - End tag to scan for, return whats
* between begin/end tags
* char** remainingDocumen t - Can return the a pointer to the remaining
* of pszDocument, this parameter is optional
*
* return char* containing whats between begin/end tags, allocated on the
* heap, need to free this.
* return NULL if nothing is found.
*/
char *getFirstElementValue(const char *document,
const char *elementBeginTag,
const char *elementEndTag,
char **remainingDocument)
{
char *value = NULL;
char *start = NULL;
char *end = NULL;
if (document != NULL && elementBeginTag != NULL
&& elementEndTag != NULL) {
start = strstr(document, elementBeginTag);
if (start != NULL) {
end = strstr(start, elementEndTag);
if (end != NULL) {
int n = strlen(elementBeginTag);
int m = end - (start + n);
value = (char *) malloc((m + 1) * sizeof(char));
strncpy(value, (start + n), m);
value[m] = (char) 0;
/* Optional, return a pointer to the remaining document,
to be used when document contains many tags with same name. */
if (remainingDocument != NULL) {
*remainingDocument = end + strlen(elementEndTag);
}
}
}
}
return value;
}
char char2nib(char c)
{
if (c >= 0x30 && c <= 0x39)
return c - 0x30;
if (c >= 0x41 && c <= 0x46)
return c - 0x41 + 0xA;
if (c >= 0x61 && c <= 0x66)
return c - 0x61 + 0xA;
return 0;
}
/* If multiline is needed add type here but we think now that
AT_SINGLE_LINE is default. */
struct at_prefix_finder_t {
char *cmd;
char *prefix;
};
/* Match is done now by looping, set more frequent commands to
beginning of table (like creg) */
#define AT_PREFIX_TABLE_MAX 6
struct at_prefix_finder_t at_prefixes[AT_PREFIX_TABLE_MAX] = {
{"AT+CREG?", "+CREG"},
{"AT+CFUN?", "+CFUN"},
{"AT+CGREG?", "+CGREG"},
{"AT+COPS?", "+COPS"},
{"AT+CIMI", "+CIMI"}, /* cimi does not have prefix but we use it internally */
{"AT*EIAC=", "*EIAC"}
};
void at_find_prefix(struct ATCommand *cmd)
{
int i, len;
if (cmd->type != AT_CHECK_PREFIX)
return;
for (i = 0; i < AT_PREFIX_TABLE_MAX; i++) {
if (i > AT_PREFIX_TABLE_MAX) {
LOGE("%s:at prefix out of range", __FUNCTION__);
return;
}
len = strlen(at_prefixes[i].cmd);
if (strncmp(at_prefixes[i].cmd, cmd->command, len) == 0) {
cmd->type = AT_SINGLE_LINE;
strncpy(cmd->responsePrefix, at_prefixes[i].prefix,
AT_MIN_LEN);
return;
}
}
LOGI("No prefix found");
cmd->type = AT_OK_ONLY;
}
/* Error simulation */
/* ------------------------------------ */
#ifdef AT_ERROR_SIMULATION
// Define here your random number range, error happening will calculated
// by using modulus. How many times rundom number is dividable by modulus.
#define AT_ES_MIN 1
#define AT_ES_MAX 10 //10000
#define AT_ES_TYPE_POS 0
#define AT_ES_MOD_POS 1
/*
e2gpssuplnirepy
at*eiad
at+creg?
at+creg=
at+cfun
at*eiac
at+cgdcont
at*e2gpssupl
at+cimi
at*eiauvw
at*e2gpssuplni
at*e2gpsstat
at*e2certun
at*e2gpsctl
at*e2certunreply
at*e2gpsnpd
ate
at*e2gpseph
at*e2gpsloc
at*e2gpstime
at+cops?
at+cops=
at+cgreg?
at+cgreg=
*/
static int es_generate_random()
{
int min, max, rn;
if (!g_es_seeded) {
srand(time(NULL)); // random seed on most compilers
g_es_seeded = 1;
}
min = AT_ES_MIN;
max = AT_ES_MAX;
rn = min + (int) ((float) max * rand() / (RAND_MAX + (float) min));
//j=1+(int)(10.0*rand()/(RAND_MAX+1.0));
return rn;
}
static void es_read_table()
{
#define O_MAX 50
FILE *file;
char *filename = "/etc/at_err_sim.txt";
char str[O_MAX];
char *help;
int i, ret, err;
for (i = 0; i < AT_ES_TBL_SZ; i++) {
g_es_table[i].cmd[0] = 0;
g_es_table[i].error = 0;
}
file = fopen(filename, "r");
if (file == NULL) {
LOGE("Failed to open file %s", filename);
return;
} else
LOGI("Opened err_sim file %s", filename);
for (i = 0; i < AT_ES_TBL_SZ; i++) {
str[0] = 0;
help = fgets(str, O_MAX, file);
err = ferror(file);
if (err) {
LOGE("Failed to read from err_sim, error=%d %s %d", err, str,
i);
goto exit_out;
} else if (feof(file)) {
LOGI("End of file reached %d", i);
goto exit_out;
}
if (str[0] == '#')
continue;
ret =
sscanf(str, "%s %d\n", g_es_table[i].cmd,
&g_es_table[i].error);
if (ret != 2) {
LOGE("sscanf read error %d %s", ret, str);
}
} // loop
exit_out:
LOGI("Mode %d, modulus %d, idx %d", g_es_table[AT_ES_TYPE_POS].error,
g_es_table[AT_ES_MOD_POS].error, i);
fclose(file);
}
static int es_is_error(const char *str)
{
int i = 0;
if (!g_es_table_read) {
es_read_table();
g_es_table_read = 1;
if (!strncmp
(g_es_table[AT_ES_TYPE_POS].cmd, "err_sim_type", AT_MIN_LEN)) {
g_err_sim_type = g_es_table[AT_ES_TYPE_POS].error;
}
if (!strncmp(g_es_table[AT_ES_MOD_POS].cmd, "modulus", AT_MIN_LEN)) {
g_es_modulus = g_es_table[AT_ES_MOD_POS].error;
}
}
if (g_err_sim_type == AT_ERR_SIM_RANDOM) {
int ret;
int rn = es_generate_random();
// ERROR = RANDOM_NUM % MODULUS
// First we get random number [MIN...MAX]
// Second, we make modulus for random number
// If you take modulus as 2,3,5,7,9 etc then you get
// certain error happening deviation
// The bigger the modulus = less error happens
ret = !(rn % g_es_modulus);
LOGI("rn %d, m %d, r %d", rn, g_es_modulus, ret);
return ret;
}
if (g_err_sim_type == AT_ERR_SIM_TABLE) {
for (i = 0; i < AT_ES_TBL_SZ; i++) {
if (strstr(str, g_es_table[i].cmd)) {
LOGI("cmd %s e %d", g_es_table[i].cmd,
g_es_table[i].error);
return g_es_table[i].error;
}
}
return 0; // no error
}
return 0; // no error
}
void es_reset_call_count()
{
g_es_call_count = 0;
g_es_table_read = 0; // next time read table again
}
/* This function is called when command gets OK. Here we can inject
our simulated error response */
void es_error_simulation(struct ATCommand *cmd)
{
if (es_is_error(cmd->command))
cmd->response->success = AT_FINAL_ERROR;
g_es_call_count++;
}
#endif // AT_ERROR_SIMULATION