2009-05-11 06:39:27 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* oFono - Open Source Telephony
|
|
|
|
*
|
2010-01-02 01:00:10 +00:00
|
|
|
* Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
|
2010-01-25 19:25:29 +00:00
|
|
|
* Copyright (C) 2010 ST-Ericsson AB.
|
2009-05-11 06:39:27 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include <ofono/log.h>
|
2009-07-29 19:33:58 +00:00
|
|
|
#include <ofono/modem.h>
|
2009-08-19 17:10:44 +00:00
|
|
|
#include <ofono/netreg.h>
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
#include "gatchat.h"
|
|
|
|
#include "gatresult.h"
|
|
|
|
|
2009-09-04 19:05:15 +00:00
|
|
|
#include "atmodem.h"
|
2009-09-04 04:05:18 +00:00
|
|
|
#include "vendor.h"
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
static const char *none_prefix[] = { NULL };
|
|
|
|
static const char *creg_prefix[] = { "+CREG:", NULL };
|
|
|
|
static const char *cops_prefix[] = { "+COPS:", NULL };
|
|
|
|
static const char *csq_prefix[] = { "+CSQ:", NULL };
|
2010-01-25 19:25:29 +00:00
|
|
|
static const char *cind_prefix[] = { "+CIND:", NULL };
|
2010-06-14 17:37:03 +00:00
|
|
|
static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL };
|
2010-01-25 19:25:29 +00:00
|
|
|
|
2009-05-11 06:39:27 +00:00
|
|
|
struct netreg_data {
|
2009-08-19 17:10:44 +00:00
|
|
|
GAtChat *chat;
|
2009-06-13 00:33:55 +00:00
|
|
|
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
|
|
|
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
2010-03-26 20:26:10 +00:00
|
|
|
int signal_index; /* If strength is reported via CIND */
|
|
|
|
int signal_min; /* min strength reported via CIND */
|
|
|
|
int signal_max; /* max strength reported via CIND */
|
2010-03-29 05:09:10 +00:00
|
|
|
int tech;
|
2010-10-20 11:55:20 +00:00
|
|
|
struct ofono_network_time time;
|
2009-09-04 04:05:18 +00:00
|
|
|
unsigned int vendor;
|
2009-05-11 06:39:27 +00:00
|
|
|
};
|
|
|
|
|
2010-06-14 17:37:03 +00:00
|
|
|
struct tech_query {
|
|
|
|
int status;
|
|
|
|
int lac;
|
|
|
|
int ci;
|
|
|
|
struct ofono_netreg *netreg;
|
|
|
|
};
|
|
|
|
|
2009-06-12 07:02:52 +00:00
|
|
|
static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
|
|
|
/* Three digit country code */
|
2009-06-13 00:33:55 +00:00
|
|
|
strncpy(mcc, str, OFONO_MAX_MCC_LENGTH);
|
|
|
|
mcc[OFONO_MAX_MCC_LENGTH] = '\0';
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
/* Usually a 2 but sometimes 3 digit network code */
|
2009-06-13 00:33:55 +00:00
|
|
|
strncpy(mnc, str + OFONO_MAX_MCC_LENGTH, OFONO_MAX_MNC_LENGTH);
|
|
|
|
mnc[OFONO_MAX_MNC_LENGTH] = '\0';
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2010-06-14 17:37:03 +00:00
|
|
|
static int option_parse_tech(GAtResult *result)
|
|
|
|
{
|
|
|
|
GAtResultIter iter;
|
|
|
|
int s, octi, ouwcti;
|
|
|
|
int tech = -1;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "_OCTI:"))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &s))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &octi))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "_OUWCTI:"))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &s))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &ouwcti))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (octi) {
|
|
|
|
case 1: /* GSM */
|
|
|
|
tech = 0;
|
|
|
|
break;
|
|
|
|
case 2: /* GPRS */
|
|
|
|
tech = 1;
|
|
|
|
break;
|
|
|
|
case 3: /* EDGE */
|
|
|
|
tech = 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ouwcti) {
|
|
|
|
case 1: /* UMTS */
|
|
|
|
tech = 2;
|
|
|
|
break;
|
|
|
|
case 2: /* HSDPA */
|
|
|
|
tech = 4;
|
|
|
|
break;
|
|
|
|
case 3: /* HSUPA */
|
|
|
|
tech = 5;
|
|
|
|
break;
|
|
|
|
case 4: /* HSPA */
|
|
|
|
tech = 6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("octi %d ouwcti %d tech %d", octi, ouwcti, tech);
|
|
|
|
|
|
|
|
return tech;
|
|
|
|
}
|
|
|
|
|
2009-05-11 06:39:27 +00:00
|
|
|
static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_status_cb_t cb = cbd->cb;
|
2009-12-09 18:50:52 +00:00
|
|
|
int status, lac, ci, tech;
|
2009-05-11 06:39:27 +00:00
|
|
|
struct ofono_error error;
|
2010-01-18 14:30:13 +00:00
|
|
|
struct netreg_data *nd = cbd->user;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, -1, -1, -1, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-09 18:50:52 +00:00
|
|
|
if (at_util_parse_reg(result, "+CREG:", NULL, &status,
|
2010-01-18 14:30:13 +00:00
|
|
|
&lac, &ci, &tech, nd->vendor) == FALSE) {
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
|
2009-05-11 06:39:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-29 05:09:10 +00:00
|
|
|
if ((status == 1 || status == 5) && (tech == -1))
|
|
|
|
tech = nd->tech;
|
|
|
|
|
2009-05-11 06:39:27 +00:00
|
|
|
cb(&error, status, lac, ci, tech, cbd->data);
|
|
|
|
}
|
|
|
|
|
2010-06-14 17:37:03 +00:00
|
|
|
static void option_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
struct ofono_netreg *netreg = cbd->data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
nd->tech = option_parse_tech(result);
|
|
|
|
else
|
|
|
|
nd->tech = -1;
|
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_registration_status(struct ofono_netreg *netreg,
|
|
|
|
ofono_netreg_status_cb_t cb,
|
2009-05-11 06:39:27 +00:00
|
|
|
void *data)
|
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2010-01-18 14:30:13 +00:00
|
|
|
cbd->user = nd;
|
|
|
|
|
2010-06-06 20:12:37 +00:00
|
|
|
switch (nd->vendor) {
|
|
|
|
case OFONO_VENDOR_MBM:
|
|
|
|
/*
|
|
|
|
* Send *ERINFO to find out the current tech, it will be
|
|
|
|
* intercepted in mbm_erinfo_notify
|
|
|
|
*/
|
2010-03-29 04:58:37 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT*ERINFO?", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
2010-06-06 20:12:37 +00:00
|
|
|
break;
|
|
|
|
case OFONO_VENDOR_NOVATEL:
|
|
|
|
/*
|
|
|
|
* Send $CNTI=0 to find out the current tech, it will be
|
|
|
|
* intercepted in nw_cnti_notify
|
|
|
|
*/
|
|
|
|
g_at_chat_send(nd->chat, "AT$CNTI=0", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
break;
|
2010-06-14 17:37:03 +00:00
|
|
|
case OFONO_VENDOR_OPTION_HSO:
|
|
|
|
/*
|
|
|
|
* Send AT_OCTI?;_OUWCTI? to find out the current tech,
|
|
|
|
* option_tech_cb will call fire CREG? to do the rest.
|
|
|
|
*/
|
|
|
|
if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?",
|
2010-06-14 17:45:04 +00:00
|
|
|
option_tech_prefix,
|
|
|
|
option_tech_cb, cbd, NULL) == 0)
|
2010-06-14 17:37:03 +00:00
|
|
|
nd->tech = -1;
|
|
|
|
break;
|
2010-06-06 20:12:37 +00:00
|
|
|
}
|
2010-03-29 04:58:37 +00:00
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
if (g_at_chat_send(nd->chat, "AT+CREG?", creg_prefix,
|
2009-05-11 06:39:27 +00:00
|
|
|
at_creg_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cops_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(cbd->user);
|
|
|
|
ofono_netreg_operator_cb_t cb = cbd->cb;
|
2009-05-11 06:39:27 +00:00
|
|
|
struct ofono_network_operator op;
|
|
|
|
GAtResultIter iter;
|
|
|
|
int format, tech;
|
|
|
|
const char *name;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
2010-06-07 16:24:13 +00:00
|
|
|
if (!ok)
|
|
|
|
goto error;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+COPS:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
|
|
|
|
ok = g_at_result_iter_next_number(&iter, &format);
|
|
|
|
|
|
|
|
if (ok == FALSE || format != 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_string(&iter, &name) == FALSE)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Default to GSM */
|
|
|
|
if (g_at_result_iter_next_number(&iter, &tech) == FALSE)
|
|
|
|
tech = 0;
|
|
|
|
|
|
|
|
strncpy(op.name, name, OFONO_MAX_OPERATOR_NAME_LENGTH);
|
|
|
|
op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
strncpy(op.mcc, nd->mcc, OFONO_MAX_MCC_LENGTH);
|
2009-06-13 00:33:55 +00:00
|
|
|
op.mcc[OFONO_MAX_MCC_LENGTH] = '\0';
|
2009-06-12 07:02:52 +00:00
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
strncpy(op.mnc, nd->mnc, OFONO_MAX_MNC_LENGTH);
|
2009-06-13 00:33:55 +00:00
|
|
|
op.mnc[OFONO_MAX_MNC_LENGTH] = '\0';
|
2009-06-12 07:02:52 +00:00
|
|
|
|
2009-11-18 19:02:02 +00:00
|
|
|
/* Set to current */
|
|
|
|
op.status = 2;
|
2009-05-11 06:39:27 +00:00
|
|
|
op.tech = tech;
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("cops_cb: %s, %s %s %d", name, nd->mcc, nd->mnc, tech);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
cb(&error, &op, cbd->data);
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-06-07 16:24:13 +00:00
|
|
|
cb(&error, NULL, cbd->data);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cops_numeric_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(cbd->user);
|
2010-06-07 16:24:13 +00:00
|
|
|
ofono_netreg_operator_cb_t cb = cbd->cb;
|
2009-05-11 06:39:27 +00:00
|
|
|
GAtResultIter iter;
|
|
|
|
const char *str;
|
|
|
|
int format;
|
2010-06-07 16:24:13 +00:00
|
|
|
int len;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+COPS:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
|
|
|
|
ok = g_at_result_iter_next_number(&iter, &format);
|
|
|
|
|
|
|
|
if (ok == FALSE || format != 2)
|
|
|
|
goto error;
|
|
|
|
|
2010-06-07 16:24:13 +00:00
|
|
|
if (g_at_result_iter_next_string(&iter, &str) == FALSE)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
len = strspn(str, "0123456789");
|
|
|
|
|
|
|
|
if (len != 5 && len != 6)
|
2009-05-11 06:39:27 +00:00
|
|
|
goto error;
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
extract_mcc_mnc(str, nd->mcc, nd->mnc);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("Cops numeric got mcc: %s, mnc: %s", nd->mcc, nd->mnc);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2010-06-07 16:24:13 +00:00
|
|
|
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix,
|
|
|
|
cops_cb, cbd, NULL);
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
return;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
error:
|
2010-06-07 16:24:13 +00:00
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_current_operator(struct ofono_netreg *netreg,
|
|
|
|
ofono_netreg_operator_cb_t cb, void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
gboolean ok;
|
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
cbd->user = netreg;
|
|
|
|
|
2010-08-20 01:00:49 +00:00
|
|
|
/* Nokia modems have a broken return value for the string
|
|
|
|
* returned for the numeric value. It misses a " at the end.
|
|
|
|
* Trying to read this will stall the parser. So skip it. */
|
|
|
|
if (nd->vendor == OFONO_VENDOR_NOKIA) {
|
|
|
|
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix,
|
|
|
|
cops_cb, cbd, NULL);
|
|
|
|
} else {
|
|
|
|
ok = g_at_chat_send(nd->chat, "AT+COPS=3,2", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix,
|
|
|
|
cops_numeric_cb, cbd, NULL);
|
|
|
|
}
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (ok)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cops_list_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_operator_list_cb_t cb = cbd->cb;
|
2009-05-11 06:39:27 +00:00
|
|
|
struct ofono_network_operator *list;
|
|
|
|
GAtResultIter iter;
|
|
|
|
int num = 0;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, 0, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
while (g_at_result_iter_next(&iter, "+COPS:")) {
|
|
|
|
while (g_at_result_iter_skip_next(&iter))
|
|
|
|
num += 1;
|
|
|
|
}
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("Got %d elements", num);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
list = g_try_new0(struct ofono_network_operator, num);
|
|
|
|
|
|
|
|
if (!list) {
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
|
2009-05-11 06:39:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
num = 0;
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
while (g_at_result_iter_next(&iter, "+COPS:")) {
|
atmodem: Parse optional PLMN parameter of AT+COPS=? result
The Infineon modem adds an optional <plmn_list> parameter after the
access technology parameter <AcT>. It is not always present, but when
present it makes the operator listing fail.
+COPS: (2,"T-Mobile D","TMO D","26201",0,0),(3,"E-Plus","E-Plus","26203",0,),(3,"Vodafone.de","Vodafone.de","26202",0,),(3,"o2 - de","o2 - de","26207",0,)
Not all networks have this parameter and maybe only the home network
has it anyway. And so far this feature seems to be Infineon specific,
but just in case, parse the parameter if present to make sure the
operator listing is available.
2010-10-21 23:00:58 +00:00
|
|
|
int status, tech, plmn;
|
2009-05-11 06:39:27 +00:00
|
|
|
const char *l, *s, *n;
|
|
|
|
gboolean have_long = FALSE;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (!g_at_result_iter_open_list(&iter))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &status))
|
|
|
|
break;
|
|
|
|
|
|
|
|
list[num].status = status;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &l))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (strlen(l) > 0) {
|
|
|
|
have_long = TRUE;
|
|
|
|
strncpy(list[num].name, l,
|
|
|
|
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &s))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (strlen(s) > 0 && !have_long)
|
|
|
|
strncpy(list[num].name, s,
|
|
|
|
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
|
|
|
|
|
|
|
list[num].name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &n))
|
|
|
|
break;
|
|
|
|
|
2009-06-12 07:02:52 +00:00
|
|
|
extract_mcc_mnc(n, list[num].mcc, list[num].mnc);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &tech))
|
|
|
|
tech = 0;
|
|
|
|
|
|
|
|
list[num].tech = tech;
|
|
|
|
|
atmodem: Parse optional PLMN parameter of AT+COPS=? result
The Infineon modem adds an optional <plmn_list> parameter after the
access technology parameter <AcT>. It is not always present, but when
present it makes the operator listing fail.
+COPS: (2,"T-Mobile D","TMO D","26201",0,0),(3,"E-Plus","E-Plus","26203",0,),(3,"Vodafone.de","Vodafone.de","26202",0,),(3,"o2 - de","o2 - de","26207",0,)
Not all networks have this parameter and maybe only the home network
has it anyway. And so far this feature seems to be Infineon specific,
but just in case, parse the parameter if present to make sure the
operator listing is available.
2010-10-21 23:00:58 +00:00
|
|
|
if (!g_at_result_iter_next_number(&iter, &plmn))
|
|
|
|
plmn = 0;
|
|
|
|
|
2009-05-11 06:39:27 +00:00
|
|
|
if (!g_at_result_iter_close_list(&iter))
|
|
|
|
break;
|
|
|
|
|
|
|
|
num += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("Got %d operators", num);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (; i < num; i++) {
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("Operator: %s, %s, %s, status: %d, %d",
|
|
|
|
list[i].name, list[i].mcc, list[i].mnc,
|
|
|
|
list[i].status, list[i].tech);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(&error, num, list, cbd->data);
|
|
|
|
|
|
|
|
g_free(list);
|
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_list_operators(struct ofono_netreg *netreg,
|
|
|
|
ofono_netreg_operator_list_cb_t cb, void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
if (g_at_chat_send(nd->chat, "AT+COPS=?", cops_prefix,
|
2009-05-11 06:39:27 +00:00
|
|
|
cops_list_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void register_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_register_cb_t cb = cbd->cb;
|
2009-05-11 06:39:27 +00:00
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
cb(&error, cbd->data);
|
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_register_auto(struct ofono_netreg *netreg,
|
|
|
|
ofono_netreg_register_cb_t cb, void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
if (g_at_chat_send(nd->chat, "AT+COPS=0", none_prefix,
|
2009-05-11 06:39:27 +00:00
|
|
|
register_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_register_manual(struct ofono_netreg *netreg,
|
2009-10-29 20:29:41 +00:00
|
|
|
const char *mcc, const char *mnc,
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_register_cb_t cb, void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
char buf[128];
|
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2010-02-05 17:59:24 +00:00
|
|
|
snprintf(buf, sizeof(buf), "AT+COPS=1,2,\"%s%s\"", mcc, mnc);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
if (g_at_chat_send(nd->chat, buf, none_prefix,
|
2009-05-11 06:39:27 +00:00
|
|
|
register_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_deregister(struct ofono_netreg *netreg,
|
|
|
|
ofono_netreg_register_cb_t cb, void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
if (g_at_chat_send(nd->chat, "AT+COPS=2", none_prefix,
|
2009-05-11 06:39:27 +00:00
|
|
|
register_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void csq_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct ofono_netreg *netreg = user_data;
|
2009-05-11 06:39:27 +00:00
|
|
|
int strength;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CSQ:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &strength))
|
|
|
|
return;
|
|
|
|
|
2010-05-20 10:53:21 +00:00
|
|
|
ofono_netreg_strength_notify(netreg,
|
|
|
|
at_util_convert_signal_strength(strength));
|
2009-09-04 04:05:18 +00:00
|
|
|
}
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-04 04:05:18 +00:00
|
|
|
static void calypso_csq_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
int strength;
|
|
|
|
GAtResultIter iter;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-04 04:05:18 +00:00
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "%CSQ:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &strength))
|
|
|
|
return;
|
|
|
|
|
2010-05-20 10:53:21 +00:00
|
|
|
ofono_netreg_strength_notify(netreg,
|
|
|
|
at_util_convert_signal_strength(strength));
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-12-07 21:09:25 +00:00
|
|
|
static void option_osigq_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
int strength;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "_OSIGQ:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &strength))
|
|
|
|
return;
|
|
|
|
|
2010-05-20 10:53:21 +00:00
|
|
|
ofono_netreg_strength_notify(netreg,
|
|
|
|
at_util_convert_signal_strength(strength));
|
2009-12-07 21:09:25 +00:00
|
|
|
}
|
|
|
|
|
2010-09-24 09:23:31 +00:00
|
|
|
static void ifx_xciev_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
int strength, ind;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+XCIEV:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &ind))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ind == 0)
|
|
|
|
strength = 0;
|
|
|
|
else if (ind == 7)
|
|
|
|
strength = 100;
|
|
|
|
else
|
|
|
|
strength = (ind * 15);
|
|
|
|
|
|
|
|
ofono_netreg_strength_notify(netreg, ind);
|
|
|
|
}
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
static void ciev_notify(GAtResult *result, gpointer user_data)
|
2010-01-25 19:25:29 +00:00
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
2010-03-26 20:26:10 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2010-01-25 19:25:29 +00:00
|
|
|
int strength, ind;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CIEV:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &ind))
|
|
|
|
return;
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
if (ind != nd->signal_index)
|
|
|
|
return;
|
2010-01-25 19:25:29 +00:00
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
if (!g_at_result_iter_next_number(&iter, &strength))
|
|
|
|
return;
|
|
|
|
|
|
|
|
strength = (strength * 100) / (nd->signal_max - nd->signal_min);
|
|
|
|
ofono_netreg_strength_notify(netreg, strength);
|
2010-01-25 19:25:29 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 11:27:04 +00:00
|
|
|
static void ctzv_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
2010-10-20 11:55:20 +00:00
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
|
|
|
int year, mon, mday, hour, min, sec;
|
2010-10-20 11:27:04 +00:00
|
|
|
const char *tz, *time;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CTZV:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_unquoted_string(&iter, &tz))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &time))
|
|
|
|
return;
|
|
|
|
|
|
|
|
DBG("tz %s time %s", tz, time);
|
2010-10-20 11:55:20 +00:00
|
|
|
|
|
|
|
if (sscanf(time, "%u/%u/%u,%u:%u:%u", &year, &mon, &mday,
|
|
|
|
&hour, &min, &sec) != 6)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nd->time.sec = sec;
|
|
|
|
nd->time.min = min;
|
|
|
|
nd->time.hour = hour;
|
|
|
|
nd->time.mday = mday;
|
|
|
|
nd->time.mon = mon;
|
|
|
|
nd->time.year = 2000 + year;
|
2010-10-20 11:27:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ctzdst_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
2010-10-20 11:55:20 +00:00
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2010-10-20 11:27:04 +00:00
|
|
|
int dst;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CTZDST:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &dst))
|
|
|
|
return;
|
|
|
|
|
|
|
|
DBG("dst %d", dst);
|
2010-10-20 11:55:20 +00:00
|
|
|
|
|
|
|
nd->time.dst = dst;
|
|
|
|
|
|
|
|
ofono_netreg_time_notify(netreg, &nd->time);
|
2010-10-20 11:27:04 +00:00
|
|
|
}
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
static void cind_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
2010-01-25 19:25:29 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_netreg_strength_cb_t cb = cbd->cb;
|
2010-03-26 20:26:10 +00:00
|
|
|
struct netreg_data *nd = cbd->user;
|
|
|
|
int index;
|
2010-01-25 19:25:29 +00:00
|
|
|
int strength;
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CIND:")) {
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
for (index = 1; index < nd->signal_index; index++)
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
2010-01-25 19:25:29 +00:00
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &strength);
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
strength = (strength * 100) / (nd->signal_max - nd->signal_min);
|
2010-01-25 19:25:29 +00:00
|
|
|
|
|
|
|
cb(&error, strength, cbd->data);
|
|
|
|
}
|
|
|
|
|
2010-06-08 00:06:36 +00:00
|
|
|
static void huawei_rssi_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
GAtResultIter iter;
|
|
|
|
int strength;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "^RSSI:"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &strength))
|
|
|
|
return;
|
|
|
|
|
|
|
|
ofono_netreg_strength_notify(netreg,
|
|
|
|
at_util_convert_signal_strength(strength));
|
|
|
|
}
|
|
|
|
|
2009-05-11 06:39:27 +00:00
|
|
|
static void csq_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_strength_cb_t cb = cbd->cb;
|
2009-05-11 06:39:27 +00:00
|
|
|
int strength;
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CSQ:")) {
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
2009-05-11 06:39:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &strength);
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("csq_cb: %d", strength);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (strength == 99)
|
|
|
|
strength = -1;
|
|
|
|
else
|
2009-09-29 18:01:26 +00:00
|
|
|
strength = (strength * 100) / 31;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
cb(&error, strength, cbd->data);
|
|
|
|
}
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
static void at_signal_strength(struct ofono_netreg *netreg,
|
|
|
|
ofono_netreg_strength_cb_t cb, void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!cbd)
|
|
|
|
goto error;
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
cbd->user = nd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we defaulted to using CIND, then keep using it,
|
|
|
|
* otherwise fall back to CSQ
|
|
|
|
*/
|
|
|
|
if (nd->signal_index > 0) {
|
2010-01-25 19:25:29 +00:00
|
|
|
if (g_at_chat_send(nd->chat, "AT+CIND?", cind_prefix,
|
2010-03-26 20:26:10 +00:00
|
|
|
cind_cb, cbd, g_free) > 0)
|
2010-01-25 19:25:29 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (g_at_chat_send(nd->chat, "AT+CSQ", csq_prefix,
|
2009-05-11 06:39:27 +00:00
|
|
|
csq_cb, cbd, g_free) > 0)
|
2010-01-25 19:25:29 +00:00
|
|
|
return;
|
|
|
|
}
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2010-10-24 19:48:56 +00:00
|
|
|
static void mbm_etzv_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
|
|
|
int year, mon, mday, hour, min, sec;
|
|
|
|
const char *tz, *time, *timestamp;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (g_at_result_iter_next(&iter, "*ETZV:") == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_string(&iter, &tz) == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_string(&iter, &time) == FALSE)
|
|
|
|
time = NULL;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_string(&iter, ×tamp) == FALSE)
|
|
|
|
timestamp = NULL;
|
|
|
|
|
|
|
|
DBG("tz %s time %s timestamp %s", tz, time, timestamp);
|
|
|
|
|
|
|
|
if (time == NULL) {
|
|
|
|
year = -1;
|
|
|
|
mon = -1;
|
|
|
|
mday = -1;
|
|
|
|
hour = -1;
|
|
|
|
min = -1;
|
|
|
|
sec = -1;
|
|
|
|
} else {
|
|
|
|
if (sscanf(time, "%u/%u/%u,%u:%u:%u", &year, &mon, &mday,
|
|
|
|
&hour, &min, &sec) != 6)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nd->time.utcoff = atoi(tz) * 15 * 60;
|
|
|
|
|
|
|
|
nd->time.sec = sec;
|
|
|
|
nd->time.min = min;
|
|
|
|
nd->time.hour = hour;
|
|
|
|
nd->time.mday = mday;
|
|
|
|
nd->time.mon = mon;
|
|
|
|
nd->time.year = year;
|
|
|
|
|
|
|
|
ofono_netreg_time_notify(netreg, &nd->time);
|
|
|
|
}
|
|
|
|
|
2010-03-29 04:30:32 +00:00
|
|
|
static void mbm_erinfo_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
2010-03-29 05:09:10 +00:00
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2010-03-29 04:30:32 +00:00
|
|
|
GAtResultIter iter;
|
|
|
|
int mode, gsm, umts;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (g_at_result_iter_next(&iter, "*ERINFO:") == FALSE)
|
|
|
|
return;
|
|
|
|
|
2010-03-29 04:58:37 +00:00
|
|
|
if (g_at_result_iter_next_number(&iter, &mode) == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_number(&iter, &gsm) == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* According to MBM the ERINFO unsolicited response does not contain
|
|
|
|
* the mode parameter, however at least the MD300 does report it. So
|
|
|
|
* we handle both 2 and 3 argument versions
|
|
|
|
*/
|
|
|
|
if (g_at_result_iter_next_number(&iter, &umts) == FALSE) {
|
|
|
|
gsm = mode;
|
|
|
|
umts = gsm;
|
|
|
|
}
|
2010-03-29 04:30:32 +00:00
|
|
|
|
|
|
|
ofono_info("network capability: GSM %d UMTS %d", gsm, umts);
|
2010-03-29 05:09:10 +00:00
|
|
|
|
|
|
|
/* Convert to tech values from 27.007 */
|
|
|
|
switch (gsm) {
|
|
|
|
case 1: /* GSM */
|
|
|
|
nd->tech = 0;
|
|
|
|
break;
|
|
|
|
case 2: /* EDGE */
|
|
|
|
nd->tech = 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nd->tech = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (umts) {
|
|
|
|
case 1: /* UMTS */
|
|
|
|
nd->tech = 2;
|
|
|
|
break;
|
|
|
|
case 2: /* UMTS + HSDPA */
|
|
|
|
nd->tech = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-03-29 04:30:32 +00:00
|
|
|
}
|
|
|
|
|
2010-06-06 20:12:37 +00:00
|
|
|
static void nw_cnti_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
//struct ofono_netreg *netreg = user_data;
|
|
|
|
//struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
|
|
|
GAtResultIter iter;
|
|
|
|
const char *tech;
|
|
|
|
int option;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (g_at_result_iter_next(&iter, "$CNTI:") == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_number(&iter, &option) == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (option != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_unquoted_string(&iter, &tech) == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ofono_info("CNTI: %s", tech);
|
|
|
|
}
|
|
|
|
|
2010-06-14 17:37:03 +00:00
|
|
|
static void option_query_tech_cb(gboolean ok,
|
|
|
|
GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct tech_query *tq = user_data;
|
|
|
|
int tech = -1;
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
tech = option_parse_tech(result);
|
|
|
|
|
|
|
|
ofono_netreg_status_notify(tq->netreg,
|
|
|
|
tq->status, tq->lac, tq->ci, tech);
|
|
|
|
}
|
|
|
|
|
2009-05-11 06:39:27 +00:00
|
|
|
static void creg_notify(GAtResult *result, gpointer user_data)
|
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct ofono_netreg *netreg = user_data;
|
2009-12-09 18:50:52 +00:00
|
|
|
int status, lac, ci, tech;
|
2010-01-18 14:30:13 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2010-06-14 17:37:03 +00:00
|
|
|
struct tech_query *tq;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-12-09 18:50:52 +00:00
|
|
|
if (at_util_parse_reg_unsolicited(result, "+CREG:", &status,
|
2010-01-18 14:30:13 +00:00
|
|
|
&lac, &ci, &tech, nd->vendor) == FALSE)
|
2009-05-11 06:39:27 +00:00
|
|
|
return;
|
|
|
|
|
2010-06-25 01:51:59 +00:00
|
|
|
if (status != 1 && status != 5)
|
|
|
|
goto notify;
|
|
|
|
|
2010-06-14 17:37:03 +00:00
|
|
|
switch (nd->vendor) {
|
|
|
|
case OFONO_VENDOR_OPTION_HSO:
|
|
|
|
tq = g_new0(struct tech_query, 1);
|
|
|
|
if (!tq)
|
|
|
|
break;
|
|
|
|
|
|
|
|
tq->status = status;
|
|
|
|
tq->lac = lac;
|
|
|
|
tq->ci = ci;
|
|
|
|
tq->netreg = netreg;
|
|
|
|
|
|
|
|
if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?",
|
2010-06-14 17:45:04 +00:00
|
|
|
option_tech_prefix,
|
|
|
|
option_query_tech_cb, tq, g_free) > 0)
|
2010-06-14 17:37:03 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(tq);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-03-29 05:18:04 +00:00
|
|
|
if ((status == 1 || status == 5) && tech == -1)
|
2010-03-29 05:09:10 +00:00
|
|
|
tech = nd->tech;
|
|
|
|
|
2010-06-25 01:51:59 +00:00
|
|
|
notify:
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_status_notify(netreg, status, lac, ci, tech);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2010-03-26 20:26:10 +00:00
|
|
|
static void cind_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
|
|
|
GAtResultIter iter;
|
|
|
|
const char *str;
|
|
|
|
int index;
|
|
|
|
int min, max;
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CIND:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
index = 1;
|
|
|
|
|
|
|
|
while (g_at_result_iter_open_list(&iter)) {
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &str))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_open_list(&iter))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
while (g_at_result_iter_next_range(&iter, &min, &max))
|
|
|
|
;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_close_list(&iter))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_close_list(&iter))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (g_str_equal("signal", str) == TRUE) {
|
|
|
|
nd->signal_index = index;
|
|
|
|
nd->signal_min = min;
|
|
|
|
nd->signal_max = max;
|
|
|
|
}
|
|
|
|
|
|
|
|
index += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nd->signal_index == 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_chat_send(nd->chat, "AT+CMER=3,0,0,1", NULL,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
g_at_chat_register(nd->chat, "+CIEV:",
|
|
|
|
ciev_notify, FALSE, netreg, NULL);
|
2010-05-20 04:33:17 +00:00
|
|
|
g_at_chat_register(nd->chat, "+CREG:",
|
|
|
|
creg_notify, FALSE, netreg, NULL);
|
2010-03-26 20:26:10 +00:00
|
|
|
|
|
|
|
ofono_netreg_register(netreg);
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
ofono_error("This driver is not setup with Signal Strength reporting"
|
|
|
|
" via CIND indications, please write proper netreg"
|
|
|
|
" handling for this device");
|
|
|
|
|
|
|
|
ofono_netreg_remove(netreg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
ofono_error("Unable to initialize Network Registration");
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_remove(netreg);
|
2009-05-11 06:39:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-07 18:27:36 +00:00
|
|
|
switch (nd->vendor) {
|
2010-03-26 20:33:19 +00:00
|
|
|
case OFONO_VENDOR_PHONESIM:
|
|
|
|
g_at_chat_register(nd->chat, "+CSQ:",
|
|
|
|
csq_notify, FALSE, netreg, NULL);
|
|
|
|
break;
|
2009-12-07 18:27:36 +00:00
|
|
|
case OFONO_VENDOR_CALYPSO:
|
|
|
|
g_at_chat_send(nd->chat, "AT%CSQ=1", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
2009-09-04 04:05:18 +00:00
|
|
|
g_at_chat_register(nd->chat, "%CSQ:", calypso_csq_notify,
|
|
|
|
FALSE, netreg, NULL);
|
2009-12-07 21:09:25 +00:00
|
|
|
break;
|
|
|
|
case OFONO_VENDOR_OPTION_HSO:
|
2009-12-07 23:14:57 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT_OSSYS=1", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
2009-12-07 21:09:25 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT_OSQI=1", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
g_at_chat_register(nd->chat, "_OSIGQ:", option_osigq_notify,
|
|
|
|
FALSE, netreg, NULL);
|
|
|
|
|
2009-12-10 01:55:53 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT_OSSYS?", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
g_at_chat_send(nd->chat, "AT_OSQI?", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
2010-10-25 00:03:00 +00:00
|
|
|
|
|
|
|
g_at_chat_send(nd->chat, "AT+CTZR=1", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
2010-01-25 19:25:29 +00:00
|
|
|
break;
|
2010-03-29 04:30:32 +00:00
|
|
|
case OFONO_VENDOR_MBM:
|
2010-10-24 19:48:56 +00:00
|
|
|
/* Enable network registration updates */
|
2010-08-20 14:53:07 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT*E2REG=1", none_prefix,
|
2010-10-24 19:48:56 +00:00
|
|
|
NULL, NULL, NULL);
|
2010-08-20 14:53:07 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT*EREG=2", none_prefix,
|
2010-10-24 19:48:56 +00:00
|
|
|
NULL, NULL, NULL);
|
2010-08-20 14:53:07 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT*EPSB=1", none_prefix,
|
2010-10-24 19:48:56 +00:00
|
|
|
NULL, NULL, NULL);
|
2010-08-20 14:50:42 +00:00
|
|
|
|
2010-10-24 19:48:56 +00:00
|
|
|
/* Register for network technology updates */
|
2010-03-29 04:30:32 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT*ERINFO=1", none_prefix,
|
2010-10-24 19:48:56 +00:00
|
|
|
NULL, NULL, NULL);
|
2010-03-29 04:30:32 +00:00
|
|
|
g_at_chat_register(nd->chat, "*ERINFO:", mbm_erinfo_notify,
|
2010-10-24 19:48:56 +00:00
|
|
|
FALSE, netreg, NULL);
|
|
|
|
|
|
|
|
/* Register for network time update reports */
|
|
|
|
g_at_chat_register(nd->chat, "*ETZV:", mbm_etzv_notify,
|
|
|
|
FALSE, netreg, NULL);
|
|
|
|
g_at_chat_send(nd->chat, "AT*ETZR=2", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
2010-03-29 04:30:32 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT+CIND=?", cind_prefix,
|
2010-10-24 19:48:56 +00:00
|
|
|
cind_support_cb, netreg, NULL);
|
2010-05-20 04:33:17 +00:00
|
|
|
return;
|
2010-06-06 20:12:37 +00:00
|
|
|
case OFONO_VENDOR_NOVATEL:
|
|
|
|
/*
|
|
|
|
* Novatel doesn't support unsolicited notifications
|
|
|
|
* of technology changes, but register a handle for
|
|
|
|
* CNTI so we get notified by any query.
|
|
|
|
*/
|
|
|
|
g_at_chat_register(nd->chat, "$CNTI:", nw_cnti_notify,
|
|
|
|
FALSE, netreg, NULL);
|
|
|
|
break;
|
2010-05-20 10:53:28 +00:00
|
|
|
case OFONO_VENDOR_HUAWEI:
|
2010-06-08 00:06:36 +00:00
|
|
|
g_at_chat_register(nd->chat, "^RSSI:", huawei_rssi_notify,
|
|
|
|
FALSE, netreg, NULL);
|
2010-03-29 04:30:32 +00:00
|
|
|
break;
|
2010-09-24 09:23:31 +00:00
|
|
|
case OFONO_VENDOR_IFX:
|
2010-10-20 11:27:04 +00:00
|
|
|
/* Register for specific signal strength reports */
|
2010-09-24 09:23:31 +00:00
|
|
|
g_at_chat_register(nd->chat, "+XCIEV:", ifx_xciev_notify,
|
2010-10-20 11:27:04 +00:00
|
|
|
FALSE, netreg, NULL);
|
|
|
|
g_at_chat_send(nd->chat, "AT+XMER=1", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
/* Register for network time update reports */
|
|
|
|
g_at_chat_register(nd->chat, "+CTZV:", ctzv_notify,
|
|
|
|
FALSE, netreg, NULL);
|
|
|
|
g_at_chat_register(nd->chat, "+CTZDST:", ctzdst_notify,
|
|
|
|
FALSE, netreg, NULL);
|
|
|
|
g_at_chat_send(nd->chat, "AT+CTZR=1", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
2010-09-24 09:23:31 +00:00
|
|
|
break;
|
2010-08-16 13:14:17 +00:00
|
|
|
case OFONO_VENDOR_ZTE:
|
2010-08-20 00:24:53 +00:00
|
|
|
case OFONO_VENDOR_NOKIA:
|
2010-08-16 13:14:17 +00:00
|
|
|
/* Signal strength reporting via CIND is not supported */
|
|
|
|
break;
|
2009-12-07 18:27:36 +00:00
|
|
|
default:
|
2010-03-26 20:26:10 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT+CIND=?", cind_prefix,
|
|
|
|
cind_support_cb, netreg, NULL);
|
2010-05-20 04:33:17 +00:00
|
|
|
return;
|
2009-12-07 18:27:36 +00:00
|
|
|
}
|
2010-05-20 04:33:17 +00:00
|
|
|
|
|
|
|
g_at_chat_register(nd->chat, "+CREG:",
|
|
|
|
creg_notify, FALSE, netreg, NULL);
|
|
|
|
ofono_netreg_register(netreg);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-11-10 06:29:56 +00:00
|
|
|
static void at_creg_test_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct ofono_netreg *netreg = user_data;
|
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
|
|
|
gint range[2];
|
|
|
|
GAtResultIter iter;
|
|
|
|
int creg1 = 0;
|
|
|
|
int creg2 = 0;
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CREG:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_open_list(&iter))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
while (g_at_result_iter_next_range(&iter, &range[0], &range[1])) {
|
|
|
|
if (1 >= range[0] && 1 <= range[1])
|
|
|
|
creg1 = 1;
|
|
|
|
if (2 >= range[0] && 2 <= range[1])
|
|
|
|
creg2 = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_close_list(&iter);
|
|
|
|
|
|
|
|
if (creg2) {
|
|
|
|
g_at_chat_send(nd->chat, "AT+CREG=2", none_prefix,
|
2010-03-26 20:26:10 +00:00
|
|
|
at_creg_set_cb, netreg, NULL);
|
2009-11-10 06:29:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (creg1) {
|
|
|
|
g_at_chat_send(nd->chat, "AT+CREG=1", none_prefix,
|
2010-03-26 20:26:10 +00:00
|
|
|
at_creg_set_cb, netreg, NULL);
|
2009-11-10 06:29:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
ofono_error("Unable to initialize Network Registration");
|
|
|
|
ofono_netreg_remove(netreg);
|
|
|
|
}
|
|
|
|
|
2009-09-02 02:39:02 +00:00
|
|
|
static int at_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
|
|
|
void *data)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-09-01 22:22:26 +00:00
|
|
|
GAtChat *chat = data;
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd;
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
nd = g_new0(struct netreg_data, 1);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2010-08-12 21:40:40 +00:00
|
|
|
nd->chat = g_at_chat_clone(chat);
|
2009-09-04 04:05:18 +00:00
|
|
|
nd->vendor = vendor;
|
2010-03-29 05:09:10 +00:00
|
|
|
nd->tech = -1;
|
2010-10-20 11:55:20 +00:00
|
|
|
nd->time.sec = -1;
|
|
|
|
nd->time.min = -1;
|
|
|
|
nd->time.hour = -1;
|
|
|
|
nd->time.mday = -1;
|
|
|
|
nd->time.mon = -1;
|
|
|
|
nd->time.year = -1;
|
|
|
|
nd->time.dst = 0;
|
|
|
|
nd->time.utcoff = 0;
|
2009-08-19 17:10:44 +00:00
|
|
|
ofono_netreg_set_data(netreg, nd);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2010-08-12 21:40:40 +00:00
|
|
|
g_at_chat_send(nd->chat, "AT+CREG=?", creg_prefix,
|
2009-11-10 06:29:56 +00:00
|
|
|
at_creg_test_cb, netreg, NULL);
|
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
return 0;
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-09-02 03:27:08 +00:00
|
|
|
static void at_netreg_remove(struct ofono_netreg *netreg)
|
2009-05-11 06:39:27 +00:00
|
|
|
{
|
2009-08-19 17:10:44 +00:00
|
|
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-11-11 21:59:01 +00:00
|
|
|
ofono_netreg_set_data(netreg, NULL);
|
|
|
|
|
2010-08-12 21:40:40 +00:00
|
|
|
g_at_chat_unref(nd->chat);
|
2009-08-19 17:10:44 +00:00
|
|
|
g_free(nd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ofono_netreg_driver driver = {
|
2009-09-02 03:33:05 +00:00
|
|
|
.name = "atmodem",
|
2009-08-19 17:10:44 +00:00
|
|
|
.probe = at_netreg_probe,
|
|
|
|
.remove = at_netreg_remove,
|
2010-06-08 00:06:57 +00:00
|
|
|
.registration_status = at_registration_status,
|
|
|
|
.current_operator = at_current_operator,
|
2009-08-19 17:10:44 +00:00
|
|
|
.list_operators = at_list_operators,
|
|
|
|
.register_auto = at_register_auto,
|
|
|
|
.register_manual = at_register_manual,
|
|
|
|
.deregister = at_deregister,
|
|
|
|
.strength = at_signal_strength,
|
|
|
|
};
|
2009-06-02 19:39:27 +00:00
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
void at_netreg_init()
|
|
|
|
{
|
|
|
|
ofono_netreg_driver_register(&driver);
|
|
|
|
}
|
2009-05-11 06:39:27 +00:00
|
|
|
|
2009-08-19 17:10:44 +00:00
|
|
|
void at_netreg_exit()
|
|
|
|
{
|
|
|
|
ofono_netreg_driver_unregister(&driver);
|
2009-05-11 06:39:27 +00:00
|
|
|
}
|