Fixed typo in error message.
[gsmd2.git] / src / modem.c
blob12e45d6a942f11632a8b89faab474d5d699b9d82
1 /*
2 * modem.c
4 * Copyright(C) 2007,2008 Ixonos Plc
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Boston, MA 02111.
22 * Written by
23 * Jukka Honkela
24 * Yi Zheng
25 * Matti Katila
26 * Vesa Pikki
27 * Heikki Paajanen
30 #include <glib.h>
31 #include <gmodule.h>
32 #include <stdio.h>
33 #include <termios.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <dlfcn.h>
37 #include <unistd.h>
38 #include "serial.h"
39 #include "modem_internal.h"
40 #include "call.h"
41 #include "call_interface.h"
42 #include "sms.h"
43 #include "sms_impl.h"
44 #include "device.h"
45 #include "pdp.h"
46 #include "network.h"
47 #include "sim.h"
48 #include "sms_interface.h"
49 #include "pdp_interface.h"
50 #include "network_interface.h"
51 #include "device_interface.h"
52 #include "sim_interface.h"
53 #include "gsmd-error.h"
54 #include "utils.h"
57 #define TIME_OUT "TIME_OUT\n"
59 /** Default time out value for AT command */
60 #define DEFAULT_TIME_OUT 100
62 /** Time out value for AT command */
63 #define TIME_OUT_PADDING 5000
66 /* static Modem *modem_priv; */
68 /**
69 * @brief Serial device
70 * Modem can have multiple serial devices, each of them has their own Serial
71 * and command queue
74 typedef struct _SerialDevice
76 /**
77 * AT command queue
79 GQueue *commandQueue;
80 /**
81 * IOChannel of serial device
83 Serial *serial;
85 /**
86 * Pointer to modem interface used
88 Modem *modem;
90 /**
91 * Index of the serial device to use
93 guint device_index;
95 } SerialDevice;
97 /**
98 * @brief Modem Struct
99 **/
100 struct _Modem
103 * time out flag
105 gboolean is_timeout;
108 * Serial devices
110 GArray *serial_devices;
113 * AT command table
115 GHashTable *commands_table;
118 * modem interface
120 ModemInterface *modem_if;
123 * vendor lib handle
125 GModule* vendor_handle;
128 * Vendor interface
130 VendorInterface *vendor;
133 * Serial plugin handle
135 GModule* serial_plugin_handle;
138 * SerialPlugin interface
140 SerialInterface *serial_if;
145 /*********************service function**************************/
146 static void gsmd_modem_init ( ModemInterface* modem);
147 static AtCommandHandlerStatus gsmd_modem_handler_unsolicite (ModemInterface *modem,
148 AtCommandContext *at,
149 GString *response);
151 static void gsmd_modem_process_next_command (Modem* modem, InterfaceType interface);
152 static gboolean gsmd_modem_timeout_handle (gpointer data);
154 static
155 SerialDevice *gsmd_modem_get_serial_device(Modem *modem, InterfaceType interface);
157 static
158 AtCommandHandlerStatus gsmd_modem_handler_alive(ModemInterface *modem,
159 AtCommandContext *at,
160 GString *response);
162 static
163 AtCommandHandlerStatus gsmd_modem_handler_current_calls(ModemInterface *modem,
164 AtCommandContext *at,
165 GString *response);
167 static void gsmd_modem_current_calls_free(AtCommandContext *at);
168 /********************End service function***********************/
171 static const AtCommand
172 commands[]
175 //Disable command echos
176 { DISABLE_ECHO, "ATE0\r\n", 100,
177 TRUE, 0,
178 gsmd_utils_handler_ok, NULL, SIM_UNKNOWN, NULL},
180 //Enable everything
181 { POWER_ON, "AT+CFUN=1\r\n", 15000,
182 TRUE, 0,
183 gsmd_utils_handler_ok, NULL, SIM_UNKNOWN, NULL},
185 //Enable Report Mobile Equipment Error
186 { ENABLE_CMEE, "AT+CMEE=1\r\n", 100,
187 TRUE, 0,
188 gsmd_utils_handler_ok, NULL, SIM_UNKNOWN, NULL},
190 //Set response of AT+COPS? to respond with operator name
191 { SET_OP_QUERY_REPLY, "AT+COPS=3,0\r\n", 100,
192 TRUE, 0,
193 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
195 //Enable Report Mobile Equipment Error
196 { ENABLE_CMEE, "AT+CMEE=1\r\n", 100,
197 TRUE, 3,
198 gsmd_utils_handler_ok, NULL, SIM_UNKNOWN, NULL},
200 //Enable call waiting
201 { ENABLE_CCWA, "AT+CCWA=1,1\r\n", 100,
202 TRUE, 0,
203 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
205 //Enable call waiting
206 { CUR_CALLS_QUERY, "AT+CLCC\r\n", 100,
207 TRUE, 0,
208 gsmd_modem_handler_current_calls, NULL, SIM_READY,
209 gsmd_modem_current_calls_free},
211 //Query if we are muted
212 { MUTE_QUERY, "AT+CMUTE=?\r\n", 5000,
213 TRUE, 0,
214 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
216 //Enable caller identification
217 { ENABLE_CLIP, "AT+CLIP=1\r\n", 180000,
218 TRUE, 3,
219 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
221 //Enable new message identification
222 { ENABLE_CNMI, "AT+CNMI=2,1,0,0,0\r\n", 5000,
223 TRUE, 3,
224 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
226 //Query ring volume
227 { RING_VOLUME_QUERY, "AT+CRSL?\r\n", 5000,
228 TRUE, 0,
229 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
231 //Escape command
232 { ESCAPE_COMMAND, "+++\r\n", 100,
233 FALSE, 0,
234 gsmd_utils_handler_ok, NULL, SIM_UNKNOWN, NULL},
236 //Just send at command
237 { AT, "AT\r\n", 5000,
238 FALSE, 0,
239 gsmd_utils_handler_ok, NULL, SIM_UNKNOWN, NULL},
241 //Test modem is alive
242 { REPLY_COMMAND, "AT\r\n", 5000,
243 FALSE, 0,
244 gsmd_modem_handler_alive, NULL, SIM_UNKNOWN, NULL},
246 //Set PDU mode
247 { SET_PDU_MODE, "AT+CMGF=0\r\n", 100,
248 FALSE, 0,
249 gsmd_utils_handler_ok, NULL, SIM_READY, NULL},
251 //Test modem is alive
252 { SOFT_RESET, "ATZ\r\n", 5000,
253 FALSE, 3,
254 gsmd_modem_handler_alive, NULL, SIM_UNKNOWN, NULL},
256 { 0, NULL, 100, TRUE, 1,
257 NULL, NULL, SIM_UNKNOWN, NULL },
259 }, *command_p = commands;
262 static const SymbolTable
263 symbols[] =
265 { "TIME_OUT", SYMBOL_TIME_OUT,},
266 { "OK", SYMBOL_OK, },
267 { "ERROR", SYMBOL_ERROR, },
268 { "RING", SYMBOL_RING, },
269 { "NO", SYMBOL_NO, },
270 { "ANSWER", SYMBOL_ANSWER, },
271 { "CARRIER", SYMBOL_CARRIER, },
272 { "BUSY", SYMBOL_BUSY, },
273 { "READY", SYMBOL_READY, },
274 { "CME", SYMBOL_CME, },
275 { "CMS", SYMBOL_CMS, },
276 { "CPIN", SYMBOL_CPIN, },
277 { "CPAS", SYMBOL_CPAS, },
278 { "CSQ", SYMBOL_CSQ, },
279 { "CMUT", SYMBOL_CMUT, },
280 { "CLIP", SYMBOL_CLIP, },
281 { "CCWA", SYMBOL_CCWA, },
282 { "CRING", SYMBOL_CRING, },
283 { "CMTI", SYMBOL_CMTI, },
284 { "CRSL", SYMBOL_CRSL, },
285 { "CMGW", SYMBOL_CMGW, },
286 { "PIN", SYMBOL_PIN, },
287 { "PUK", SYMBOL_PUK, },
288 { NULL, 0, },
289 }, *symbol_p = symbols;
293 * @brief Creates modem interface and sets pointers
295 * @param modem modem whose interface to create
296 * @return
298 void gsmd_modem_set_up_interface(Modem *modem)
300 modem->modem_if = g_new0(ModemInterface, 1);
301 modem->modem_if->priv = (gpointer)modem;
305 * @brief Function used to free gvalues stored in modem's cache
307 * @param data pointer to gvalue to be freed
309 static void gsmd_modem_cache_destroy(gpointer data)
311 GValue *value = data;
312 g_value_unset(value);
313 g_free(value);
317 * @brief Allocates a new modem struct
319 * @return newly created modem struct
321 Modem* gsmd_modem_allocate()
323 ModemInterface *modem = NULL;
324 Modem *modem_priv = g_try_new0 (Modem, 1);
326 if (!modem_priv)
328 g_warning("%s : Failed to allocate a modem structure.", __func__);
329 return NULL;
332 gsmd_modem_set_up_interface(modem_priv);
334 modem = modem_priv->modem_if;
336 modem_priv->vendor_handle = NULL;
337 modem_priv->is_timeout = FALSE;
339 modem->status = MODEM_UNINITIALIZED;
340 //modem->sim_status = SIM_UNKNOWN;
341 modem->devices = NULL;
345 modem->calls = NULL;
347 modem->scanner = g_scanner_new (NULL);
348 if (!modem->scanner)
350 g_warning("%s : Failed to set a scanner for the modem.", __func__);
351 goto error;
354 modem->scanner->config->symbol_2_token = TRUE;
355 modem->scanner->config->numbers_2_int = TRUE;
356 modem->scanner->config->skip_comment_single = FALSE;
357 modem->scanner->config->cpair_comment_single = "";
358 /* the character to skip*/
360 //Add commands list into hash table
361 modem_priv->commands_table = g_hash_table_new(NULL,NULL);
362 if (!modem_priv->commands_table)
364 g_warning("%s : Failed to set command table for the modem.", __func__);
365 goto error;
367 gint i=0;
368 for (i=0; i < INTERFACE_LAST; i++)
370 modem->caches[i] = g_hash_table_new_full(NULL,
371 g_str_equal,
372 NULL,
373 gsmd_modem_cache_destroy);
375 gsmd_utils_table_insert_int(modem->caches[INTERFACE_NETWORK],
376 GSMD_MODEM_KEY_NETWORK_STATUS,
377 NETWORK_UNKNOWN);
379 modem->call = g_try_new0 (CallInterface, 1);
380 if (!modem->call)
381 goto error;
382 modem->call_ipc = g_try_new0 (CallIPCInterface, 1);
383 if (!modem->call_ipc)
384 goto error;
385 modem->sms = g_try_new0 (SMSInterface, 1);
386 if (!modem->sms)
387 goto error;
388 modem->sms_ipc = g_try_new0 (SMSIPCInterface, 1);
389 if (!modem->sms_ipc)
390 goto error;
391 modem->device= g_try_new0 (DeviceInterface, 1);
392 if (!modem->device)
393 goto error;
394 modem->device_ipc= g_try_new0 (DeviceIPCInterface, 1);
395 if (!modem->device_ipc)
396 goto error;
398 modem->network = g_try_new0 (NetworkInterface, 1);
399 if (!modem->network)
400 goto error;
401 modem->network_ipc = g_try_new0 (NetworkIPCInterface, 1);
402 if (!modem->network_ipc)
403 goto error;
404 modem->pdp = g_try_new0 (PDPInterface, 1);
405 if (!modem->pdp)
406 goto error;
407 modem->pdp_ipc = g_try_new0 (PDPIPCInterface, 1);
408 if (!modem->pdp_ipc)
409 goto error;
410 modem->sim = g_try_new0 (SIMInterface, 1);
411 if (!modem->sim)
412 goto error;
413 modem->sim_ipc = g_try_new0 (SIMIPCInterface, 1);
414 if (!modem->sim_ipc)
415 goto error;
418 return modem_priv;
420 error:
421 g_warning("%s: error", __func__);
422 if ( modem )
424 g_free (modem->device);
425 g_free (modem->device_ipc);
426 g_free (modem->sms);
427 g_free (modem->sms_ipc);
428 g_free (modem->call);
429 g_free (modem->call_ipc);
430 g_free (modem->network);
431 g_free (modem->network_ipc);
432 g_free (modem->pdp);
433 g_free (modem->pdp_ipc);
434 g_free (modem->sim);
435 gint i=0;
436 for (i=0; i < INTERFACE_LAST; i++)
438 g_hash_table_destroy (modem->caches[i]);
440 g_free (modem);
442 if ( modem_priv )
444 if (modem_priv->commands_table)
445 g_hash_table_destroy (modem_priv->commands_table);
446 if (modem_priv->modem_if->scanner)
447 g_scanner_destroy (modem->scanner);
448 g_free (modem_priv);
450 return NULL;
455 * @brief Loads and initializes vendor
456 * @param modem modem to attach the handler
457 * @param vendor the vendor's name. E.g. "telit"
458 * @return TRUE if load was successful, otherwise FALSE
460 gboolean gsmd_modem_load_vendor_handler (Modem* modem, const gchar* vendor)
462 VendorInit vendor_init;
463 gpointer vendor_init_symbol = NULL;;
464 GString* vendor_name = NULL;
465 const gchar *plugindir = g_getenv("GSMD2VENDORPLUGINDIR");
466 //perform vendor init
467 //vendor_telit_unsolicite_handler_init (modem);
468 if (!vendor)
469 return FALSE;
471 g_debug("%s : Vendor: %s", __func__, vendor);
472 vendor_name = g_string_new ("");
474 if ( !plugindir )
476 plugindir = GSMD2PLUGINDIR;
478 g_string_printf (vendor_name, "vendor%s", vendor);
479 gchar *plugin_path = g_module_build_path(plugindir, vendor_name->str);
480 modem->vendor_handle = g_module_open (plugin_path ,G_MODULE_BIND_MASK);
481 g_string_free (vendor_name, TRUE);
482 vendor_name = NULL;
483 g_free( plugin_path );
484 plugin_path = NULL;
485 if (!modem->vendor_handle)
487 g_critical ("Vendor %s not found from %s",vendor, plugindir);
488 return FALSE;
491 if (!g_module_symbol (modem->vendor_handle,"vendor_handle_init", &vendor_init_symbol) )
493 g_critical ("'vendor_handle_init' symbol %s not found from %s",vendor, plugindir);
494 g_module_close(modem->vendor_handle);
495 modem->vendor_handle = NULL;
496 return FALSE;
498 vendor_init = (VendorInit)vendor_init_symbol;
499 return vendor_init (modem->vendor, modem->modem_if);
503 * Finds the correct vendor handler
504 * @param modem modem to attach the handler
505 * @param vendor the vendor's name. E.g. "telit"
506 * @return TRUE if load was successful, otherwise FALSE
508 gboolean gsmd_modem_load_serial_plugin (Modem* modem, const gchar* plugin)
510 g_debug("%s : Serial plugin: %s", __func__, plugin);
511 SerialPluginInit serial_init = NULL;
512 gpointer serial_init_symbol = NULL;
513 GString* plugin_name = NULL;
514 //perform vendor init
515 //plugin_telit_unsolicite_handler_init (modem);
516 if (!plugin)
518 return FALSE;
520 plugin_name = g_string_new ("");
522 const gchar *plugindir = g_getenv("GSMD2SERIALPLUGINDIR");
523 if ( !plugindir )
525 plugindir = GSMD2PLUGINDIR;
527 g_string_printf (plugin_name, "serial%s", plugin);
528 gchar *plugin_path = g_module_build_path(plugindir, plugin_name->str);
529 modem->serial_plugin_handle = g_module_open (plugin_path ,G_MODULE_BIND_MASK);
530 g_string_free (plugin_name, TRUE);
531 plugin_name = NULL;
532 g_free(plugin_path);
533 plugin_path = NULL;
534 if (!modem->serial_plugin_handle)
536 g_critical ("%s : Serial plugin %s not found from %s",__func__, plugin, plugindir);
537 return FALSE;
539 if (!g_module_symbol(modem->serial_plugin_handle,"serial_plugin_init", &serial_init_symbol) )
541 g_critical ("%s : Serial plugin %s init function not found",__func__, plugin);
542 g_module_close(modem->serial_plugin_handle);
543 modem->serial_plugin_handle = NULL;
544 return FALSE;
546 g_module_make_resident(modem->serial_plugin_handle);
547 serial_init = (SerialPluginInit)serial_init_symbol;
549 modem->serial_if = g_new0(SerialInterface, 1);
551 return serial_init (modem->serial_if, modem->modem_if);
555 * @brief Adds default scanner symbols and registers at commands to modem struct
557 * @param modem modem to initialize
559 void gsmd_modem_init_standard_at_handler(ModemInterface* modem)
561 g_debug("%s", __func__);
563 while (symbol_p->symbol_name)
565 g_scanner_add_symbol (modem->scanner, symbol_p->symbol_name,
566 GINT_TO_POINTER(symbol_p->symbol_token));
567 symbol_p++;
570 while (command_p->command)
572 gsmd_modem_register_command (modem,command_p);
573 command_p++;
578 * @brief Function to call when command needs to be cancelled prematurely
580 * Removes timeout and calls error_function
582 * @param data pointer to atcommand context to be cancelled
583 * @param user_data not used
585 void gsmd_modem_clear_queue_func(gpointer data,
586 gpointer user_data)
588 AtCommandContext *at = (AtCommandContext*)data;
589 gsmd_utils_send_error(at, GSMD_ERROR_RESET, "Reseting modem");
590 if (at->timeout_event_id != 0)
592 g_debug("%s : Removing timeout id: %d",
593 __func__,
594 at->timeout_event_id);
596 g_source_remove(at->timeout_event_id);
598 gsmd_at_command_context_free(at);
603 * @brief Closes all serial ports
605 * @param modem pointer to modem whose serial ports to close
607 void gsmd_modem_close_serial_ports(Modem *modem)
609 g_debug("%s",__func__);
610 gint i=0;
612 if (modem->serial_devices)
614 for (i=0;i<modem->serial_devices->len;i++)
616 SerialDevice *serial = g_array_index(modem->serial_devices,SerialDevice*,i);
617 if (modem->serial_if->close_serial)
619 modem->serial_if->close_serial(modem->serial_if,serial->serial->fd);
621 gsmd_serial_free(serial->serial);
622 g_queue_foreach(serial->commandQueue,gsmd_modem_clear_queue_func,NULL);
623 g_queue_free(serial->commandQueue);
625 g_array_free(modem->serial_devices,TRUE);
626 modem->serial_devices = NULL;
629 modem->modem_if->status = MODEM_UNINITIALIZED;
633 * @brief Initializes modem's serial ports
635 * @param modem modem whose serial ports to initialize
636 * @return TRUE if they were intialized
638 gboolean gsmd_modem_init_serial_ports(Modem *modem)
640 g_debug("%s",__func__);
642 //Make sure we aren't initializing the modem twice
643 if (modem->modem_if->status != MODEM_UNINITIALIZED)
644 return FALSE;
646 modem->modem_if->status = MODEM_SERIAL_INIT;
648 gint i=0;
649 g_assert(modem);
650 g_assert(modem->modem_if);
651 g_assert(modem->modem_if->devices);
653 modem->serial_devices = g_array_new(TRUE,TRUE,sizeof(SerialDevice*));
656 GList *device_it = modem->modem_if->devices;
657 while (device_it)
659 gchar *device = device_it->data;
660 g_debug("Adding device %s",device);
661 gint device_fd = modem->serial_if->open_serial( modem->serial_if, device);
663 if ( !device_fd )
665 g_warning ("%s : init_serial failed\n",
666 __func__);
667 gsmd_modem_close_serial_ports (modem);
668 return FALSE;
671 Serial *serial = gsmd_serial_open_port (device_fd);
672 if (!serial)
674 g_warning("%s : Failed to open device %s",
675 __func__,
676 device);
677 //open failed, release the resource
678 gsmd_modem_close_serial_ports (modem);
679 return FALSE;
681 SerialDevice *serial_device = g_new0(SerialDevice, 1);
682 serial_device->serial = serial;
683 serial_device->commandQueue = g_queue_new();
684 serial_device->modem = modem;
685 serial_device->device_index = i;
687 gsmd_serial_register_trigger( serial, "\r\n",
688 &gsmd_modem_data_in,
689 (gpointer)serial_device,
690 FALSE);
691 gsmd_serial_register_trigger( serial, "\r",
692 &gsmd_modem_data_in,
693 (gpointer)serial_device,
694 FALSE);
695 gsmd_serial_register_trigger( serial, "\n",
696 &gsmd_modem_data_in,
697 (gpointer)serial_device,
698 FALSE);
700 g_array_append_val(modem->serial_devices,serial_device);
701 device_it = g_list_next(device_it);
702 i++;
705 if ( modem->vendor->wakeup_modem )
707 if (modem->vendor->wakeup_modem(modem->vendor))
709 gsmd_modem_post_alive_test(modem->modem_if,TRUE);
712 else
714 gsmd_modem_post_alive_test(modem->modem_if,TRUE);
717 return TRUE;
721 * @brief Opens a modem device.
723 * Before using modem, this function must be called to open modem and
724 * get modem device struct pointer
726 * @param devices list of device file names
727 * @param vendor The libname name of the vendor
728 * for example "telit"
729 * @param serial_plugin The libname name of the serial plugin
730 * for example "fsomuxer"
731 * @param no_cache should caching be used(FALSE) or not (TRUE)
732 * @param conf configuration file
733 * @param ipc_init pointer to ipc initialization function
734 * @param interface_devices a list that maps interfaces to devices
735 * @return pointer to newly created modem interface struct
737 ModemInterface* gsmd_modem_open (gchar **devices,
738 const gchar* vendor,
739 const gchar* serial_plugin,
740 gboolean no_cache,
741 GKeyFile *conf,
742 IPCInit ipc_init,
743 int *interface_devices)
745 // g_type_init ();
746 Modem* modem = gsmd_modem_allocate();
747 modem->modem_if->no_cache = no_cache;
748 modem->modem_if->conf_file = conf;
749 gchar *device = NULL;
752 gint i = 0;
755 if (!modem)
756 return NULL;
758 gsmd_modem_init (modem->modem_if);
760 modem->modem_if->ipc_data = ipc_init(modem->modem_if);
762 if (!modem->modem_if->ipc_data)
764 g_warning("Cannot initialize ipc!\n");
765 return NULL;
769 if (!gsmd_modem_load_vendor_handler (modem, vendor))
771 g_warning ("Can't find the vendor or vendor init failed: %s\n", vendor);
772 return NULL;
775 if (!gsmd_modem_load_serial_plugin (modem, serial_plugin))
777 g_warning ("Can't find the serial plugin or plugin init failed: %s\n", serial_plugin);
778 return NULL;
781 gsmd_modem_init_standard_at_handler(modem->modem_if);
783 if ( modem->serial_if->get_ports )
785 modem->modem_if->devices = modem->serial_if->get_ports(modem->serial_if);
786 if ( modem->modem_if->devices )
788 g_debug("%s : Using ports given by serial plugin", __func__);
791 if ( !modem->modem_if->devices )
793 g_debug("%s : Using ports given from command line or configuration file", __func__);
794 i=0;
795 device = devices[i];
796 while (device)
798 g_debug("%s : '%s'", __func__, device);
799 modem->modem_if->devices = g_list_append(modem->modem_if->devices,device);
800 i++;
801 device = devices[i];
805 if (!gsmd_modem_init_serial_ports(modem))
806 return NULL;
809 if ( !gsmd_modem_assign_device_indices(modem->modem_if,interface_devices) )
811 gsmd_modem_free(modem->modem_if);
812 return NULL;
815 return modem->modem_if;
819 * @brief Changes sim's status
821 * Calls gsmd_modem_general_at_init_sim_ready when appropriate
823 * @param modem modem whose sim status to change
824 * @param status new status to set
826 void gsmd_modem_change_sim_status(ModemInterface *modem, SIMStatus status)
828 g_assert( modem );
829 Modem *modem_priv = (Modem*)modem->priv;
830 if ( modem->sim_status < SIM_READY
831 && status >= SIM_READY)
833 if ( modem_priv->vendor->init_at_sim_ready )
835 modem_priv->vendor->init_at_sim_ready (modem_priv->vendor);
837 else
839 gsmd_modem_general_at_init_sim_ready(modem);
842 modem->sim_status = status;
846 * @brief Frees all serial devices within the modem
848 * @param modem modem whose serial devices to free
850 void gsmd_modem_serial_devices_free(Modem *modem)
852 gint i=0;
853 if (modem->serial_devices)
855 for (i=0;i<modem->serial_devices->len;i++)
857 SerialDevice *device = g_array_index(modem->serial_devices,SerialDevice*,i);
858 /* //ask vendor to close it */
859 /* if (modem->vendor->close_serial) */
860 /* modem->vendor->close_serial(modem->vendor, */
861 /* serial->fd); */
862 /* else //or close it ourselves */
863 /* close(serial->fd); */
864 gsmd_serial_free(device->serial);
865 g_queue_foreach(device->commandQueue,gsmd_modem_clear_queue_func,NULL);
866 g_queue_free(device->commandQueue);
870 g_array_free(modem->serial_devices,FALSE);
871 modem->serial_devices = NULL;
876 * @brief Frees modem struct
878 * @param modem The pointer to the modem device struct which to be close
880 void gsmd_modem_free (ModemInterface* modem)
882 Modem *modem_priv = (Modem*)modem->priv;
883 g_assert (modem_priv);
884 g_debug("%s", __func__);
885 g_assert (modem);
886 if (modem_priv->vendor_handle)
887 dlclose (modem_priv->vendor_handle);
888 g_free (modem->call);
889 g_free (modem->call_ipc);
891 g_free (modem->sms);
892 g_free (modem->sms_ipc);
894 gsmd_network_deinitialize(modem);
895 g_free (modem->network);
896 g_free (modem->network_ipc);
898 g_free (modem->device);
899 g_free (modem->device_ipc);
901 g_free (modem->pdp);
902 g_free (modem->pdp_ipc);
905 gsmd_sim_deinitialize(modem);
906 g_free (modem->sim);
907 g_free (modem->sim_ipc);
909 gint i=0;
910 for (i=0; i < INTERFACE_LAST; i++)
912 g_hash_table_destroy (modem->caches[i]);
915 g_scanner_destroy (modem->scanner);
916 g_hash_table_destroy (modem_priv->commands_table);
918 gsmd_modem_serial_devices_free(modem_priv);
921 GList *list = modem->calls;
922 while ( list )
924 Call *call = (Call*)list->data;
925 g_free(call);
926 list = g_list_next( list );
928 g_list_free(modem->calls);
929 modem->calls = NULL;
931 g_key_file_free(modem->conf_file);
933 g_free (modem);
937 /************************service function**************************************/
940 * @brief Get serial device with specified index
942 * @param modem pointer to modem whose serial device to get
943 * @param device_index index of the device to get
944 * @return serial device or NULL if none found
946 SerialDevice* gsmd_modem_get_serial_device_index(Modem *modem,
947 guint device_index)
949 g_assert(modem);
950 g_assert(modem->serial_devices);
951 if ( modem->serial_devices->len > device_index )
953 return g_array_index(modem->serial_devices, SerialDevice*, device_index);
955 else
957 g_warning("%s : Invalid index: %d. We have %d device(s)",
958 __func__, device_index, modem->serial_devices->len);
959 g_assert(FALSE);
961 return NULL;
965 * @brief Gets specific interface's serial device
967 * @param modem modem whose serial devices to get
968 * @param interface interface whose serial to get
969 * @return serialdevice mapped to specified interface
971 SerialDevice* gsmd_modem_get_serial_device(Modem *modem,InterfaceType interface)
973 g_assert(modem);
974 g_return_val_if_fail(modem->serial_devices, NULL);
975 guint device_index = modem->modem_if->interface_devices[interface];
976 return gsmd_modem_get_serial_device_index(modem, device_index);
980 * @brief Sends initializing at commands to the modem
982 * @param modem modem to initialize
984 void gsmd_modem_general_at_init (ModemInterface* modem)
986 g_assert(modem);
987 gsmd_modem_post_at_command_id (modem,
988 DISABLE_ECHO,
989 NULL, NULL, NULL, NULL,
990 INTERFACE_GENERAL,
991 NULL);
993 gsmd_modem_post_at_command_id (modem,
994 ENABLE_CMEE,
995 NULL, NULL, NULL, NULL,
996 INTERFACE_GENERAL,
997 NULL);
999 gsmd_modem_post_at_command_id( modem,
1000 IMEI_QUERY,
1001 NULL, NULL, NULL, NULL,
1002 INTERFACE_DEVICE,
1003 NULL);
1005 gsmd_modem_post_at_command_id( modem,
1006 MANUFACTURER_QUERY,
1007 NULL, NULL, NULL, NULL,
1008 INTERFACE_DEVICE,
1009 NULL);
1011 gsmd_modem_post_at_command_id( modem,
1012 SW_REVISION_QUERY,
1013 NULL, NULL, NULL, NULL,
1014 INTERFACE_DEVICE,
1015 NULL);
1017 gsmd_modem_post_at_command_id( modem,
1018 MODEL_QUERY,
1019 NULL, NULL, NULL, NULL,
1020 INTERFACE_DEVICE,
1021 NULL);
1023 gsmd_modem_post_at_command_id (modem,
1024 PIN_QUERY,
1025 NULL, NULL, NULL, NULL,
1026 INTERFACE_GENERAL,
1027 NULL);
1030 * @brief Sends initializing at commands that need sim_status >=
1031 * SIM_READY to the modem
1033 * @param modem modem to initialize
1035 void gsmd_modem_general_at_init_sim_ready (ModemInterface* modem)
1037 g_assert(modem);
1038 gsmd_modem_post_at_command_id (modem,
1039 ENABLE_CLIP,
1040 NULL,NULL,NULL,NULL,
1041 INTERFACE_GENERAL,
1042 NULL);
1044 gsmd_modem_post_at_command_id (modem,
1045 ENABLE_CNMI,
1046 NULL, NULL, NULL, NULL,
1047 INTERFACE_GENERAL,
1048 NULL);
1050 gsmd_modem_post_at_command_id (modem,
1051 SET_PDU_MODE,
1052 NULL, NULL, NULL, NULL,
1053 INTERFACE_GENERAL,
1054 NULL);
1055 gsmd_modem_post_at_command_id (modem,
1056 SET_OP_QUERY_REPLY,
1057 NULL, NULL, NULL, NULL,
1058 INTERFACE_GENERAL,
1059 NULL);
1061 gsmd_modem_post_at_command_id (modem,
1062 ENABLE_CCWA,
1063 NULL, NULL, NULL, NULL,
1064 INTERFACE_GENERAL,
1065 NULL);
1067 gsmd_modem_post_at_command_id (modem,
1068 CUR_CALLS_QUERY,
1069 NULL, NULL, NULL, NULL,
1070 INTERFACE_GENERAL,
1071 NULL);
1076 * @brief Get AT command processed currently
1078 * @param modem modem device struct pointer
1079 * @param device_index index of the device whose command to get
1080 * @return atcommand that is currently processed
1082 AtCommandContext* gsmd_modem_get_current_at_command_index (ModemInterface *modem,
1083 guint device_index)
1085 g_assert( modem );
1086 Modem *modem_priv = (Modem*)modem->priv;
1087 g_assert (modem_priv);
1088 g_assert (modem_priv->serial_devices);
1089 SerialDevice *device = gsmd_modem_get_serial_device_index( modem_priv, device_index);
1090 if (device)
1091 return g_queue_peek_head(device->commandQueue);
1092 return NULL;
1096 * @brief Get the AT command that is processed at the moment
1098 * @param modem modem device struct pointer
1099 * @param interface which interface's command to get
1100 * @return at command that is currently processed
1102 AtCommandContext* gsmd_modem_get_current_at_command (ModemInterface *modem,
1103 InterfaceType interface)
1105 return gsmd_modem_get_current_at_command_index(modem,
1106 gsmd_modem_get_interface_device_index(modem,
1107 interface));
1111 * @brief Send AT command to front of the queue
1113 * Diffrent from modem_add_command, forces command to be the first in
1114 * command queue.
1116 * @param modem modem device struct pointer
1117 * @param at AT command to send
1118 * @param interface which interface's queue is this command forced to
1121 void gsmd_modem_send_command_force_next (Modem *modem,
1122 AtCommandContext *at,
1123 InterfaceType interface)
1126 g_assert( modem );
1127 g_assert( at );
1128 SerialDevice *device = gsmd_modem_get_serial_device( modem, interface);
1130 if (device)
1132 AtCommandContext *current_at = g_queue_pop_head ( device->commandQueue );
1133 g_queue_push_tail ( device->commandQueue, at );
1134 if ( current_at )
1136 g_queue_push_head (device->commandQueue, current_at );
1143 * @brief Adds an modem alive test command (AT) or soft reset (ATZ) to the front
1144 * of the queue ignoring uncancellable commands and processes it
1146 * @param modem_if pointer to modem device struct
1147 * @param reset if TRUE, send ATZ instead of AT
1149 void gsmd_modem_post_alive_test (ModemInterface *modem_if, gboolean reset)
1151 g_debug("%s",__func__);
1152 g_assert(modem_if);
1153 Modem *modem = (Modem*)modem_if->priv;
1154 g_assert(modem);
1155 g_assert(modem->serial_devices);
1156 SerialDevice *device = gsmd_modem_get_serial_device( modem, INTERFACE_GENERAL);
1157 g_assert(device);
1159 AtCommandContext *at = NULL;
1160 if (reset)
1162 g_assert(modem->modem_if->status < MODEM_READY);
1163 at = gsmd_at_command_context_new_from_id(modem->modem_if,
1164 SOFT_RESET,
1165 NULL,
1166 NULL,
1167 NULL,
1168 NULL,
1169 NULL);
1171 else
1173 at = gsmd_at_command_context_new_from_id(modem->modem_if,
1174 REPLY_COMMAND,
1175 NULL,
1176 NULL,
1177 NULL,
1178 NULL,
1179 NULL);
1181 g_queue_push_head (device->commandQueue, at);
1182 gsmd_modem_process_next_command(modem,INTERFACE_GENERAL);
1189 * @brief Add an AT command to command queue
1191 * @param modem pointer to modem device struct
1192 * @param at custom at command to add
1193 * @param interface interface to post the command to
1194 * @param cancel should we try to cancel the current command and
1195 * place this command first (or second if current command can't
1196 * be cancelled) in queue.
1197 * @return TRUE if command was posted properly
1199 static
1200 gboolean gsmd_modem_post_at_command_internal ( ModemInterface *modem,
1201 AtCommandContext *at,
1202 InterfaceType interface,
1203 gboolean cancel)
1205 g_assert(modem);
1206 g_assert (at);
1207 gsmd_utils_print_data(__func__,"command: ",at->command->command);
1208 Modem *modem_priv = (Modem*)modem->priv;
1209 if ( !modem_priv->serial_devices )
1211 //If serial ports aren't initialized then initialize them
1212 gsmd_modem_init_serial_ports(modem_priv);
1214 // modem is not ready so fail this request
1217 if (modem->status < MODEM_INITIALIZING)
1219 gsmd_utils_print_data(__func__,
1220 "Modem is uninitialized, unable to add command: ",
1221 at->command->command);
1223 g_debug("%s : Unable to add command %s because modem is uninitialized",
1224 __func__,at->command->command);
1226 gsmd_utils_send_error(at, GSMD_ERROR_RESET, "Modem not ready yet");
1227 gsmd_at_command_context_free(at);
1228 return TRUE;
1231 SerialDevice *device = gsmd_modem_get_serial_device( modem_priv,
1232 interface);
1234 if (!device)
1236 g_warning("%s : improper device index",__func__);
1237 return FALSE;
1239 AtCommandContext *current_at = gsmd_modem_get_current_at_command ( modem,
1240 interface);
1242 //If no commands in queue, insert this one and process the queue
1243 if (!current_at)
1245 if ( cancel )
1247 g_debug("%s : No commands in queue, no need to cancel",
1248 __func__);
1250 g_queue_push_tail (device->commandQueue, at);
1251 gsmd_modem_process_next_command(modem_priv,interface);
1252 return TRUE;
1255 if ( cancel )
1258 //if there are commands in the queue and we can cancel the first
1259 // one, break it (+++) and push ours first
1260 if (current_at->command->cancellable)
1262 g_debug("%s : Cancelling current command",__func__);
1263 //Remove timeout for the previous command
1264 if (current_at->timeout_event_id != 0)
1266 g_debug("%s : Removing timeout id: %d",
1267 __func__,
1268 current_at->timeout_event_id);
1270 g_source_remove(current_at->timeout_event_id);
1273 g_queue_push_head (device->commandQueue, at);
1274 gsmd_modem_serial_write_simple (modem,
1275 "+++\r\n",
1276 interface);
1278 //Process the new command
1279 gsmd_modem_process_next_command(modem_priv,interface);
1281 else //if the current command isn't cancellable,
1283 //push our new command second in line
1284 g_debug("%s : Current command can't be overridden, moving next in queue",
1285 __func__);
1286 g_queue_pop_head(device->commandQueue);
1287 g_queue_push_head(device->commandQueue, at);
1288 g_queue_push_head(device->commandQueue,current_at);
1293 else
1295 g_queue_push_tail (device->commandQueue, at);
1297 return TRUE;
1301 * @brief Add a custom AT command to command queue. Cancels the first
1302 * command if possible and tries to run this command as soon as possible.
1304 * @param modem pointer to modem device struct
1305 * @param at custom at command to add
1306 * @param interface interface to post the command to
1307 * @return result of gsmd_modem_post_at_command_internal
1309 gboolean gsmd_modem_post_at_command_and_cancel (ModemInterface *modem,
1310 AtCommandContext *at,
1311 InterfaceType interface)
1313 return gsmd_modem_post_at_command_internal(modem, at, interface, TRUE);
1317 * @brief Add an AT command to command queue
1319 * @param modem pointer to modem device struct
1320 * @param at custom at command to add
1321 * @param interface interface to post the command to
1322 * @return result of gsmd_modem_post_at_command_internal
1324 gboolean gsmd_modem_post_at_command ( ModemInterface *modem,
1325 AtCommandContext *at,
1326 InterfaceType interface)
1328 return gsmd_modem_post_at_command_internal(modem, at, interface, FALSE);
1333 * @brief Posts at command to the queue
1336 * @param modem pointer to modem interface
1337 * @param command_id id of the command to post
1338 * @param param parameter for the command
1339 * @param ipc_data ipc data
1340 * @param error_function error function to call incase an error is occurred
1341 * @param error_data data to pass with error_function call
1342 * @param interface interface to post the command to
1343 * @param handler_data if command creater wants to add data to at command
1344 * for the handler, it can create a new GHashTable and insert it there. If
1345 * no handler_data is specified then a new handler_data will be created
1346 * automatically.
1348 gboolean gsmd_modem_post_at_command_id ( ModemInterface* modem,
1349 AtCommandID command_id,
1350 const gchar *param,
1351 gpointer *ipc_data,
1352 ErrorFunction error_function,
1353 gpointer error_data,
1354 InterfaceType interface,
1355 GHashTable *handler_data)
1357 AtCommandContext *at = gsmd_at_command_context_new_from_id( modem,
1358 command_id,
1359 param,
1360 ipc_data,
1361 error_function,
1362 error_data,
1363 handler_data);
1364 return gsmd_modem_post_at_command (modem, at,interface);
1369 * @brief Posts at command to the front of the queue if possible
1371 * This command will cancel current command if possible and place itself
1372 * to the front of the command queue (or second if first can't be cancelled)
1374 * @param modem pointer to modem interface
1375 * @param command_id id of the command to post
1376 * @param param parameter for the command
1377 * @param ipc_data ipc data
1378 * @param error_function error function to call incase an error is occurred
1379 * @param error_data data to pass with error_function call
1380 * @param interface interface to post the command to
1381 * @param handler_data if command creater wants to add data to at command
1382 * for the handler, it can create a new GHashTable and insert it there. If
1383 * no handler_data is specified then a new handler_data will be created
1384 * automatically.
1386 gboolean gsmd_modem_post_at_command_id_and_cancel ( ModemInterface* modem,
1387 AtCommandID command_id,
1388 const gchar *param,
1389 gpointer *ipc_data,
1390 ErrorFunction error_function,
1391 gpointer error_data,
1392 InterfaceType interface,
1393 GHashTable *handler_data)
1395 AtCommandContext *at = gsmd_at_command_context_new_from_id( modem,
1396 command_id,
1397 param,
1398 ipc_data,
1399 error_function,
1400 error_data,
1401 handler_data);
1402 return gsmd_modem_post_at_command_and_cancel (modem, at,interface);
1410 * @brief Create new AT command context struct
1412 * @param atcmd at command to use
1413 * @param param parameter for the command
1414 * @param ipc_data ipc data
1415 * @param error_function error function to call incase an error is occurred
1416 * @param error_data data to pass with error_function call
1417 * @param handler_data if command creater wants to add data to at command
1418 * for the handler, it can create a new GHashTable and insert it there. If
1419 * no handler_data is specified then a new handler_data will be created
1420 * automatically.
1421 * @return newly created at command context
1423 AtCommandContext* gsmd_at_command_context_new (AtCommand *atcmd,
1424 const gchar *param,
1425 gpointer ipc_data,
1426 GHashTable *handler_data,
1427 ErrorFunction error_function,
1428 gpointer error_data)
1430 AtCommandContext *at = NULL;
1431 at = g_slice_new0 (AtCommandContext);
1432 if (!at)
1434 g_warning ("Failed to create new AtCommandContext.\n");
1435 return NULL;
1437 at->command = atcmd;
1440 at->command_param = g_strdup(param);
1441 at->retry_counter = atcmd->retry;
1442 at->timeout_event_id = 0;
1443 at->ipc_data = ipc_data;
1444 at->error_function = error_function;
1445 at->error_data = error_data;
1446 if (!handler_data)
1447 at->handler_data = gsmd_utils_create_hash_table();
1448 else
1449 at->handler_data = handler_data;
1453 if ( at->error_function && !at->error_data)
1455 g_warning("%s : AT command '%s' has error function but no error data!",
1456 __func__, atcmd->command);
1459 return at;
1464 * @brief Creates a new at command context from at command id
1466 * @param modem Modem whose commands to use
1467 * @param cmd_id command's id
1468 * @param param parameter for the command
1469 * @param ipc_data ipc data
1470 * @param error_function error function to call incase an error is occurred
1471 * @param error_data data to pass with error_function call
1472 * @param handler_data if command creater wants to add data to at command
1473 * for the handler, it can create a new GHashTable and insert it there. If
1474 * no handler_data is specified then a new handler_data will be created
1475 * automatically.
1476 * @return newly created at command context
1478 AtCommandContext* gsmd_at_command_context_new_from_id (ModemInterface *modem,
1479 AtCommandID cmd_id,
1480 const gchar *param,
1481 gpointer ipc_data,
1482 ErrorFunction error_function,
1483 gpointer error_data,
1484 GHashTable *handler_data)
1486 Modem *modem_priv = (Modem*)modem->priv;
1487 AtCommandContext *at = NULL;
1488 AtCommand *command = (AtCommand *) g_hash_table_lookup(modem_priv->commands_table,
1489 GINT_TO_POINTER(cmd_id));
1491 g_assert(command);
1492 at = gsmd_at_command_context_new(command,
1493 param,
1494 ipc_data,
1495 handler_data,
1496 error_function,
1497 error_data);
1498 return at;
1502 * @brief Free the AT command context struct
1504 * @param at The AT command context pointer
1506 void gsmd_at_command_context_free (AtCommandContext* at)
1508 if (at== NULL) return;
1509 if (at->command_param)
1510 g_free(at->command_param);
1512 if (at->command->free_function)
1514 at->command->free_function(at);
1516 if ( at->handler_data )
1518 g_hash_table_destroy(at->handler_data);
1520 g_slice_free (AtCommandContext,at);
1524 * @brief Function called after a command has been finished.
1526 * AtCommand will be removed from queue and freed.
1527 * If gsm modem failed to respond to command, AT command can be
1528 * sent to gsm modem to test weither it is still alive. This is
1529 * done when test_alive is TRUE.
1531 * @param modem pointer to the modem
1532 * @param interface device whose command to finish
1533 * @param test_alive should test alive command be sent
1535 static void gsmd_modem_finish_command (Modem* modem,
1536 InterfaceType interface,
1537 gboolean test_alive)
1539 /* g_debug("%s\n",__func__); */
1540 SerialDevice *device = gsmd_modem_get_serial_device( modem, interface);
1541 if (!device)
1543 return;
1546 GQueue *queue = device->commandQueue;
1548 AtCommandContext *at = g_queue_pop_head (queue);
1550 if (at)
1552 /* gsmd_utils_print_data(__func__, */
1553 /* "Removing command ", */
1554 /* at->command->command); */
1556 //g_debug("%s : %s",__func__,at->command->command);
1557 if (at->timeout_event_id != 0)
1559 /* g_debug("%s : Removing timeout id: %d", __func__, at->timeout_event_id); */
1560 g_source_remove(at->timeout_event_id);
1562 gsmd_at_command_context_free (at);
1565 else
1566 g_debug("Got no next command to finish\n");
1568 // if command handler (e.g. some vendor command)
1569 // marked the modem not alive
1570 if ( modem->modem_if->status == MODEM_RESET)
1572 gsmd_modem_close_serial_ports(modem);
1573 gsmd_modem_init_serial_ports(modem);
1575 else if (test_alive)
1577 g_debug("%s : testing that modem is alive",__func__);
1578 gsmd_modem_post_alive_test(modem->modem_if, FALSE);
1580 else
1582 /* g_debug("%s : processing next command",__func__); */
1583 gsmd_modem_process_next_command(modem,interface);
1588 * @brief Function to be called when serial has finished writing current command.
1590 * This indicates that the command has been written and to stop handler from
1591 * reading previous command's data.
1593 * For example on some modem's AT+CPIN? responds with CPIN: READY\\r\\nOK\\r\\n,
1594 * for others it returns with just CPIN: READY\\r\\n
1595 * If AT+CPIN command's handler were to assume that it never replies with OK,
1596 * and there were ATD command in the queue after AT+CPIN?. This would
1597 * cause ATD's handler to handle AT+CPIN's OK as an indicator that a call
1598 * has been initiated. gsmd_modem_data_in checks at->write_complete before
1599 * allowing at's handler to handle the data to prevent these errors.
1601 * @param write write data associated witht the command
1602 * @param data pointer to at command context
1604 static void gsmd_modem_write_complete(WriteData *write, gpointer data)
1606 g_debug("%s", __func__);
1607 AtCommandContext *at = (AtCommandContext*)data;
1608 at->write_complete = TRUE;
1612 * @brief Takes the next command from command queue and processes it
1614 * @param modem whose next command to process
1615 * @param interface which interface's next command to process
1617 static void gsmd_modem_process_next_command (Modem* modem, InterfaceType interface)
1619 /* g_debug("%s: device: %d",__func__,interface); */
1620 AtCommandContext *at = gsmd_modem_get_current_at_command ( modem->modem_if,
1621 interface );
1623 if (modem->vendor->command_prepare)
1625 at = modem->vendor->command_prepare(modem->vendor,modem->modem_if,at);
1626 if ( at )
1628 gsmd_utils_print_data(__func__,
1629 "Running command_prepare AT command: ",
1630 at->command->command);
1633 g_debug("%s : Running command_prepare AT command: '%s'",
1634 __func__,
1635 at->command->command);
1637 SerialDevice *device = gsmd_modem_get_serial_device(modem, interface);
1638 g_assert(device);
1639 GQueue *queue = device->commandQueue;
1640 g_queue_push_head (queue, at);
1645 //Get current command again to allow vendor to insert their own command
1646 at = gsmd_modem_get_current_at_command ( modem->modem_if,
1647 interface );
1649 if (!at)
1651 g_debug("%s : No commands in queue", __func__);
1652 return;
1654 //Most commands require PIN code to be set
1655 if (at->command->required_state > modem->modem_if->sim_status)
1657 g_debug("%s : sim status: %d, command '%s' requires: %d",
1658 __func__, modem->modem_if->sim_status,
1659 at->command->command, at->command->required_state);
1660 if (at->error_function)
1662 gsmd_utils_send_error(at,
1663 GSMD_ERROR_SIM_UNAUTHORIZED,
1664 "SIM AUTHENTICATION ERROR");
1667 gsmd_modem_finish_command(modem, interface, FALSE);
1668 return;
1671 AtCommandPrepare prepare = at->command->prepare;
1672 gboolean prepare_ok = TRUE;
1674 gsmd_utils_print_data(__func__,
1675 "Processing command ",
1676 at->command->command);
1679 modem->is_timeout = TRUE;//set the timeout flag
1681 GString *command = g_string_new (at->command->command);
1684 if (at->command_param)
1686 g_string_printf(command,at->command->command,
1687 at->command_param);
1692 if ( prepare )
1694 prepare_ok = (*prepare)(modem->modem_if);
1696 // TODO handle failed prepare
1697 if ( !prepare_ok )
1699 g_warning("%s: Prepare failed!", __func__);
1700 gsmd_utils_send_error(at,
1701 GSMD_ERROR_INTERNAL,
1702 "COMMAND PREPARE FAILED");
1703 gsmd_modem_finish_command(modem, interface, FALSE);
1704 return;
1707 WriteData *data = g_try_new0(WriteData,1);
1709 data->command = g_strdup(command->str);
1710 g_string_free(command,TRUE);
1711 command = NULL;
1715 data->timeout = at->command->timeout + TIME_OUT_PADDING;
1719 data->timeoutid = &at->timeout_event_id;
1720 data->timeout_data = gsmd_modem_get_serial_device(modem,
1721 interface);
1722 data->timeout_function = &gsmd_modem_timeout_handle;
1723 data->write_complete_data = at;
1724 data->write_complete_function = &gsmd_modem_write_complete;
1725 if (!gsmd_modem_serial_queue_write (modem->modem_if, data,interface))
1727 g_warning("%s: Queue write failed!", __func__);
1733 * @brief Initializes scanner for modem's input
1735 * @param modem whose scanner to initialize
1736 * @param str string to initialize scanner with
1738 static
1739 void gsmd_modem_scanner_init (ModemInterface *modem, GString *str)
1741 GScanner* scanner = modem->scanner;
1742 g_scanner_input_text (scanner, str->str, str->len);
1743 g_scanner_get_next_token (scanner);
1744 g_scanner_peek_next_token (scanner);
1747 static
1748 gboolean gsmd_modem_call_activity(gpointer data)
1750 ModemInterface *modem = (ModemInterface*)data;
1751 g_debug("%s", __func__);
1752 gsmd_modem_post_at_command_id (modem,
1753 CUR_CALLS_QUERY,
1754 NULL, NULL, NULL, NULL,
1755 INTERFACE_GENERAL,
1756 NULL);
1757 /* AtCommandContext *at = gsmd_at_command_context_new_from_id (modem, */
1758 /* CUR_CALLS_QUERY, */
1759 /* NULL, */
1760 /* NULL, */
1761 /* NULL, */
1762 /* NULL, */
1763 /* NULL); */
1764 return FALSE;
1767 static
1768 void gsmd_modem_monitor_call_activity(ModemInterface *modem)
1770 if ( modem->no_call_monitoring_needed )
1772 return;
1774 if (modem->call_monitor_timer != 0)
1776 g_source_remove(modem->call_monitor_timer);
1778 modem->call_monitor_timer = g_timeout_add(1000,&gsmd_modem_call_activity,modem);
1782 * @brief Function to handle data read from serial port
1784 * Checks SerialData on which device received the data, then
1785 * checks which was the last command sent to that interface
1786 * and runs that commands handler. If the handler doesn't understand
1787 * data, then unsolicite handler is called. This function also retries
1788 * the command if necessary.
1790 * @param buffer data that has been read
1791 * @param data pointer to SerialData containing information on
1792 * what was read (buffer)
1794 void gsmd_modem_data_in (GString *buffer, gpointer data )
1796 SerialDevice *serial = (SerialDevice*)data;
1797 Modem *modem = serial->modem;
1798 ModemInterface *modem_if = modem->modem_if;
1799 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
1800 AtCommandHandler handler = NULL;
1801 AtCommandContext *at = NULL;
1802 g_assert(modem);
1804 at = gsmd_modem_get_current_at_command_index ( modem_if, serial->device_index);
1805 if ( at && !at->write_complete)
1807 g_debug("%s : Got input, but current command has not been written.", __func__);
1808 at = NULL;
1810 if (at && at->command)
1812 if ( at->handler )
1814 handler = at->handler;
1816 else if ( at->command->handler )
1818 handler = at->command->handler;
1820 else
1822 handler = &gsmd_utils_handler_ok;
1825 GString *debug_str = g_string_new("");
1826 g_string_printf(debug_str,"Received from port %d: ",serial->device_index);
1828 gsmd_utils_print_data(__func__,
1829 debug_str->str,
1830 buffer->str);
1831 g_string_free(debug_str,TRUE);
1833 if ( modem->vendor->data_in )
1835 modem->vendor->data_in(modem_if, at, buffer);
1837 gsmd_modem_scanner_init (modem_if, buffer);
1839 if ( handler )
1842 status = (*handler)(modem_if, at, buffer);
1843 switch ( status )
1845 case AT_HANDLER_DONE:
1846 case AT_HANDLER_DONE_ERROR:
1847 //if handled then process next command if there is
1848 modem->is_timeout = FALSE;
1849 gsmd_modem_finish_command(modem,
1850 serial->device_index,
1851 FALSE);
1852 break;
1853 case AT_HANDLER_ERROR:
1854 modem->is_timeout = FALSE;
1855 gsmd_modem_finish_command(modem,
1856 serial->device_index,
1857 FALSE);
1858 // run unsolicite because we don't know if the message
1859 // belonged to handler or not
1860 gsmd_modem_handler_unsolicite( modem_if, NULL, buffer );
1861 break;
1862 case AT_HANDLER_NEED_MORE:
1863 break;
1864 case AT_HANDLER_DONT_UNDERSTAND:
1865 gsmd_modem_handler_unsolicite( modem_if, NULL, buffer );
1866 break;
1867 case AT_HANDLER_RETRY:
1868 gsmd_modem_retry_current_command( modem,
1869 serial->device_index );
1870 break;
1874 else
1876 if (gsmd_modem_handler_unsolicite( modem_if, NULL, buffer ) ==
1877 AT_HANDLER_DONE)
1878 modem->is_timeout = FALSE;
1890 * @brief Sms indicator parser, parses new sms's index
1892 * @param scanner whose data to parse
1893 * @return sms index
1895 gint gsmd_modem_sms_indicator_parse (GScanner* scanner)
1897 //TODO reimplement without assuming that we'll always get proper values
1898 g_debug("%s",__func__);
1899 //input: CMTI: "SM", 1
1900 gint pos = -1;
1901 if (scanner->token == SYMBOL_CMTI)
1903 g_scanner_get_next_token (scanner);// get ,
1904 g_scanner_get_next_token (scanner);//get s
1905 g_scanner_get_next_token (scanner);//get m
1906 g_scanner_get_next_token (scanner);//get ,
1907 pos = scanner->value.v_int;
1908 //g_message("sms pos is %d\n",pos);
1911 return pos;
1915 * @brief Registers a new command for the modem
1917 * @param modem modem to register the new command to
1918 * @param command command to register
1920 void gsmd_modem_register_command (ModemInterface *modem,
1921 const AtCommand *command)
1923 Modem *modem_priv = (Modem*)modem->priv;
1924 g_hash_table_insert(modem_priv->commands_table,
1925 GINT_TO_POINTER(command->cmd_id),
1926 (gpointer)command);
1930 * @brief Helper function to register serial trigger
1932 * @param modem pointer to modem interface
1933 * @param trigger_str trigger string
1934 * @param handler handler for received data that has the trigger string
1935 * @param handler_data user data for the handler
1936 * @param onetime is this a onetime trigger (discarded when trigged)
1937 * or permanent.
1938 * @param interface interface to apply the trigger to
1939 * @return newly created trigger. It is returned only so that it can
1940 * be deregistered with gsmd_serial_deregister_trigger
1942 Trigger* gsmd_modem_serial_register_trigger(ModemInterface *modem,
1943 const gchar *trigger_str,
1944 SerialDataIn handler,
1945 gpointer handler_data,
1946 gboolean onetime,
1947 InterfaceType interface)
1949 Modem *modem_priv = (Modem*)modem->priv;
1950 SerialDevice *device = gsmd_modem_get_serial_device(modem_priv, interface);
1951 if (!device)
1953 return NULL;
1956 if ( !handler )
1958 g_debug("%s : Using default handler/data", __func__);
1959 handler = &gsmd_modem_data_in;
1960 handler_data = device;
1963 return gsmd_serial_register_trigger(device->serial,
1964 trigger_str,
1965 handler,
1966 handler_data,
1967 onetime);
1971 * @brief Queue a new write to serial port
1973 * @param modem pointer to modem interface
1974 * @param data writedata that contains timeout information
1975 * and the data to write to serial port
1976 * @param interface which interface to be used to write command
1977 * @return FALSE if write failed
1979 gboolean gsmd_modem_serial_queue_write ( ModemInterface *modem,
1980 WriteData *data,
1981 InterfaceType interface)
1983 Modem *modem_priv = (Modem*)modem->priv;
1984 SerialDevice *device = gsmd_modem_get_serial_device(modem_priv, interface);
1985 if (device)
1987 if ( !gsmd_serial_queue_write( device->serial, data) )
1989 g_warning("%s : Error in serial.", __func__);
1990 gsmd_modem_close_serial_ports(modem_priv);
1991 return FALSE;
1994 else
1996 g_warning("%s : Writing data to improper serial device %d",
1997 __func__,
1998 device->device_index);
1999 return FALSE;
2002 return TRUE;
2006 * @brief Writes data directly to serial port
2008 * @param modem pointer to modem interface
2009 * @param data writedata that contains timeout information
2010 * and the data to write to serial port
2011 * @param interface which interface to be used to write command
2012 * @return FALSE if write failed
2014 gboolean gsmd_modem_serial_write ( ModemInterface *modem,
2015 WriteData *data,
2016 InterfaceType interface)
2018 Modem *modem_priv = (Modem*)modem->priv;
2019 SerialDevice *device = gsmd_modem_get_serial_device(modem_priv,
2020 interface);
2022 if (device)
2024 if ( !gsmd_serial_write( device->serial, data) )
2026 g_warning("%s : Error in serial.", __func__);
2027 gsmd_modem_close_serial_ports(modem_priv);
2028 return FALSE;
2031 else
2033 g_warning("%s : Writing data to improper serial device %d",
2034 __func__,
2035 device->device_index);
2036 return FALSE;
2038 return TRUE;
2043 * @brief Write command (or data) directly to serial port
2045 * @param modem modem device struct pointer
2046 * @param command AT command (or data) to write
2047 * @param interface which interface to be used to write command
2049 gboolean gsmd_modem_serial_write_simple ( ModemInterface *modem,
2050 const gchar *command,
2051 InterfaceType interface )
2053 WriteData *data = g_try_new0(WriteData,1);
2054 data->command = g_strdup(command);
2055 data->timeoutid = NULL;
2056 data->timeout = 0;
2057 data->timeout_data = NULL;
2058 data->timeout_function = NULL;
2059 return gsmd_modem_serial_write(modem,data,interface);
2063 * @brief Initializes modem
2065 * Calls all interface initializers aswell.
2067 * @param modem pointer to modem to initialize
2069 static void gsmd_modem_init (ModemInterface* modem)
2071 Modem *modem_priv = (Modem*)modem->priv;
2073 modem_priv->vendor = g_new0(VendorInterface, 1);
2074 gsmd_device_init (modem);
2075 gsmd_pdp_init (modem);
2076 gsmd_sim_init (modem);
2077 gsmd_network_init (modem);
2078 gsmd_call_init (modem);
2079 gsmd_sms_init (modem);
2084 * @brief Timeout handler
2086 * Fakes that modem has received TIME_OUT message and runs the
2087 * (timeouted) command's handler to handle that input. This allows
2088 * command handler's creator to perform actions before command is being
2089 * deleted. If handler doesn't return HANDLER_DONE or HANDLER_DONE_ERROR
2090 * then command's error function is called by this function.
2091 * Finally the command is removed.
2093 * @param data pointer to serialdata
2094 * @return always returns false
2096 static gboolean gsmd_modem_timeout_handle (gpointer data)
2098 SerialDevice *serial = (SerialDevice*) data;
2099 guint device_index = serial->device_index;
2100 AtCommandHandlerStatus handled = AT_HANDLER_DONT_UNDERSTAND;
2101 Modem* modem = serial->modem;
2102 AtCommandHandler handler;
2103 AtCommandContext *at = gsmd_modem_get_current_at_command_index ( modem->modem_if,
2104 device_index );
2106 if ( !at )
2108 g_warning("%s : No current command!",__func__);
2109 return FALSE;
2111 g_debug("%s: timeout id: %d, userdata: %p",__func__,at->timeout_event_id, data);
2112 // Setting timeout_event_id to 0 as it is removed when we return FALSE here.
2113 at->timeout_event_id = 0;
2114 g_assert( at->command);
2115 handler = at->command->handler;
2117 g_debug("Timeout on command %s\n",at->command->command);
2119 if (modem->is_timeout)
2121 modem->is_timeout = FALSE;//clear the timeout flag
2123 //If it has a handler, test if it can handle TIME_OUT
2124 if (handler)
2126 //copy TIME_OUT string to input buffer
2127 GString *timeout_buffer = g_string_new (TIME_OUT) ;//
2128 gsmd_modem_scanner_init (modem->modem_if, timeout_buffer);
2129 g_debug("Running command's handler for TIME_OUT");
2130 handled = (*handler)(modem->modem_if, at, timeout_buffer);
2131 g_string_free (timeout_buffer, TRUE);
2134 //if it couldn't handle it or didn't have a handler, let
2135 //unsolicite handler take care of it
2137 if (!handler || (handled != AT_HANDLER_DONE && handled != AT_HANDLER_DONE_ERROR))
2139 gsmd_utils_send_error(at,
2140 GSMD_ERROR_DEVICE_TIMEOUT,
2141 "TIMEOUT");
2145 gsmd_modem_finish_command(modem,device_index, TRUE);
2148 return FALSE;
2150 /***********************end of service function********************************/
2154 * @brief Change network status and use ipc data if new commands are issued
2156 * This function will post current operator query command if network's new
2157 * status is registered. This is used by getstatus fso method.
2159 * @param modem pointer to modem struct
2160 * @param status new network status
2161 * @param ipc_data ipc data used to post new commands if necessary
2162 * @param error_function error function to call if error occurs
2163 * @param error_data data to be supplied to error function call
2165 void gsmd_modem_change_network_status_data(ModemInterface *modem,
2166 NetworkStatus status,
2167 gpointer *ipc_data,
2168 ErrorFunction error_function,
2169 gpointer error_data)
2171 //TODO check that these assumptions are sane
2172 /* Simplified assumptions for actions for new statuses
2173 NETWORK_UNREGISTERED -> clear provider name, send empty status signal
2174 NETWORK_REGISTERED -> ask provider name and signal strength
2175 NETWORK_BUSY -> send empty status signal
2176 NETWORK_DENIED -> send empty status signal
2177 NETWORK_UNKNOWN -> send empty status signal
2178 NETWORK_ROAMING -> ask provider name and signal strength
2181 GString* message = g_string_new ("");
2182 g_string_printf(message, "%d",status);
2186 gsmd_utils_table_insert_int(modem->caches[INTERFACE_NETWORK],
2187 GSMD_MODEM_KEY_NETWORK_STATUS,
2188 status);
2190 switch (status)
2192 case NETWORK_UNREGISTERED:
2193 case NETWORK_BUSY:
2194 case NETWORK_DENIED:
2195 case NETWORK_UNKNOWN:
2197 if (modem->network->provider_name)
2199 g_string_free(modem->network->provider_name,TRUE);
2201 GHashTable *status = gsmd_utils_create_hash_table();
2202 gsmd_utils_table_insert_string(status,"provider","");
2203 gsmd_utils_table_insert_string(status,"registration",message->str);
2204 gsmd_utils_table_insert_int(status,"strength",0);
2205 modem->network->provider_name = g_string_new("");
2206 modem->network_ipc->status(modem->network_ipc,
2207 status);
2208 g_hash_table_destroy(status);
2210 break;
2211 case NETWORK_ROAMING:
2212 case NETWORK_REGISTERED:
2213 gsmd_modem_post_at_command_id( modem,
2214 CUR_OP_QUERY,
2215 NULL,
2216 ipc_data,
2217 error_function,
2218 error_data,
2219 INTERFACE_NETWORK,
2220 NULL);
2221 break;
2227 g_string_free(message,TRUE);
2231 * @brief Change network status
2233 * @param modem modem interface pointer
2234 * @param new status
2236 void gsmd_modem_change_network_status(ModemInterface *modem,
2237 NetworkStatus status)
2239 gsmd_modem_change_network_status_data(modem,status,
2240 NULL,
2241 NULL,
2242 NULL);
2247 * @brief Handles network status (+CREG) messages
2249 * @param modem modem to apply network status
2250 * @param response string to handle
2252 static
2253 void gsmd_modem_handle_network_status(ModemInterface *modem,
2254 GString *response)
2256 GError **error = NULL;
2257 GRegex *regex = g_regex_new ("\\+CREG:\\s(?<status>[0-5]),?(?<lac>\\d*),?(?<id>\\d*)",
2260 error);
2261 GMatchInfo *match_info;
2262 NetworkStatus status = NETWORK_UNKNOWN;
2263 gchar *match = NULL;
2265 if (g_regex_match (regex, response->str, 0, &match_info))
2267 if (gsmd_utils_match_exists(match_info,"status"))
2269 match = g_match_info_fetch_named(match_info,
2270 "status");
2271 status = g_ascii_digit_value(match[0]);
2272 gsmd_modem_change_network_status(modem,status);
2273 g_free(match);
2277 g_match_info_free (match_info);
2278 g_regex_unref (regex);
2283 * @brief Handles clip messages
2284 * Creates a new call with unknown call id
2286 * @param modem modem whose clip to handle
2287 * @param response string with CLIP
2289 static
2290 void gsmd_modem_handle_incoming_call(ModemInterface *modem,
2291 GString *response)
2293 g_debug("%s",__func__);
2295 +CLIP: "040123456789",128,"",128,"",0
2297 \+CLIP:\s"(\+?\w+)".*
2300 GError **error = NULL;
2301 GRegex *regex = g_regex_new ("\\+CLIP:\\s(?<phone>\"\\+?\\w+\")",
2304 error);
2305 GMatchInfo *match_info;
2306 gchar *match = NULL;
2309 if (g_regex_match (regex, response->str, 0, &match_info))
2311 if (gsmd_utils_match_exists(match_info,"phone"))
2313 match = g_match_info_fetch_named(match_info,
2314 "phone");
2316 gchar *number = NULL;
2317 if (g_str_equal(match,"\"\""))
2318 number = g_strdup("Unknown number");
2319 else
2321 GString *temp = g_string_new(&match[1]);
2322 g_string_erase(temp,temp->len-1,1);
2323 number = g_strdup(temp->str);
2324 g_string_free(temp,TRUE);
2327 g_debug("%s : incoming call from : %s",__func__,number);
2329 Call *call = gsmd_utils_find_call_number(modem,number);
2330 if ( !call)
2332 call = gsmd_utils_new_call(modem,
2333 number,
2334 "", //TODO type ignored
2335 CALL_INCOMING);
2337 gsmd_modem_monitor_call_activity(modem);
2339 gsmd_utils_call_send_status(modem,
2340 call,
2341 "incoming");
2343 g_free(match);
2344 g_free(number);
2347 else
2349 g_debug("Didn't understand +clip");
2352 g_match_info_free (match_info);
2353 g_regex_unref (regex);
2358 * @brief Finds first call with incoming status and sends call status signal
2359 * Should be called when ring message is received from gsm modem.
2361 * @param modem modem who sent ring message
2363 static
2364 void gsmd_modem_handle_ring(ModemInterface *modem)
2366 Call *call = gsmd_utils_find_first_call_status(modem,CALL_INCOMING);
2367 if (call)
2369 gsmd_utils_call_send_status(modem,
2370 call,
2371 "incoming");
2376 * @brief Handles CCWA (call waiting) messages from modem
2378 * @param modem modem whose call waiting message to handle
2379 * @param response string with CCWA
2381 static
2382 void gsmd_modem_handle_call_waiting(ModemInterface *modem,
2383 GString *response)
2386 +CCWA: "0401234567",129,1,"",0
2388 \+CCWA:\s"(\+?\d+)"
2391 GError **error = NULL;
2392 GRegex *regex = g_regex_new ("\\+CCWA:\\s\"(?<phone>\\+?\\d+)\"",
2395 error);
2396 GMatchInfo *match_info;
2397 gchar *match = NULL;
2399 if (g_regex_match (regex, response->str, 0, &match_info))
2401 if (gsmd_utils_match_exists(match_info,"phone"))
2403 match = g_match_info_fetch_named(match_info,
2404 "phone");
2406 Call *call = gsmd_utils_find_call_number(modem,match);
2407 if ( !call)
2409 call = gsmd_utils_new_call(modem,
2410 match,
2411 "", //TODO type ignored
2412 CALL_INCOMING);
2416 gsmd_utils_call_send_status(modem,
2417 call,
2418 "incoming");
2420 g_free(match);
2423 else
2425 g_debug("Didn't understand +ccwa");
2428 g_match_info_free (match_info);
2429 g_regex_unref (regex);
2433 * @brief Parses clcc line and applies information to modem's calls
2434 * Can also create new calls if necessary.
2436 * @param modem pointer to modem whose calls to modify
2437 * @param clcc line returned by clcc
2438 * @return handled call or NULL
2440 Call* gsmd_modem_apply_current_call(ModemInterface *modem, const gchar *clcc)
2443 Test data with clip and ecam:
2444 +CLIP: "044123456",128,"",128,"",0
2446 #ECAM: 0,6,1,,,
2448 RING
2450 +CLIP: "044123456",128,"",128,"",0
2451 at+clcc
2453 +CLCC: 1,1,4,0,0,"044123456",128,""
2455 Test data with two calls
2456 +CLCC: 1,0,0,0,0,"+35840123456",145,""
2457 +CLCC: 2,1,5,0,0,"044654321",128,""
2461 In the first example #ECAM has call id 0
2462 but CLCC says call id is 1
2463 Call id can't be trusted to be call->vendor_id,
2464 but vendor_id _could_ be clcc's id -1
2466 \+CLCC:\s\d+,(\d),(\d),(\d),\d,"(\+?\d+)"
2469 static GRegex *regex = NULL;
2470 if ( !regex )
2472 regex = g_regex_new ("\\+CLCC:\\s(?<index>\\d+),(?<direction>\\d),"
2473 "(?<state>\\d),(?<mode>\\d),\\d,\"(?<number>\\+?\\d+)\"",
2476 NULL);
2478 GMatchInfo *match_info;
2479 Call *call = NULL;
2481 if (g_regex_match (regex, clcc, 0, &match_info))
2483 if (gsmd_utils_match_exists(match_info,"index"))
2485 gint index = gsmd_utils_fetch_match_int(match_info,
2486 "index",0);
2488 gint state = gsmd_utils_fetch_match_int(match_info,
2489 "state",0);
2491 gchar *number = g_match_info_fetch_named(match_info,
2492 "number");
2494 //phone number types might cause a problem if modem
2495 //automatically converts them to national/international
2496 //format. This would cause the call to not be found
2497 call = gsmd_utils_find_call_number(modem,number);
2498 if (!call)
2500 gsmd_utils_print_calls(modem);
2501 call = gsmd_utils_new_call(modem,number,"",CALL_IDLE);
2503 if (call->index < 0)
2505 call->index = index;
2507 else if (call->index != index)
2509 // TODO handle this?
2510 g_warning("%s : Number matches but index does not (%d != %d)",__func__, call->index, index);
2511 gsmd_utils_print_calls(modem);
2514 switch (state)
2516 case 0:
2517 call->status = CALL_CONNECTED;
2518 break;
2519 case 1:
2520 call->status = CALL_HOLD;
2521 break;
2522 case 2:
2523 case 3:
2524 call->status = CALL_CALLING;
2525 break;
2526 case 4:
2527 case 5:
2528 call->status = CALL_INCOMING;
2529 break;
2532 //Mode is currently ignored
2533 g_debug("%s: Got a call to/from %s with status %s",
2534 __func__,
2535 number,
2536 gsmd_utils_call_status_to_string(call->status));
2538 g_free(number);
2543 g_match_info_free (match_info);
2545 return call;
2549 * @brief Iterates all calls in current calls list in given table
2550 * and calls gsmd_modem_apply_current_call on each of them
2552 * @param modem modem who own's the calls to parse
2553 * @param table GHashtable containing pointer to current calls list under
2554 * GSMD_MODEM_KEY_CALL_STATUS_ARRAY key
2556 void gsmd_modem_current_calls_parse(ModemInterface *modem,GHashTable *table)
2558 g_assert(table);
2559 g_assert(modem);
2561 GValue *val = g_hash_table_lookup(table,
2562 GSMD_MODEM_KEY_CALL_STATUS_ARRAY);
2564 GList *calls = NULL;
2565 if (val)
2568 GList *list = g_value_get_pointer(val);
2570 while (list)
2572 gchar *line = list->data;
2573 Call *call = gsmd_modem_apply_current_call(modem,line);
2574 if ( call )
2576 calls = g_list_append (calls, call);
2578 list = g_list_next( list );
2581 if (modem->call_monitor_timer != 0)
2583 g_debug("%s : Checking calls", __func__);
2584 gboolean need_activity_monitor = FALSE;
2585 GList *list = modem->calls;
2586 GList *calls_to_remove = NULL;
2587 while (list)
2589 Call *call = (Call*)list->data;
2590 GList *tmp = calls;
2591 gboolean found = FALSE;
2592 while (tmp)
2594 if (tmp->data == (gpointer)call )
2596 found = TRUE;
2597 break;
2599 tmp = g_list_next(tmp);
2601 if ( !found )
2603 g_debug("%s : Call %d not anymore", __func__, call->id);
2604 calls_to_remove = g_list_append(calls_to_remove, call);
2606 else if ( call->status == CALL_INCOMING )
2608 need_activity_monitor = TRUE;
2610 list = g_list_next(list);
2612 list = calls_to_remove;
2613 while ( list )
2615 gsmd_utils_remove_call_direct(modem,(Call*)list->data,TRUE);
2616 list = g_list_next(list);
2618 g_list_free(calls_to_remove);
2619 if ( need_activity_monitor )
2621 modem->call_monitor_timer = 0;
2622 gsmd_modem_monitor_call_activity (modem);
2628 * @brief Free function for list current calls method
2629 * Frees current calls array from the at command
2631 * @param at at command context to free current calls array
2633 static
2634 void gsmd_modem_current_calls_free(AtCommandContext *at)
2636 g_assert(at);
2638 GList *list = NULL;
2639 GValue *val = g_hash_table_lookup(at->handler_data,
2640 GSMD_MODEM_KEY_CALL_STATUS_ARRAY);
2642 if (!val)
2643 return;
2645 list = g_value_get_pointer(val);
2647 while (list)
2649 g_free(list->data);
2650 list = g_list_next( list );
2653 g_list_free(g_value_get_pointer(val));
2657 * @brief Handler for a command to list current calls
2658 * Adds calls to a list and then updates call structs
2659 * within modem to match.
2661 * @param modem pointer to modem interface
2662 * @param at current at command's context
2663 * @param response message to handle
2664 * @return handler status
2666 static
2667 AtCommandHandlerStatus gsmd_modem_handler_current_calls(ModemInterface *modem,
2668 AtCommandContext *at,
2669 GString *response)
2671 g_debug("%s",__func__);
2672 GError **error = NULL;
2673 GRegex *regex = g_regex_new ("\\+CLCC:\\s(?<index>\\d+),(?<direction>\\d),(?<state>\\d),(?<mode>\\d),\\d,\"(?<number>\\+?\\d+)\"|(?<error>ERROR)|(?<timeout>TIME_OUT)|(?<ok>OK)",
2676 error);
2677 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2678 GMatchInfo *match_info;
2679 GValue *val = NULL;
2682 if (g_regex_match (regex, response->str, 0, &match_info))
2684 if (gsmd_utils_match_exists(match_info,"index"))
2687 GList *list = NULL;
2688 val = g_hash_table_lookup(at->handler_data,
2689 GSMD_MODEM_KEY_CALL_STATUS_ARRAY);
2690 if (val)
2691 list = g_value_get_pointer(val);
2693 list = g_list_append(list,g_strdup(response->str));
2695 gsmd_utils_table_insert_pointer(at->handler_data,
2696 GSMD_MODEM_KEY_CALL_STATUS_ARRAY,
2697 list);
2700 status = AT_HANDLER_NEED_MORE;
2702 else if (gsmd_utils_match_exists(match_info,"error"))
2704 gsmd_utils_send_error(at,
2705 GSMD_ERROR_UNKNOWN,
2706 "FAILED TO READ CURRENT CALL LIST");
2707 status = AT_HANDLER_DONE_ERROR;
2709 else if (gsmd_utils_match_exists(match_info,"timeout"))
2711 gsmd_utils_send_error(at,
2712 GSMD_ERROR_DEVICE_TIMEOUT,
2713 "TIMEOUT WHEN READING CURRENT CALL LIST");
2714 status = AT_HANDLER_DONE_ERROR;
2716 else if (gsmd_utils_match_exists(match_info,"ok"))
2719 gsmd_modem_current_calls_parse(modem,at->handler_data);
2722 status = AT_HANDLER_DONE;
2727 g_free(error);
2728 g_match_info_free (match_info);
2729 g_regex_unref (regex);
2732 return status;
2737 * @brief Handler for command to test if modem is alive
2739 * @param modem pointer to modem interface
2740 * @param at current at command's context
2741 * @param response message to handle
2742 * @return handler status
2744 static
2745 AtCommandHandlerStatus gsmd_modem_handler_alive(ModemInterface *modem,
2746 AtCommandContext *at,
2747 GString *response)
2749 g_debug("%s",__func__);
2750 Modem *modem_priv = (Modem*)modem->priv;
2751 GScanner* scanner = modem->scanner;
2753 //we've got a response, modem is alive. Start initializations
2754 if (scanner->token == SYMBOL_OK)
2756 if (modem->status == MODEM_SERIAL_INIT)
2758 modem->status = MODEM_INITIALIZING;
2760 if ( modem_priv->vendor->init_at )
2762 modem_priv->vendor->init_at (modem_priv->vendor);
2764 else
2766 gsmd_modem_general_at_init(modem);
2769 return AT_HANDLER_DONE;
2772 //Modem didn't reply or replied with an error
2773 if (scanner->token == SYMBOL_TIME_OUT ||
2774 scanner->token == SYMBOL_ERROR)
2776 modem->status = MODEM_UNINITIALIZED;
2777 modem->sim_status = SIM_UNKNOWN;
2779 //Ask vendor if it can deal with an unresponsive modem
2780 if (modem_priv->vendor->not_responding &&
2781 modem_priv->vendor->not_responding(modem_priv->vendor))
2782 return AT_HANDLER_RETRY;
2783 else
2785 gsmd_modem_close_serial_ports(modem_priv);
2786 return AT_HANDLER_DONE;
2790 return AT_HANDLER_DONT_UNDERSTAND;
2794 * @brief Handles unsolicited messages such as +CREG.
2796 * Unsolicite mesaage is an unexpected message or reply or a reply the
2797 * command's handler didn't understand.
2799 * @param modem pointer to modem interface
2800 * @param at current at command's context
2801 * @param response message to handle
2802 * @return handler status
2804 static
2805 AtCommandHandlerStatus gsmd_modem_handler_unsolicite (ModemInterface *modem,
2806 AtCommandContext *at,
2807 GString *response)
2809 Modem *modem_priv = (Modem*)modem->priv;
2810 GScanner* scanner = modem->scanner;
2811 gint sms_pos;
2812 g_debug("%s", __func__);
2813 Call *call = NULL;
2814 gint call_id = 0;
2816 if (g_scanner_eof(scanner))
2817 return AT_HANDLER_DONE;
2819 //Let vendor override unsolicite messages first
2820 if (modem_priv->vendor->unsolicite_handler) //if there is vendor handler
2823 AtCommandHandlerStatus status;
2824 /* g_debug("%s: Running vendor_unsolicite_handler", __func__); */
2825 //if vendor handled it, then we dont need to handle it ourselves
2826 status = modem_priv->vendor->unsolicite_handler (modem, NULL, response);
2827 if ( status != AT_HANDLER_DONT_UNDERSTAND )
2829 /* g_debug("%s: vendor_unsolicite_handler understood", __func__); */
2830 return status;
2832 //reset the scanner
2833 gsmd_modem_scanner_init (modem, response);
2837 g_debug("%s: Running our default handler", __func__);
2839 switch (scanner->token)
2841 case '+':
2842 g_scanner_get_next_token (scanner);
2843 switch (scanner->token)
2845 case SYMBOL_CCWA:
2846 gsmd_modem_handle_call_waiting(modem,response);
2847 case SYMBOL_CLIP://display the incoming call phoneNo
2848 gsmd_modem_handle_incoming_call(modem,response);
2849 break;
2850 case SYMBOL_CRING://display +CRING: VOICE
2851 // don't handle RING, we use CLIP
2852 gsmd_modem_handle_ring(modem);
2854 break;
2855 case SYMBOL_CREG:
2856 gsmd_modem_handle_network_status(modem,response);
2857 break;
2858 case SYMBOL_CMTI://sms indicator
2859 g_debug("%s: CMTI", __func__);
2860 sms_pos = gsmd_modem_sms_indicator_parse (scanner);
2861 if (sms_pos > 0 && modem->sim_ipc->incoming_message)
2863 modem->sim_ipc->incoming_message(modem->sim_ipc,
2864 sms_pos);
2868 break;
2869 default:
2870 g_warning ("Got unrecognized unsolicited symbol: %s\n",
2871 response->str);
2873 break;
2876 * NOTE! Handling NO CARRIER and BUSY have to be overridden in
2877 * vendor unsolicite handler if multiple concurrent calls are to be
2878 * implemented. By default we assume that only concurrent call
2879 * is possible and we remove the first call in both previously
2880 * mentioned cases.
2882 case SYMBOL_BUSY://remote hangup the call
2883 g_debug("%s: BUSY", __func__);
2884 call = gsmd_utils_call_get_current(modem);
2885 if (call)
2887 call_id = call->id;
2888 gsmd_utils_remove_call(modem,call_id, TRUE);
2891 break;
2892 case SYMBOL_RING://handled in CLIP
2893 break;
2896 case SYMBOL_NO:
2897 g_scanner_get_next_token(scanner);
2898 if (scanner->token == SYMBOL_CARRIER)
2900 call = gsmd_utils_call_get_current(modem);
2901 if (call)
2903 call_id = call->id;
2906 gsmd_utils_remove_call(modem,call_id, TRUE);
2909 else
2911 g_scanner_unexp_token (scanner,
2912 SYMBOL_CARRIER,
2913 NULL,
2914 "symbol",
2915 NULL,
2916 NULL,
2917 TRUE);
2920 break;
2921 default:
2922 break;
2926 return AT_HANDLER_DONE;
2928 /**********************End of Default handler**********************************/
2932 * @brief Re-excute current AT command at the tail of command queue
2934 * @param modem Modem device struct pointer
2935 * @param interface interface whose current command to retry
2937 void gsmd_modem_retry_current_command (Modem* modem, InterfaceType interface)
2939 g_debug("%s: device: %d", __func__,interface);
2940 g_assert ( modem );
2941 g_assert ( modem->serial_devices );
2942 AtCommandContext *at = gsmd_modem_get_current_at_command ( modem->modem_if,
2943 interface );
2944 modem->is_timeout = FALSE;
2947 //Remove old timeout
2948 if (at->timeout_event_id != 0)
2950 g_debug("%s : Removing timeout id: %d", __func__, at->timeout_event_id);
2951 g_source_remove(at->timeout_event_id);
2952 at->timeout_event_id = 0;
2956 if (at->retry_counter > 0)
2958 g_debug("Retrying command %s",at->command->command);
2959 at->retry_counter--;
2960 gsmd_modem_process_next_command (modem,interface);
2962 else
2964 g_debug("Finished retrying command %s",at->command->command);
2965 gsmd_modem_finish_command(modem,interface,FALSE);
2973 * @brief Finds all commands with specified command id in the command queue
2974 * and removes them. Doesn't properly cancel the command if it's currently
2975 * being processed (e.g. if it has already been sent to gsm modem)
2977 * @param modem modem whose commands to cancel
2978 * @param cmd_id id of the commands to cancel
2979 * @param interface which interface's commands to cancel
2980 * @return TRUE if atleast one command was cancelled
2982 gboolean gsmd_modem_cancel_command_id(ModemInterface *modem,
2983 AtCommandID cmd_id,
2984 InterfaceType interface)
2986 Modem * modem_priv = (Modem*)modem->priv;
2987 SerialDevice *device = gsmd_modem_get_serial_device(modem_priv, interface);
2988 g_assert(device);
2989 GQueue* queue = device->commandQueue;
2990 g_assert(queue);
2991 GList* list = NULL;
2992 gboolean res = FALSE;
2994 gint len = g_queue_get_length (queue);
2995 gint i=0;
2996 AtCommandContext* at = NULL;
2997 for (i=0; i < len; i++) //the tail should not be remove which is handling
2999 at = (AtCommandContext*) g_queue_peek_nth (queue, i);
3000 if ( at->command->cmd_id == cmd_id )
3002 //g_queue_remove (queue, (gpointer) at);
3003 list = g_list_append (list, at);
3006 while (list)
3008 res = TRUE;
3009 g_queue_remove (queue, list->data);
3010 gsmd_at_command_context_free(list->data);
3011 list = g_list_next (list);
3013 return res;
3017 * @brief Assigns device indices to each of gsmd2's interfaces
3019 * @param modem modem whose interface devices to set
3020 * @param indices a list of indices to set
3021 * @return TRUE if indices were properly assigned
3023 gboolean gsmd_modem_assign_device_indices(ModemInterface *modem, int *indices)
3025 int i=0;
3026 int last_device = -1;
3027 for (i=0;i<INTERFACE_LAST;i++)
3029 int dev = indices[i];
3030 SerialDevice *device = gsmd_modem_get_serial_device_index((Modem*)modem->priv,dev);
3031 if (!device)
3033 if ( last_device < 0)
3035 return FALSE;
3037 g_warning("%s : Assigning device %d because device %d is not available",
3038 __func__, last_device, dev);
3039 dev = last_device;
3041 last_device = dev;
3042 modem->interface_devices[i]=dev;
3044 return TRUE;
3049 * @brief Gets given interface's device index
3050 * Modem might have several serial devices, each interface
3051 * (CALL,SMS,SIM,NETWORK,...) is assigned to one of those devices.
3054 * @param modem modem whose interface to lookup
3055 * @param interface interface whose device to lookup
3056 * @return interface's device index
3058 guint gsmd_modem_get_interface_device_index(ModemInterface *modem,
3059 InterfaceType interface)
3061 g_assert(modem);
3062 return modem->interface_devices[interface];
3066 * @brief Finds command with specified command id from commands_table
3068 * @param modem modem whose command to find
3069 * @param cmd_id command id to find
3070 * @return command's pointer or NULL if none found
3072 AtCommand* gsmd_modem_get_command (ModemInterface *modem,
3073 guint cmd_id)
3075 Modem *modem_priv = (Modem*)modem->priv;
3076 return (AtCommand*)g_hash_table_lookup(modem_priv->commands_table,
3077 GINT_TO_POINTER(cmd_id));
3081 * @brief Sets modem's state to RESET
3083 * @param modem modem to set
3085 void gsmd_modem_reset(ModemInterface *modem)
3087 g_debug("%s",__func__);
3088 g_assert( modem );
3090 modem->status = MODEM_RESET;