Gemalto: support for voicecall
v2 cover Gemalto: support for voicecall
This series of patches adds a vendor-specific voicecall atom for gemaltomodem, and then adds it to the plugin, along with all other call-related atoms.
related to the first version submitted for RFC, it integrates the comments from Denis, and only uses the required URCs, leaving out for example RING.
It also fixes a problem with the first version when the SLCC URC was parsed exactly like the AT+CLCC command: now it takes into account that the URC function is called for each line, and not for all together, while for CLCC all lines are parsed at once.
Giacinto Cifelli (2):
Gemalto: voicecall atom
plugins/gemalto: added voice support
Makefile.am | 3 +- drivers/gemaltomodem/gemaltomodem.c | 2 + drivers/gemaltomodem/gemaltomodem.h | 2 + drivers/gemaltomodem/voicecall.c | 751 ++++++++++++++++++++++++++++ plugins/gemalto.c | 11 + 5 files changed, 768 insertions(+), 1 deletion(-) create mode 100644 drivers/gemaltomodem/voicecall.c
Signature · 1 line
2.17.1
PATCH v2 1/2 Gemalto: voicecall atom
Added voicecall atom specific for Gemalto modems.
This atom uses the URC ^SLCC to monitor the call status, as well as incoming calls.
--- Makefile.am | 3 +- drivers/gemaltomodem/gemaltomodem.c | 2 + drivers/gemaltomodem/gemaltomodem.h | 2 + drivers/gemaltomodem/voicecall.c | 751 ++++++++++++++++++++++++++++ 4 files changed, 757 insertions(+), 1 deletion(-) create mode 100644 drivers/gemaltomodem/voicecall.c
Makefile.am +2 -1
@@ -397,7 +397,8 @@ builtin_modules += gemaltomodem builtin_sources += drivers/atmodem/atutil.h \ drivers/gemaltomodem/gemaltomodem.h \ drivers/gemaltomodem/gemaltomodem.c \ - drivers/gemaltomodem/location-reporting.c + drivers/gemaltomodem/location-reporting.c \ + drivers/gemaltomodem/voicecall.c builtin_modules += xmm7modem builtin_sources += drivers/atmodem/atutil.h \
drivers/gemaltomodem/gemaltomodem.c +2 -0
@@ -35,6 +35,7 @@static int gemaltomodem_init (void ) {gemalto_location_reporting_init (); +gemalto_voicecall_init ();return 0 ; }
@@ -42,6 +43,7 @@ static int gemaltomodem_init(void)static void gemaltomodem_exit (void ) {gemalto_location_reporting_exit (); +gemalto_voicecall_exit (); } OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
drivers/gemaltomodem/gemaltomodem.h +2 -0
@@ -23,3 +23,5 @@extern void gemalto_location_reporting_init ();extern void gemalto_location_reporting_exit (); +extern void gemalto_voicecall_init (); +extern void gemalto_voicecall_exit ();
drivers/gemaltomodem/voicecall.c new file +751 -0
751 lines not on this page · raw message
Signature · 1 line
2.17.1
Re: [PATCH v2 1/2] Gemalto: voicecall atom
Hi Giacinto,
Some, mostly trivial, comments below.
/Jonas
Quoted 38 lines · Giacinto Cifelli
Added voicecall atom specific for Gemalto modems.
This atom uses the URC ^SLCC to monitor the call status, as well as incoming calls.--- Makefile.am | 3 +- drivers/gemaltomodem/gemaltomodem.c | 2 + drivers/gemaltomodem/gemaltomodem.h | 2 + drivers/gemaltomodem/voicecall.c | 751 ++++++++++++++++++++++++++++ 4 files changed, 757 insertions(+), 1 deletion(-)create mode 100644
drivers/gemaltomodem/voicecall.cMakefile.am +2
-1@@ -397,7 +397,8 @@ builtin_modules += gemaltomodem builtin_sources += drivers/atmodem/atutil.h \ drivers/gemaltomodem/gemaltomodem.h \ drivers/gemaltomodem/gemaltomodem.c \ - drivers/gemaltomodem/location-reporting.c + drivers/gemaltomodem/location-reporting.c \ + drivers/gemaltomodem/voicecall.c builtin_modules += xmm7modem builtin_sources += drivers/atmodem/atutil.h \drivers/gemaltomodem/gemaltomodem.c +1
-0@@ -35,6 +35,7 @@static int gemaltomodem_init (void ) {gemalto_location_reporting_init (); +gemalto_voicecall_init ();return 0 ; }
drivers/gemaltomodem/gemaltomodem.c static int gemaltomodem_init(void) · line 47
Quoted 5 lines
drivers/gemaltomodem/gemaltomodem.c +1
-0@@ -42,6 +43,7 @@ static int gemaltomodem_init(void)static void gemaltomodem_exit (void ) {gemalto_location_reporting_exit (); +gemalto_voicecall_exit (); }
init and exit functions usually reverse the order of the functions so that last initialized is first to be cleaned up. Presumably not relevant here but it's good form.
Quoted 108 lines
drivers/gemaltomodem/gemaltomodem.c +0
-0OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,drivers/gemaltomodem/gemaltomodem.h +2
-0@@ -23,3 +23,5 @@extern void gemalto_location_reporting_init ();extern void gemalto_location_reporting_exit (); +extern void gemalto_voicecall_init (); +extern void gemalto_voicecall_exit ();drivers/gemaltomodem/voicecall.c new file +90
-0@@ -0,0 +1,751 @@ +/* +* +* oFono - Open Source Telephony +* +* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. +* Copyright (C) 2018 Gemalto M2M +* +* 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 <errno.h> + +#include <glib.h> + +#include <ofono/log.h> +#include <ofono/modem.h> +#include <ofono/voicecall.h> + +#include "gatchat.h" +#include "gatresult.h" + +#include "common.h" + +#include "gemaltomodem.h" + +static const char *clcc_prefix[] = {"+CLCC:" ,NULL }; +static const char *none_prefix[] = {NULL }; + +/* According to 27.007 COLP is an intermediate status for ATD */ +static const char *atd_prefix[] = {"+COLP:" ,NULL }; + +#define FLAG_NEED_CLIP 1 + +struct voicecall_data { +GAtChat *chat; +GSList *calls; +unsigned int local_release; +unsigned int vendor; +unsigned char flags; +GSList *new_calls; +}; + +struct release_id_req { +struct ofono_voicecall *vc; +ofono_voicecall_cb_t cb; +void *data; +int id; +}; + +struct change_state_req { +struct ofono_voicecall *vc; +ofono_voicecall_cb_t cb; +void *data; +int affected_types; +}; + +static void generic_cb (gboolean ok,GAtResult *result,gpointer user_data) +{ +struct change_state_req *req = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (req->vc); +struct ofono_error error; + +decode_at_error (&error,g_at_result_final_response (result)); + +if (ok && req->affected_types) { +GSList *l; +struct ofono_call *call; + +for (l = vd->calls; l; l = l->next) { + call = l->data;
drivers/gemaltomodem/voicecall.c line 100
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +10
-0+ +if (req->affected_types & (1 << call->status)) + vd->local_release |= (1 << call->id); + } + } + + req->cb (&error, req->data); +} + +static void gemalto_template(const char *cmd, struct ofono_voicecall *vc,
gemalto_template is not a great name. gemalto_common, gemalto_call_common...???
drivers/gemaltomodem/voicecall.c line 105
Quoted 5 lines
drivers/gemaltomodem/voicecall.c new file +5
-0+ GAtResultFunc result_cb, unsigned int affected_types, + ofono_voicecall_cb_t cb, void *data) +{ + struct voicecall_data *vd = ofono_voicecall_get_data(vc); + struct change_state_req *req = g_try_new0(struct change_state_req, 1);
g_new0 is sufficient.
drivers/gemaltomodem/voicecall.c line 108
Quoted 3 lines
drivers/gemaltomodem/voicecall.c new file +3
-0+ +if (req ==NULL ) + goto error;
Linux will never fail the allocation so skip the error check.
Quoted 152 lines
drivers/gemaltomodem/voicecall.c new file +152
-0+ + req->vc = vc; + req->cb = cb; + req->data = data; + req->affected_types = affected_types; + +if (g_at_chat_send (vd->chat, cmd, none_prefix, + result_cb, req, g_free) >0 ) +return ; + +error: +g_free (req); + +CALLBACK_WITH_FAILURE (cb, data); +} + +static void gemalto_answer (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +gemalto_template ("ATA" , vc, generic_cb,0 , cb, data); +} + +static void gemalto_hangup_all (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_INCOMING ) | + (1 <<CALL_STATUS_DIALING ) | + (1 <<CALL_STATUS_ALERTING ) | + (1 <<CALL_STATUS_WAITING ) | + (1 <<CALL_STATUS_HELD ) | + (1 <<CALL_STATUS_ACTIVE ); + +/* Hangup all calls */ +gemalto_template ("AT+CHUP" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_hangup (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ); + +/* Hangup current active call */ +gemalto_template ("AT+CHLD=1" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_hold_all_active (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ); +gemalto_template ("AT+CHLD=2" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_release_all_held (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_INCOMING ) | + (1 <<CALL_STATUS_WAITING ); + +gemalto_template ("AT+CHLD=0" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_set_udub (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_INCOMING ) | + (1 <<CALL_STATUS_WAITING ); + +gemalto_template ("AT+CHLD=0" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_release_all_active (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ); + +gemalto_template ("AT+CHLD=1" , vc, generic_cb, affected, cb, data); +} + +static void release_id_cb (gboolean ok,GAtResult *result, +gpointer user_data) +{ +struct release_id_req *req = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (req->vc); +struct ofono_error error; + +decode_at_error (&error,g_at_result_final_response (result)); + +if (ok) + vd->local_release =1 << req->id; + + req->cb (&error, req->data); +} + +static void gemalto_release_specific (struct ofono_voicecall *vc,int id, +ofono_voicecall_cb_t cb,void *data) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); + struct release_id_req *req = g_try_new0(struct release_id_req, 1); +char buf[32 ]; + +if (req ==NULL ) + goto error; + + req->vc = vc; + req->cb = cb; + req->data = data; + req->id = id; + +snprintf (buf,sizeof (buf),"AT+CHLD=1%d" , id); + +if (g_at_chat_send (vd->chat, buf, none_prefix, + release_id_cb, req, g_free) >0 ) +return ; + +error: +g_free (req); + +CALLBACK_WITH_FAILURE (cb, data); +} + +static void gemalto_private_chat (struct ofono_voicecall *vc,int id, +ofono_voicecall_cb_t cb,void *data) +{ +char buf[32 ]; + +snprintf (buf,sizeof (buf),"AT+CHLD=2%d" , id); +gemalto_template (buf, vc, generic_cb,0 , cb, data); +} + +static void gemalto_create_multiparty (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +gemalto_template ("AT+CHLD=3" , vc, generic_cb,0 , cb, data); +} + +static void gemalto_transfer (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +/* Held & Active */ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ) | + (1 <<CALL_STATUS_HELD ); + +/* Transfer can puts held & active calls together and disconnects +* from both. However, some networks support transferring of +* dialing/ringing calls as well. +*/ + affected |= (1 <<CALL_STATUS_DIALING ) | + (1 <<CALL_STATUS_ALERTING ); + +gemalto_template ("AT+CHLD=4" , vc, generic_cb, affected, cb, data); +} +
drivers/gemaltomodem/voicecall.c line 270
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +10
-0+static void gemalto_send_dtmf (struct ofono_voicecall *vc,const char *dtmf, +ofono_voicecall_cb_t cb,void *data) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +int len =strlen (dtmf); +int s; +int i; +char *buf; +struct ofono_modem *modem =ofono_voicecall_get_modem (vc); +int use_quotes =ofono_modem_get_integer (modem,"GemaltoVtsQuotes" );
GemaltoVtsQuotes is set unconditionally in patch 2/2. Was that your intention? If so, you don't need this variable...
drivers/gemaltomodem/voicecall.c line 273
Quoted 3 lines
drivers/gemaltomodem/voicecall.c new file +3
-0+ +/* strlen("+VTS=\"T\";") = 9 + initial AT + null */ + buf =g_try_new (char, len *9 +3 );
g_new
drivers/gemaltomodem/voicecall.c line 278
Quoted 5 lines
drivers/gemaltomodem/voicecall.c new file +5
-0+ +if (buf ==NULL ) { +CALLBACK_WITH_FAILURE (cb, data); +return ; + }
Linux won't fail the allocation.
drivers/gemaltomodem/voicecall.c line 284
Quoted 6 lines
drivers/gemaltomodem/voicecall.c new file +6
-0+ +if (use_quotes) + s =sprintf (buf,"AT+VTS=\"%c\"" , dtmf[0 ]); +else + s =sprintf (buf,"AT+VTS=%c" , dtmf[0 ]); +
As per above, use_quotes is always 1...
Quoted 13 lines
drivers/gemaltomodem/voicecall.c new file +13
-0+for (i =1 ; i < len; i++) { + +if (use_quotes) + s +=sprintf (buf + s,";+VTS=\"%c\"" , dtmf[i]); +else + s +=sprintf (buf + s,";+VTS=%c" , dtmf[i]); + } + +g_at_chat_send (vd->chat, buf,NULL ,NULL ,NULL ,NULL ); +g_free (buf); +} + +static struct ofono_call *create_call(struct ofono_voicecall *vc, int type,
drivers/gemaltomodem/voicecall.c line 307
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +10
-0+ int direction, int status, + const char *num, int num_type, int clip) +{ + struct voicecall_data *d = ofono_voicecall_get_data(vc); +struct ofono_call *call; + +/* Generate a call structure for the waiting call */ + call = g_try_new(struct ofono_call, 1); +if (call ==NULL ) +return NULL ;
g_new... won't fail.
Quoted 95 lines
drivers/gemaltomodem/voicecall.c new file +95
-0+ +ofono_call_init (call); + + call->id =ofono_voicecall_get_next_callid (vc); + call->type = type; + call->direction = direction; + call->status = status; + +if (clip !=2 ) { +strncpy (call->phone_number.number, num, +OFONO_MAX_PHONE_NUMBER_LENGTH ); + call->phone_number.type = num_type; + } + + call->clip_validity = clip; + call->cnap_validity =CNAP_VALIDITY_NOT_AVAILABLE ; + + d->calls =g_slist_insert_sorted (d->calls, call, at_util_call_compare); + +return call; +} + +static void atd_cb (gboolean ok,GAtResult *result,gpointer user_data) +{ +struct cb_data *cbd = user_data; +struct ofono_voicecall *vc = cbd->user; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +ofono_voicecall_cb_t cb = cbd->cb; +GAtResultIter iter; +const char *num; +int type =128 ; +int validity =2 ; +struct ofono_error error; +struct ofono_call *call; +GSList *l; + +decode_at_error (&error,g_at_result_final_response (result)); + +if (!ok) + goto out; + +/* On a success, make sure to put all active calls on hold */ +for (l = vd->calls; l; l = l->next) { + call = l->data; + +if (call->status !=CALL_STATUS_ACTIVE ) +continue ; + + call->status =CALL_STATUS_HELD ; +ofono_voicecall_notify (vc, call); + } + +g_at_result_iter_init (&iter, result); + +if (g_at_result_iter_next (&iter,"+COLP:" )) { +g_at_result_iter_next_string (&iter, &num); +g_at_result_iter_next_number (&iter, &type); + +if (strlen (num) >0 ) + validity =0 ; +else + validity =2 ; + +DBG ("colp_notify: %s %d %d" , num, type, validity); + } + +/* Generate a voice call that was just dialed, we guess the ID */ + call =create_call (vc,0 ,0 ,CALL_STATUS_DIALING , num, type, validity); +if (call ==NULL ) { +ofono_error ("Unable to malloc, call tracking will fail!" ); +return ; + } + +/* oFono core will generate a call with the dialed number +* inside its dial callback. Unless we got COLP information +* we do not need to communicate that a call is being +* dialed +*/ +if (validity !=2 ) +ofono_voicecall_notify (vc, call); + +out: +cb (&error, cbd->data); +} + +static void gemalto_dial (struct ofono_voicecall *vc, +const struct ofono_phone_number *ph, +enum ofono_clir_option clir,ofono_voicecall_cb_t cb, +void *data) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +struct cb_data *cbd =cb_data_new (cb, data); +char buf[256 ]; + + cbd->user = vc;
drivers/gemaltomodem/voicecall.c line 411
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +9
-0+ +if (ph->type ==145 ) +snprintf (buf,sizeof (buf),"ATD+%s" , ph->number); +else +snprintf (buf,sizeof (buf),"ATD%s" , ph->number); + +switch (clir) { +case OFONO_CLIR_OPTION_INVOCATION : +strcat (buf,"I" );
I'm a bit allergic to snprintf followed by strcat... you already know the length of buf (at least, if you grab the return value from snprintf), so use snprintf again and save having to do a search for \0 like strcat does.
Quoted 340 lines
drivers/gemaltomodem/voicecall.c new file +340
-0+break ; +case OFONO_CLIR_OPTION_SUPPRESSION : +strcat (buf,"i" ); +break ; +default : +break ; + } + +strcat (buf,";" ); + +if (g_at_chat_send (vd->chat, buf, atd_prefix, + atd_cb, cbd, g_free) >0 ) +return ; + +g_free (cbd); + +CALLBACK_WITH_FAILURE (cb, data); +} + +static gboolean gemalto_parse_slcc (GAtResult *result,GSList **l, +unsigned int *ret_mpty_ids) +{ +GAtResultIter iter; +int id, dir, status, type; +ofono_bool_t mpty; +struct ofono_call *call; +unsigned int mpty_ids =0 ; +gboolean last = TRUE; +const char *str ="" ; +int number_type =129 ; + +g_at_result_iter_init (&iter, result); + +g_at_result_iter_next (&iter,"^SLCC:" ); + +if (!g_at_result_iter_next_number (&iter, &id)) + goto finish; + + last = FALSE; + +if (id ==0 ) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &dir)) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &status)) + goto finish; + +if (status >5 ) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &type)) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &mpty)) + goto finish; + +/* skip 'Reserved=0' parameter, only difference from CLCC */ +if (!g_at_result_iter_skip_next (&iter)) + goto finish; + +if (g_at_result_iter_next_string (&iter, &str)) +g_at_result_iter_next_number (&iter, &number_type); + + call = g_new0(struct ofono_call, 1); +ofono_call_init (call); + call->id = id; + call->direction = dir; + call->status = status; + call->type = type; +strncpy (call->phone_number.number, str, +OFONO_MAX_PHONE_NUMBER_LENGTH ); + call->phone_number.type = number_type; + +if (strlen (call->phone_number.number) >0 ) + call->clip_validity =0 ; +else + call->clip_validity =2 ; + + *l =g_slist_insert_sorted (*l, call, at_util_call_compare); + +if (mpty) + mpty_ids |=1 << id; + +if (ret_mpty_ids) + *ret_mpty_ids = mpty_ids; + +finish: +return last; +} + +static void clcc_cb (gboolean ok,GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +GSList *l; + +if (!ok) +return ; + + vd->calls =at_util_parse_clcc (result,NULL ); + +for (l = vd->calls; l; l = l->next) +ofono_voicecall_notify (vc, l->data); +} + +/* +* ^SLCC, except for one RFU parameter (see above in the parsing), is identical +* to +CLCC, but as URC it is parsed line by line, and the last line is +* indicated by an empty "^SLCC:" (equivalent to the "OK" for CLCC). +*/ +static void slcc_notify (GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +GSList *n, *o; +struct ofono_call *nc, *oc; + +gboolean last =gemalto_parse_slcc (result, &vd->new_calls,NULL ); + +if (!last) +return ; + + n = vd->new_calls; + o = vd->calls; + +while (n || o) { + + nc = n ? n->data :NULL ; + oc = o ? o->data :NULL ; + +if (oc && (nc ==NULL || (nc->id > oc->id))) { +enum ofono_disconnect_reason reason; + +if (vd->local_release & (1 << oc->id)) + reason =OFONO_DISCONNECT_REASON_LOCAL_HANGUP ; +else + reason =OFONO_DISCONNECT_REASON_REMOTE_HANGUP ; + +if (!oc->type) +ofono_voicecall_disconnected (vc, oc->id, + reason,NULL ); + + o = o->next; + }else if (nc && (oc ==NULL || (nc->id < oc->id))) { + +if (nc->type ==0 )/* new call, signal it */ +ofono_voicecall_notify (vc, nc); + + n = n->next; + }else { +/* +* Always use the clip_validity from old call +* the only place this is truly told to us is +* in the CLIP notify, the rest are fudged +* anyway. Useful when RING, CLIP is used, +* and we're forced to use CLCC/SLCC and clip_validity +* is 1 +*/ +if (oc->clip_validity ==1 ) + nc->clip_validity = oc->clip_validity; + +/* +* CNAP doesn't arrive as part of CLCC, always +* re-use from the old call +*/ +strncpy (nc->name, oc->name, +OFONO_MAX_CALLER_NAME_LENGTH ); + nc->name[OFONO_MAX_CALLER_NAME_LENGTH ] ='\0' ; + nc->cnap_validity = oc->cnap_validity; + +/* +* CDIP doesn't arrive as part of CLCC, always +* re-use from the old call +*/ +memcpy (&nc->called_number, &oc->called_number, +sizeof (oc->called_number)); + +/* +* If the CLIP is not provided and the CLIP never +* arrives, or RING is used, then signal the call +* here +*/ +if (nc->status ==CALL_STATUS_INCOMING && + (vd->flags &FLAG_NEED_CLIP )) { +if (nc->type ==0 ) +ofono_voicecall_notify (vc, nc); + + vd->flags &= ~FLAG_NEED_CLIP ; + }else if (memcmp (nc, oc,sizeof (*nc)) && nc->type ==0 ) +ofono_voicecall_notify (vc, nc); + + n = n->next; + o = o->next; + } + } + +g_slist_free_full (vd->calls, g_free); + + vd->calls = vd->new_calls; + vd->new_calls =NULL ; + + vd->local_release =0 ; +} + +static void cssi_notify (GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +GAtResultIter iter; +int code, index; + +g_at_result_iter_init (&iter, result); + +if (!g_at_result_iter_next (&iter,"+CSSI:" )) +return ; + +if (!g_at_result_iter_next_number (&iter, &code)) +return ; + +if (!g_at_result_iter_next_number (&iter, &index)) + index =0 ; + +ofono_voicecall_ssn_mo_notify (vc,0 , code, index); +} + +static void cssu_notify (GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +GAtResultIter iter; +int code; +int index; +const char *num; +struct ofono_phone_number ph; + + ph.number[0 ] ='\0' ; + ph.type =129 ; + +g_at_result_iter_init (&iter, result); + +if (!g_at_result_iter_next (&iter,"+CSSU:" )) +return ; + +if (!g_at_result_iter_next_number (&iter, &code)) +return ; + +if (!g_at_result_iter_next_number_default (&iter,-1 , &index)) + goto out; + +if (!g_at_result_iter_next_string (&iter, &num)) + goto out; + +strncpy (ph.number, num,OFONO_MAX_PHONE_NUMBER_LENGTH ); + +if (!g_at_result_iter_next_number (&iter, &ph.type)) +return ; + +out: +ofono_voicecall_ssn_mt_notify (vc,0 , code, index, &ph); +} + +static void gemalto_voicecall_initialized (gboolean ok,GAtResult *result, +gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); + +DBG ("voicecall_init: registering to notifications" ); + +/* NO CARRIER, NO ANSWER, BUSY, NO DIALTONE are handled through SLCC */ +g_at_chat_register (vd->chat,"^SLCC:" , slcc_notify, FALSE, vc,NULL ); +g_at_chat_register (vd->chat,"+CSSI:" , cssi_notify, FALSE, vc,NULL ); +g_at_chat_register (vd->chat,"+CSSU:" , cssu_notify, FALSE, vc,NULL ); + +ofono_voicecall_register (vc); + +/* Populate the call list */ +g_at_chat_send (vd->chat,"AT+CLCC" , clcc_prefix, clcc_cb, vc,NULL ); +} + +static int gemalto_voicecall_probe (struct ofono_voicecall *vc, +unsigned int vendor,void *data) +{ +GAtChat *chat = data; +struct voicecall_data *vd; + + vd = g_try_new0(struct voicecall_data, 1); + +if (vd ==NULL ) +return -ENOMEM ; + + vd->chat =g_at_chat_clone (chat); + vd->vendor = vendor; +ofono_voicecall_set_data (vc, vd); +g_at_chat_send (vd->chat,"AT+CSSN=1,1" ,NULL ,NULL ,NULL ,NULL ); +g_at_chat_send (vd->chat,"AT^SLCC=1" ,NULL , + gemalto_voicecall_initialized, vc,NULL ); +return 0 ; +} + +static void gemalto_voicecall_remove (struct ofono_voicecall *vc) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); + +ofono_voicecall_set_data (vc,NULL ); + +g_at_chat_unref (vd->chat); +g_free (vd); +} + +static struct ofono_voicecall_driver driver = { + .name ="gemaltomodem" , + .probe = gemalto_voicecall_probe, + .remove = gemalto_voicecall_remove, + .dial = gemalto_dial, + .answer = gemalto_answer, + .hangup_all = gemalto_hangup_all, + .hangup_active = gemalto_hangup, + .hold_all_active = gemalto_hold_all_active, + .release_all_held = gemalto_release_all_held, + .set_udub = gemalto_set_udub, + .release_all_active = gemalto_release_all_active, + .release_specific = gemalto_release_specific, + .private_chat = gemalto_private_chat, + .create_multiparty = gemalto_create_multiparty, + .transfer = gemalto_transfer, + .deflect =NULL , + .swap_without_accept =NULL , + .send_tones = gemalto_send_dtmf +}; + +void gemalto_voicecall_init (void ) +{ +ofono_voicecall_driver_register (&driver); +} + +void gemalto_voicecall_exit (void ) +{ +ofono_voicecall_driver_unregister (&driver); +}
Re: [PATCH v2 1/2] Gemalto: voicecall atom
Hi Jonas,
thank you, ok to all your comments, except GemaltoVtsQuotes, about which I have commented on patch 2/2.
This atom is obviously heavily inspired from the one of atmodem, hence the double copyright in the header.
I assumed that the code was ok there, but a refresh is in order. I noticed another g_try_new and removed it, along with the control on the pointer, but the ones you mentioned in your review escaped my check.
I will change the code and re-submit.
Regards,
Giacinto
Quoted 859 lines · Jonas Bonn
Hi Giacinto,
Some, mostly trivial, comments below.
/Jonas
Quoted 38 lines · Giacinto Cifelli
Added voicecall atom specific for Gemalto modems.
This atom uses the URC ^SLCC to monitor the call status, as well as incoming calls.--- Makefile.am | 3 +- drivers/gemaltomodem/gemaltomodem.c | 2 + drivers/gemaltomodem/gemaltomodem.h | 2 + drivers/gemaltomodem/voicecall.c | 751 ++++++++++++++++++++++++++++ 4 files changed, 757 insertions(+), 1 deletion(-)create mode 100644
drivers/gemaltomodem/voicecall.cMakefile.am +2
-1@@ -397,7 +397,8 @@ builtin_modules += gemaltomodem builtin_sources += drivers/atmodem/atutil.h \ drivers/gemaltomodem/gemaltomodem.h \ drivers/gemaltomodem/gemaltomodem.c \ - drivers/gemaltomodem/location-reporting.c + drivers/gemaltomodem/location-reporting.c \ + drivers/gemaltomodem/voicecall.c builtin_modules += xmm7modem builtin_sources += drivers/atmodem/atutil.h \drivers/gemaltomodem/gemaltomodem.c +1
-0@@ -35,6 +35,7 @@static int gemaltomodem_init (void ) {gemalto_location_reporting_init (); +gemalto_voicecall_init ();return 0 ; }drivers/gemaltomodem/gemaltomodem.c static int gemaltomodem_init(void) · line 47
Quoted 5 lines
drivers/gemaltomodem/gemaltomodem.c +1
-0@@ -42,6 +43,7 @@ static int gemaltomodem_init(void)static void gemaltomodem_exit (void ) {gemalto_location_reporting_exit (); +gemalto_voicecall_exit (); }init and exit functions usually reverse the order of the functions so that last initialized is first to be cleaned up. Presumably not relevant here but it's good form.
Quoted 108 lines
drivers/gemaltomodem/gemaltomodem.c +0
-0OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,drivers/gemaltomodem/gemaltomodem.h +2
-0@@ -23,3 +23,5 @@extern void gemalto_location_reporting_init ();extern void gemalto_location_reporting_exit (); +extern void gemalto_voicecall_init (); +extern void gemalto_voicecall_exit ();drivers/gemaltomodem/voicecall.c new file +90
-0@@ -0,0 +1,751 @@ +/* +* +* oFono - Open Source Telephony +* +* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. +* Copyright (C) 2018 Gemalto M2M +* +* 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 <errno.h> + +#include <glib.h> + +#include <ofono/log.h> +#include <ofono/modem.h> +#include <ofono/voicecall.h> + +#include "gatchat.h" +#include "gatresult.h" + +#include "common.h" + +#include "gemaltomodem.h" + +static const char *clcc_prefix[] = {"+CLCC:" ,NULL }; +static const char *none_prefix[] = {NULL }; + +/* According to 27.007 COLP is an intermediate status for ATD */ +static const char *atd_prefix[] = {"+COLP:" ,NULL }; + +#define FLAG_NEED_CLIP 1 + +struct voicecall_data { +GAtChat *chat; +GSList *calls; +unsigned int local_release; +unsigned int vendor; +unsigned char flags; +GSList *new_calls; +}; + +struct release_id_req { +struct ofono_voicecall *vc; +ofono_voicecall_cb_t cb; +void *data; +int id; +}; + +struct change_state_req { +struct ofono_voicecall *vc; +ofono_voicecall_cb_t cb; +void *data; +int affected_types; +}; + +static void generic_cb (gboolean ok,GAtResult *result,gpointer user_data) +{ +struct change_state_req *req = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (req->vc); +struct ofono_error error; + +decode_at_error (&error,g_at_result_final_response (result)); + +if (ok && req->affected_types) { +GSList *l; +struct ofono_call *call; + +for (l = vd->calls; l; l = l->next) { + call = l->data;drivers/gemaltomodem/voicecall.c line 100
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +10
-0+ +if (req->affected_types & (1 << call->status)) + vd->local_release |= (1 << call->id); + } + } + + req->cb (&error, req->data); +} + +static void gemalto_template(const char *cmd, struct ofono_voicecall *vc,
gemalto_templateis not a great name.gemalto_common,gemalto_call_common...???drivers/gemaltomodem/voicecall.c line 105
Quoted 5 lines
drivers/gemaltomodem/voicecall.c new file +5
-0+ GAtResultFunc result_cb, unsigned int affected_types, + ofono_voicecall_cb_t cb, void *data) +{ + struct voicecall_data *vd = ofono_voicecall_get_data(vc); + struct change_state_req *req = g_try_new0(struct change_state_req, 1);
g_new0is sufficient.drivers/gemaltomodem/voicecall.c line 108
Quoted 3 lines
drivers/gemaltomodem/voicecall.c new file +3
-0+ +if (req ==NULL ) + goto error;Linux will never fail the allocation so skip the error check.
Quoted 152 lines
drivers/gemaltomodem/voicecall.c new file +152
-0+ + req->vc = vc; + req->cb = cb; + req->data = data; + req->affected_types = affected_types; + +if (g_at_chat_send (vd->chat, cmd, none_prefix, + result_cb, req, g_free) >0 ) +return ; + +error: +g_free (req); + +CALLBACK_WITH_FAILURE (cb, data); +} + +static void gemalto_answer (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +gemalto_template ("ATA" , vc, generic_cb,0 , cb, data); +} + +static void gemalto_hangup_all (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_INCOMING ) | + (1 <<CALL_STATUS_DIALING ) | + (1 <<CALL_STATUS_ALERTING ) | + (1 <<CALL_STATUS_WAITING ) | + (1 <<CALL_STATUS_HELD ) | + (1 <<CALL_STATUS_ACTIVE ); + +/* Hangup all calls */ +gemalto_template ("AT+CHUP" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_hangup (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ); + +/* Hangup current active call */ +gemalto_template ("AT+CHLD=1" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_hold_all_active (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ); +gemalto_template ("AT+CHLD=2" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_release_all_held (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_INCOMING ) | + (1 <<CALL_STATUS_WAITING ); + +gemalto_template ("AT+CHLD=0" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_set_udub (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_INCOMING ) | + (1 <<CALL_STATUS_WAITING ); + +gemalto_template ("AT+CHLD=0" , vc, generic_cb, affected, cb, data); +} + +static void gemalto_release_all_active (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ); + +gemalto_template ("AT+CHLD=1" , vc, generic_cb, affected, cb, data); +} + +static void release_id_cb (gboolean ok,GAtResult *result, +gpointer user_data) +{ +struct release_id_req *req = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (req->vc); +struct ofono_error error; + +decode_at_error (&error,g_at_result_final_response (result)); + +if (ok) + vd->local_release =1 << req->id; + + req->cb (&error, req->data); +} + +static void gemalto_release_specific (struct ofono_voicecall *vc,int id, +ofono_voicecall_cb_t cb,void *data) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); + struct release_id_req *req = g_try_new0(struct release_id_req, 1); +char buf[32 ]; + +if (req ==NULL ) + goto error; + + req->vc = vc; + req->cb = cb; + req->data = data; + req->id = id; + +snprintf (buf,sizeof (buf),"AT+CHLD=1%d" , id); + +if (g_at_chat_send (vd->chat, buf, none_prefix, + release_id_cb, req, g_free) >0 ) +return ; + +error: +g_free (req); + +CALLBACK_WITH_FAILURE (cb, data); +} + +static void gemalto_private_chat (struct ofono_voicecall *vc,int id, +ofono_voicecall_cb_t cb,void *data) +{ +char buf[32 ]; + +snprintf (buf,sizeof (buf),"AT+CHLD=2%d" , id); +gemalto_template (buf, vc, generic_cb,0 , cb, data); +} + +static void gemalto_create_multiparty (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +gemalto_template ("AT+CHLD=3" , vc, generic_cb,0 , cb, data); +} + +static void gemalto_transfer (struct ofono_voicecall *vc, +ofono_voicecall_cb_t cb,void *data) +{ +/* Held & Active */ +unsigned int affected = (1 <<CALL_STATUS_ACTIVE ) | + (1 <<CALL_STATUS_HELD ); + +/* Transfer can puts held & active calls together and disconnects +* from both. However, some networks support transferring of +* dialing/ringing calls as well. +*/ + affected |= (1 <<CALL_STATUS_DIALING ) | + (1 <<CALL_STATUS_ALERTING ); + +gemalto_template ("AT+CHLD=4" , vc, generic_cb, affected, cb, data); +} +drivers/gemaltomodem/voicecall.c line 270
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +10
-0+static void gemalto_send_dtmf (struct ofono_voicecall *vc,const char *dtmf, +ofono_voicecall_cb_t cb,void *data) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +int len =strlen (dtmf); +int s; +int i; +char *buf; +struct ofono_modem *modem =ofono_voicecall_get_modem (vc); +int use_quotes =ofono_modem_get_integer (modem,"GemaltoVtsQuotes" );GemaltoVtsQuotes is set unconditionally in patch 2/2. Was that your intention? If so, you don't need this variable...
drivers/gemaltomodem/voicecall.c line 273
Quoted 3 lines
drivers/gemaltomodem/voicecall.c new file +3
-0+ +/* strlen("+VTS=\"T\";") = 9 + initial AT + null */ + buf =g_try_new (char, len *9 +3 );
g_newdrivers/gemaltomodem/voicecall.c line 278
Quoted 5 lines
drivers/gemaltomodem/voicecall.c new file +5
-0+ +if (buf ==NULL ) { +CALLBACK_WITH_FAILURE (cb, data); +return ; + }Linux won't fail the allocation.
drivers/gemaltomodem/voicecall.c line 284
Quoted 6 lines
drivers/gemaltomodem/voicecall.c new file +6
-0+ +if (use_quotes) + s =sprintf (buf,"AT+VTS=\"%c\"" , dtmf[0 ]); +else + s =sprintf (buf,"AT+VTS=%c" , dtmf[0 ]); +As per above,
use_quotesis always 1...Quoted 13 lines
drivers/gemaltomodem/voicecall.c new file +13
-0+for (i =1 ; i < len; i++) { + +if (use_quotes) + s +=sprintf (buf + s,";+VTS=\"%c\"" , dtmf[i]); +else + s +=sprintf (buf + s,";+VTS=%c" , dtmf[i]); + } + +g_at_chat_send (vd->chat, buf,NULL ,NULL ,NULL ,NULL ); +g_free (buf); +} + +static struct ofono_call *create_call(struct ofono_voicecall *vc, int type,drivers/gemaltomodem/voicecall.c line 307
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +10
-0+ int direction, int status, + const char *num, int num_type, int clip) +{ + struct voicecall_data *d = ofono_voicecall_get_data(vc); +struct ofono_call *call; + +/* Generate a call structure for the waiting call */ + call = g_try_new(struct ofono_call, 1); +if (call ==NULL ) +return NULL ;
g_new... won't fail.Quoted 95 lines
drivers/gemaltomodem/voicecall.c new file +95
-0+ +ofono_call_init (call); + + call->id =ofono_voicecall_get_next_callid (vc); + call->type = type; + call->direction = direction; + call->status = status; + +if (clip !=2 ) { +strncpy (call->phone_number.number, num, +OFONO_MAX_PHONE_NUMBER_LENGTH ); + call->phone_number.type = num_type; + } + + call->clip_validity = clip; + call->cnap_validity =CNAP_VALIDITY_NOT_AVAILABLE ; + + d->calls =g_slist_insert_sorted (d->calls, call, at_util_call_compare); + +return call; +} + +static void atd_cb (gboolean ok,GAtResult *result,gpointer user_data) +{ +struct cb_data *cbd = user_data; +struct ofono_voicecall *vc = cbd->user; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +ofono_voicecall_cb_t cb = cbd->cb; +GAtResultIter iter; +const char *num; +int type =128 ; +int validity =2 ; +struct ofono_error error; +struct ofono_call *call; +GSList *l; + +decode_at_error (&error,g_at_result_final_response (result)); + +if (!ok) + goto out; + +/* On a success, make sure to put all active calls on hold */ +for (l = vd->calls; l; l = l->next) { + call = l->data; + +if (call->status !=CALL_STATUS_ACTIVE ) +continue ; + + call->status =CALL_STATUS_HELD ; +ofono_voicecall_notify (vc, call); + } + +g_at_result_iter_init (&iter, result); + +if (g_at_result_iter_next (&iter,"+COLP:" )) { +g_at_result_iter_next_string (&iter, &num); +g_at_result_iter_next_number (&iter, &type); + +if (strlen (num) >0 ) + validity =0 ; +else + validity =2 ; + +DBG ("colp_notify: %s %d %d" , num, type, validity); + } + +/* Generate a voice call that was just dialed, we guess the ID */ + call =create_call (vc,0 ,0 ,CALL_STATUS_DIALING , num, type, validity); +if (call ==NULL ) { +ofono_error ("Unable to malloc, call tracking will fail!" ); +return ; + } + +/* oFono core will generate a call with the dialed number +* inside its dial callback. Unless we got COLP information +* we do not need to communicate that a call is being +* dialed +*/ +if (validity !=2 ) +ofono_voicecall_notify (vc, call); + +out: +cb (&error, cbd->data); +} + +static void gemalto_dial (struct ofono_voicecall *vc, +const struct ofono_phone_number *ph, +enum ofono_clir_option clir,ofono_voicecall_cb_t cb, +void *data) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +struct cb_data *cbd =cb_data_new (cb, data); +char buf[256 ]; + + cbd->user = vc;drivers/gemaltomodem/voicecall.c line 411
Quoted 10 lines
drivers/gemaltomodem/voicecall.c new file +9
-0+ +if (ph->type ==145 ) +snprintf (buf,sizeof (buf),"ATD+%s" , ph->number); +else +snprintf (buf,sizeof (buf),"ATD%s" , ph->number); + +switch (clir) { +case OFONO_CLIR_OPTION_INVOCATION : +strcat (buf,"I" );I'm a bit allergic to snprintf followed by strcat... you already know the length of buf (at least, if you grab the return value from snprintf), so use snprintf again and save having to do a search for \0 like strcat does.
Quoted 340 lines
drivers/gemaltomodem/voicecall.c new file +340
-0+break ; +case OFONO_CLIR_OPTION_SUPPRESSION : +strcat (buf,"i" ); +break ; +default : +break ; + } + +strcat (buf,";" ); + +if (g_at_chat_send (vd->chat, buf, atd_prefix, + atd_cb, cbd, g_free) >0 ) +return ; + +g_free (cbd); + +CALLBACK_WITH_FAILURE (cb, data); +} + +static gboolean gemalto_parse_slcc (GAtResult *result,GSList **l, +unsigned int *ret_mpty_ids) +{ +GAtResultIter iter; +int id, dir, status, type; +ofono_bool_t mpty; +struct ofono_call *call; +unsigned int mpty_ids =0 ; +gboolean last = TRUE; +const char *str ="" ; +int number_type =129 ; + +g_at_result_iter_init (&iter, result); + +g_at_result_iter_next (&iter,"^SLCC:" ); + +if (!g_at_result_iter_next_number (&iter, &id)) + goto finish; + + last = FALSE; + +if (id ==0 ) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &dir)) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &status)) + goto finish; + +if (status >5 ) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &type)) + goto finish; + +if (!g_at_result_iter_next_number (&iter, &mpty)) + goto finish; + +/* skip 'Reserved=0' parameter, only difference from CLCC */ +if (!g_at_result_iter_skip_next (&iter)) + goto finish; + +if (g_at_result_iter_next_string (&iter, &str)) +g_at_result_iter_next_number (&iter, &number_type); + + call = g_new0(struct ofono_call, 1); +ofono_call_init (call); + call->id = id; + call->direction = dir; + call->status = status; + call->type = type; +strncpy (call->phone_number.number, str, +OFONO_MAX_PHONE_NUMBER_LENGTH ); + call->phone_number.type = number_type; + +if (strlen (call->phone_number.number) >0 ) + call->clip_validity =0 ; +else + call->clip_validity =2 ; + + *l =g_slist_insert_sorted (*l, call, at_util_call_compare); + +if (mpty) + mpty_ids |=1 << id; + +if (ret_mpty_ids) + *ret_mpty_ids = mpty_ids; + +finish: +return last; +} + +static void clcc_cb (gboolean ok,GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +GSList *l; + +if (!ok) +return ; + + vd->calls =at_util_parse_clcc (result,NULL ); + +for (l = vd->calls; l; l = l->next) +ofono_voicecall_notify (vc, l->data); +} + +/* +* ^SLCC, except for one RFU parameter (see above in the parsing), is identical +* to +CLCC, but as URC it is parsed line by line, and the last line is +* indicated by an empty "^SLCC:" (equivalent to the "OK" for CLCC). +*/ +static void slcc_notify (GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); +GSList *n, *o; +struct ofono_call *nc, *oc; + +gboolean last =gemalto_parse_slcc (result, &vd->new_calls,NULL ); + +if (!last) +return ; + + n = vd->new_calls; + o = vd->calls; + +while (n || o) { + + nc = n ? n->data :NULL ; + oc = o ? o->data :NULL ; + +if (oc && (nc ==NULL || (nc->id > oc->id))) { +enum ofono_disconnect_reason reason; + +if (vd->local_release & (1 << oc->id)) + reason =OFONO_DISCONNECT_REASON_LOCAL_HANGUP ; +else + reason =OFONO_DISCONNECT_REASON_REMOTE_HANGUP ; + +if (!oc->type) +ofono_voicecall_disconnected (vc, oc->id, + reason,NULL ); + + o = o->next; + }else if (nc && (oc ==NULL || (nc->id < oc->id))) { + +if (nc->type ==0 )/* new call, signal it */ +ofono_voicecall_notify (vc, nc); + + n = n->next; + }else { +/* +* Always use the clip_validity from old call +* the only place this is truly told to us is +* in the CLIP notify, the rest are fudged +* anyway. Useful when RING, CLIP is used, +* and we're forced to use CLCC/SLCC and clip_validity +* is 1 +*/ +if (oc->clip_validity ==1 ) + nc->clip_validity = oc->clip_validity; + +/* +* CNAP doesn't arrive as part of CLCC, always +* re-use from the old call +*/ +strncpy (nc->name, oc->name, +OFONO_MAX_CALLER_NAME_LENGTH ); + nc->name[OFONO_MAX_CALLER_NAME_LENGTH ] ='\0' ; + nc->cnap_validity = oc->cnap_validity; + +/* +* CDIP doesn't arrive as part of CLCC, always +* re-use from the old call +*/ +memcpy (&nc->called_number, &oc->called_number, +sizeof (oc->called_number)); + +/* +* If the CLIP is not provided and the CLIP never +* arrives, or RING is used, then signal the call +* here +*/ +if (nc->status ==CALL_STATUS_INCOMING && + (vd->flags &FLAG_NEED_CLIP )) { +if (nc->type ==0 ) +ofono_voicecall_notify (vc, nc); + + vd->flags &= ~FLAG_NEED_CLIP ; + }else if (memcmp (nc, oc,sizeof (*nc)) && nc->type ==0 ) +ofono_voicecall_notify (vc, nc); + + n = n->next; + o = o->next; + } + } + +g_slist_free_full (vd->calls, g_free); + + vd->calls = vd->new_calls; + vd->new_calls =NULL ; + + vd->local_release =0 ; +} + +static void cssi_notify (GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +GAtResultIter iter; +int code, index; + +g_at_result_iter_init (&iter, result); + +if (!g_at_result_iter_next (&iter,"+CSSI:" )) +return ; + +if (!g_at_result_iter_next_number (&iter, &code)) +return ; + +if (!g_at_result_iter_next_number (&iter, &index)) + index =0 ; + +ofono_voicecall_ssn_mo_notify (vc,0 , code, index); +} + +static void cssu_notify (GAtResult *result,gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +GAtResultIter iter; +int code; +int index; +const char *num; +struct ofono_phone_number ph; + + ph.number[0 ] ='\0' ; + ph.type =129 ; + +g_at_result_iter_init (&iter, result); + +if (!g_at_result_iter_next (&iter,"+CSSU:" )) +return ; + +if (!g_at_result_iter_next_number (&iter, &code)) +return ; + +if (!g_at_result_iter_next_number_default (&iter,-1 , &index)) + goto out; + +if (!g_at_result_iter_next_string (&iter, &num)) + goto out; + +strncpy (ph.number, num,OFONO_MAX_PHONE_NUMBER_LENGTH ); + +if (!g_at_result_iter_next_number (&iter, &ph.type)) +return ; + +out: +ofono_voicecall_ssn_mt_notify (vc,0 , code, index, &ph); +} + +static void gemalto_voicecall_initialized (gboolean ok,GAtResult *result, +gpointer user_data) +{ +struct ofono_voicecall *vc = user_data; +struct voicecall_data *vd =ofono_voicecall_get_data (vc); + +DBG ("voicecall_init: registering to notifications" ); + +/* NO CARRIER, NO ANSWER, BUSY, NO DIALTONE are handled through SLCC */ +g_at_chat_register (vd->chat,"^SLCC:" , slcc_notify, FALSE, vc,NULL ); +g_at_chat_register (vd->chat,"+CSSI:" , cssi_notify, FALSE, vc,NULL ); +g_at_chat_register (vd->chat,"+CSSU:" , cssu_notify, FALSE, vc,NULL ); + +ofono_voicecall_register (vc); + +/* Populate the call list */ +g_at_chat_send (vd->chat,"AT+CLCC" , clcc_prefix, clcc_cb, vc,NULL ); +} + +static int gemalto_voicecall_probe (struct ofono_voicecall *vc, +unsigned int vendor,void *data) +{ +GAtChat *chat = data; +struct voicecall_data *vd; + + vd = g_try_new0(struct voicecall_data, 1); + +if (vd ==NULL ) +return -ENOMEM ; + + vd->chat =g_at_chat_clone (chat); + vd->vendor = vendor; +ofono_voicecall_set_data (vc, vd); +g_at_chat_send (vd->chat,"AT+CSSN=1,1" ,NULL ,NULL ,NULL ,NULL ); +g_at_chat_send (vd->chat,"AT^SLCC=1" ,NULL , + gemalto_voicecall_initialized, vc,NULL ); +return 0 ; +} + +static void gemalto_voicecall_remove (struct ofono_voicecall *vc) +{ +struct voicecall_data *vd =ofono_voicecall_get_data (vc); + +ofono_voicecall_set_data (vc,NULL ); + +g_at_chat_unref (vd->chat); +g_free (vd); +} + +static struct ofono_voicecall_driver driver = { + .name ="gemaltomodem" , + .probe = gemalto_voicecall_probe, + .remove = gemalto_voicecall_remove, + .dial = gemalto_dial, + .answer = gemalto_answer, + .hangup_all = gemalto_hangup_all, + .hangup_active = gemalto_hangup, + .hold_all_active = gemalto_hold_all_active, + .release_all_held = gemalto_release_all_held, + .set_udub = gemalto_set_udub, + .release_all_active = gemalto_release_all_active, + .release_specific = gemalto_release_specific, + .private_chat = gemalto_private_chat, + .create_multiparty = gemalto_create_multiparty, + .transfer = gemalto_transfer, + .deflect =NULL , + .swap_without_accept =NULL , + .send_tones = gemalto_send_dtmf +}; + +void gemalto_voicecall_init (void ) +{ +ofono_voicecall_driver_register (&driver); +} + +void gemalto_voicecall_exit (void ) +{ +ofono_voicecall_driver_unregister (&driver); +}
PATCH v2 2/2 plugins/gemalto: added voice support
In reply to Giacinto CifelliThe plugin for Gemalto modems is enriched with all voice-related atoms, as well as USSD.
All except the voicecall itself are from the atmodem, while the voicecall is from gemaltomodem.
--- plugins/gemalto.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
plugins/gemalto.c +11 -0
@@ -571,6 +571,10 @@ static void gemalto_pre_sim(struct ofono_modem *modem)ofono_devinfo_create (modem,0 ,"atmodem" , data->app);ofono_location_reporting_create (modem,0 ,"gemaltomodem" , data->app); + +ofono_modem_set_integer (modem,"GemaltoVtsQuotes" ,1 ); +ofono_voicecall_create (modem,0 ,"gemaltomodem" , data->app); + data->sim =ofono_sim_create (modem,OFONO_VENDOR_GEMALTO ,"atmodem" , data->app);
@@ -597,6 +601,13 @@ static void gemalto_post_sim(struct ofono_modem *modem)if (gprs && gc)ofono_gprs_add_context (gprs, gc); +ofono_ussd_create (modem,0 ,"atmodem" , data->app); + +ofono_call_forwarding_create (modem,0 ,"atmodem" , data->app); +ofono_call_settings_create (modem,0 ,"atmodem" , data->app); +ofono_call_meter_create (modem,0 ,"atmodem" , data->app); +ofono_call_barring_create (modem,0 ,"atmodem" , data->app); +if (!g_strcmp0 (model, GEMALTO_MODEL_ALS3_PLS8x))ofono_lte_create (modem,OFONO_VENDOR_CINTERION ,"atmodem" , data->app);
Signature · 1 line
2.17.1
Re: [PATCH v2 2/2] plugins/gemalto: added voice support
Quoted 13 lines · Giacinto Cifelli
The plugin for Gemalto modems is enriched with all voice-related atoms, as well as USSD.
All except the voicecall itself are from the atmodem, while the voicecall is from gemaltomodem.--- plugins/gemalto.c | 11 +++++++++++ 1 file changed, 11 insertions(+)plugins/gemalto.c +0
-0
plugins/gemalto.c static void gemalto_pre_sim(struct ofono_modem *modem) · line 575
Quoted 5 lines
plugins/gemalto.c +2
-0@@ -571,6 +571,10 @@ static void gemalto_pre_sim(struct ofono_modem *modem)ofono_devinfo_create (modem,0 ,"atmodem" , data->app);ofono_location_reporting_create (modem,0 ,"gemaltomodem" , data->app); + +ofono_modem_set_integer (modem,"GemaltoVtsQuotes" ,1 );
Do you really mean to set this unconditionally for all models?
/Jonas
Quoted 19 lines
plugins/gemalto.c +9
-0+ofono_voicecall_create (modem,0 ,"gemaltomodem" , data->app); + data->sim =ofono_sim_create (modem,OFONO_VENDOR_GEMALTO ,"atmodem" , data->app);@@ -597,6 +601,13 @@ static void gemalto_post_sim(struct ofono_modem *modem)if (gprs && gc)ofono_gprs_add_context (gprs, gc); +ofono_ussd_create (modem,0 ,"atmodem" , data->app); + +ofono_call_forwarding_create (modem,0 ,"atmodem" , data->app); +ofono_call_settings_create (modem,0 ,"atmodem" , data->app); +ofono_call_meter_create (modem,0 ,"atmodem" , data->app); +ofono_call_barring_create (modem,0 ,"atmodem" , data->app); +if (!g_strcmp0 (model, GEMALTO_MODEL_ALS3_PLS8x))ofono_lte_create (modem,OFONO_VENDOR_CINTERION ,"atmodem" , data->app);
Re: [PATCH v2 2/2] plugins/gemalto: added voice support
Hi Jonas,
I answer here to the point about VTS with quotes.
Quoted 18 lines · Jonas Bonn
Quoted 14 lines · Giacinto Cifelli
The plugin for Gemalto modems is enriched with all voice-related atoms, as well as USSD.
All except the voicecall itself are from the atmodem, while the voicecall is from gemaltomodem.--- plugins/gemalto.c | 11 +++++++++++ 1 file changed, 11 insertions(+)plugins/gemalto.c +0
-0@@ -571,6 +571,10 @@ static void gemalto_pre_sim(struct ofono_modem *modem)
Quoted 6 lines
plugins/gemalto.c static void gemalto_pre_sim(struct ofono_modem *modem) · line 575
Quoted 4 lines
plugins/gemalto.c +2
-0ofono_devinfo_create (modem,0 ,"atmodem" , data->app);ofono_location_reporting_create (modem,0 ,"gemaltomodem" , data->app); + +ofono_modem_set_integer (modem,"GemaltoVtsQuotes" ,1 );Do you really mean to set this unconditionally for all models?
The current supported modules for the gemalto plugin, and also TC65 for the cinterion plugin, require quotes.
But not the EHS6.
I need to add quite a few modules in the gemalto plugin, but for now there are still too many patches to push before.
So for now, it is fixed, but later it will depend on the model. I won't be patching the cinterion plugin, because I have the impression it is not used anymore.
Several things don't work anymore as they were when this was implemented. I intend, however, to merge it with the gemalto one, and then I will take care of it.
Most Gemalto modules can work over USB or RS232, so it still makes sense to maintain the serial interface.
Quoted 3 lines
/Jonas
Giacinto