gsm: use PDU modem when the modem doesn't support text mode

Eventually we should be using PDU mode whenever the modem supports
it instead of defaulting to text mode, but there are still some
bugs.
This commit is contained in:
Dan Williams
2012-01-18 13:45:03 -06:00
parent 43e6039cee
commit d51ff9ac07

View File

@@ -136,6 +136,7 @@ typedef struct {
* structures.
*/
GHashTable *sms_parts;
gboolean sms_pdu_mode;
guint sms_fetch_pending;
@@ -1799,6 +1800,88 @@ clck_cb (MMAtSerialPort *port,
mm_serial_port_close (MM_SERIAL_PORT (port));
}
static void
sms_set_format_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
if (error) {
mm_warn ("(%s): failed to set SMS mode, assuming text mode",
mm_port_get_device (MM_PORT (port)));
MM_GENERIC_GSM_GET_PRIVATE (user_data)->sms_pdu_mode = FALSE;
} else {
mm_info ("(%s): using %s mode for SMS",
mm_port_get_device (MM_PORT (port)),
MM_GENERIC_GSM_GET_PRIVATE (user_data)->sms_pdu_mode ? "PDU" : "text");
}
}
#define CMGF_TAG "+CMGF:"
static void
sms_get_format_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMGenericGsm *self;
MMGenericGsmPrivate *priv;
const char *reply;
GRegex *r;
GMatchInfo *match_info;
char *s;
guint32 min = -1, max = -1;
if (error) {
mm_warn ("(%s): failed to query SMS mode, assuming text mode",
mm_port_get_device (MM_PORT (port)));
return;
}
/* Strip whitespace and response tag */
reply = response->str;
if (g_str_has_prefix (reply, CMGF_TAG))
reply += strlen (CMGF_TAG);
while (isspace (*reply))
reply++;
r = g_regex_new ("\\(?\\s*(\\d+)\\s*[-,]?\\s*(\\d+)?\\s*\\)?", 0, 0, NULL);
if (!r) {
mm_warn ("(%s): failed to parse CMGF query result", mm_port_get_device (MM_PORT (port)));
return;
}
self = MM_GENERIC_GSM (user_data);
priv = MM_GENERIC_GSM_GET_PRIVATE (self);
if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
s = g_match_info_fetch (match_info, 1);
if (s)
min = atoi (s);
g_free (s);
s = g_match_info_fetch (match_info, 2);
if (s)
max = atoi (s);
g_free (s);
/* If the modem only supports PDU mode, use PDUs.
* FIXME: when the PDU code is more robust, default to PDU if the
* modem supports it.
*/
if (min == 0 && max < 1) {
/* Will get reset to FALSE on receipt of error */
priv->sms_pdu_mode = TRUE;
mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=0", 3, sms_set_format_cb, self);
} else
mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=1", 3, sms_set_format_cb, self);
}
g_match_info_free (match_info);
g_regex_unref (r);
}
void
mm_generic_gsm_enable_complete (MMGenericGsm *self,
GError *error,
@@ -1849,6 +1932,9 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self,
mm_at_serial_port_queue_command (priv->primary, cmd, 3, NULL, NULL);
g_free (cmd);
/* Check and enable the right SMS mode */
mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=?", 3, sms_get_format_cb, self);
/* Enable USSD notifications */
mm_at_serial_port_queue_command (priv->primary, "+CUSD=1", 3, cusd_enable_cb, self);
@@ -4669,21 +4755,49 @@ sms_send (MMModemGsmSms *modem,
gpointer user_data)
{
MMCallbackInfo *info;
MMGenericGsm *self = MM_GENERIC_GSM (modem);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
char *command;
MMAtSerialPort *port;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
port = mm_generic_gsm_get_best_at_port (self, &info->error);
if (!port) {
mm_callback_info_schedule (info);
return;
}
/* FIXME: use the PDU mode instead */
mm_at_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL);
if (priv->sms_pdu_mode) {
guint8 *pdu;
guint pdulen = 0;
guint smsclen = 0;
char *hex;
pdu = sms_create_submit_pdu (number, text, smsc, validity, class, &pdulen, &info->error);
if (!pdu) {
mm_callback_info_schedule (info);
return;
}
smsclen = pdu[0];
hex = utils_bin2hexstr (pdu, pdulen);
g_free (pdu);
if (hex == NULL) {
g_set_error_literal (&info->error,
MM_MODEM_ERROR,
MM_MODEM_ERROR_GENERAL,
"Not enough memory to send SMS PDU");
mm_callback_info_schedule (info);
return;
}
/* CMGS length is the size of the PDU without SMSC information */
command = g_strdup_printf ("+CMGS=%d\r%s\x1a", pdulen - smsclen, hex);
g_free (hex);
} else
command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text);
command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text);
mm_at_serial_port_queue_command (port, command, 10, sms_send_done, info);
g_free (command);
}