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)
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.
37 #include "modem_internal.h"
39 #include "call_interface.h"
45 #include "phonebook.h"
47 #include "sms_interface.h"
48 #include "pdp_interface.h"
49 #include "network_interface.h"
50 #include "device_interface.h"
51 #include "phonebook_interface.h"
52 #include "sim_interface.h"
53 #include "gsmd-error.h"
58 #define TIME_OUT "TIME_OUT\n"
60 /** Default time out value for AT command */
61 #define DEFAULT_TIME_OUT 100
63 /** Time out value for AT command */
64 #define TIME_OUT_PADDING 5000
67 /* static Modem *modem_priv; */
70 * @brief Private data used when reading and writing data to/from serial.
75 * Pointer to modem interface used
80 * Index of the serial device to use
87 typedef struct _SerialData SerialData
;
89 typedef struct _SerialDevice
{
95 * IOChannel of serial device
99 * Data used by IOChannel
101 SerialData
*serial_data
;
106 * @brief Modem Struct
122 GArray
*serial_devices
;
127 GHashTable
*commands_table
;
132 ModemInterface
*modem_if
;
137 VendorInterface
*vendor
;
142 /*********************service function**************************/
143 static void gsmd_modem_init ( ModemInterface
* modem
);
144 static AtCommandHandlerStatus
gsmd_modem_handler_unsolicite (ModemInterface
*modem
,
145 AtCommandContext
*at
,
148 static void gsmd_modem_process_next_command (Modem
* modem
, InterfaceType interface
);
149 static gboolean
gsmd_modem_timeout_handle (gpointer data
);
151 static void gsmd_modem_send_command_raw ( ModemInterface
*modem
,
152 const gchar
*command
,
153 InterfaceType interface
);
155 AtCommandHandlerStatus
gsmd_modem_handler_alive(ModemInterface
*modem
,
156 AtCommandContext
*at
,
160 SerialData
*gsmd_modem_get_serial_data(Modem
*modem
, InterfaceType interface
);
163 AtCommandHandlerStatus
gsmd_modem_handler_current_calls(ModemInterface
*modem
,
164 AtCommandContext
*at
,
167 static void gsmd_modem_current_calls_free(AtCommandContext
*at
);
168 /********************End service function***********************/
171 static const AtCommand
174 //Disable command echos
175 { DISABLE_ECHO
, "ATE0\r\n", 100,
177 gsmd_utils_handler_ok
, NULL
, SIM_UNKNOWN
, NULL
},
180 { POWER_ON
, "AT+CFUN=1\r\n", 15000,
182 gsmd_utils_handler_ok
, NULL
, SIM_UNKNOWN
, NULL
},
184 //Enable Report Mobile Equipment Error
185 { ENABLE_CMEE
, "AT+CMEE=1\r\n", 100,
187 gsmd_utils_handler_ok
, NULL
, SIM_UNKNOWN
, NULL
},
189 //Set response of AT+COPS? to respond with operator name
190 { SET_OP_QUERY_REPLY
, "AT+COPS=3,0\r\n", 100,
192 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
194 //Enable Report Mobile Equipment Error
195 { ENABLE_CMEE
, "AT+CMEE=1\r\n", 100,
197 gsmd_utils_handler_ok
, NULL
, SIM_UNKNOWN
, NULL
},
199 //Enable call waiting
200 { ENABLE_CCWA
, "AT+CCWA=1,1\r\n", 100,
202 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
204 //Enable call waiting
205 { CUR_CALLS_QUERY
, "AT+CLCC\r\n", 100,
207 gsmd_modem_handler_current_calls
, NULL
, SIM_READY
,
208 gsmd_modem_current_calls_free
},
210 //Query if we are muted
211 { MUTE_QUERY
, "AT+CMUTE=?\r\n", 5000,
213 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
215 //Enable caller identification
216 { ENABLE_CLIP
, "AT+CLIP=1\r\n", 180000,
218 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
220 //Enable new message identification
221 { ENABLE_CNMI
, "AT+CNMI=2,1,0,0,0\r\n", 5000,
223 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
226 { RING_VOLUME_QUERY
, "AT+CRSL?\r\n", 5000,
228 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
231 { ESCAPE_COMMAND
, "+++\r\n", 100,
233 gsmd_utils_handler_ok
, NULL
, SIM_UNKNOWN
, NULL
},
235 //Just send at command
236 { AT
, "AT\r\n", 5000,
238 gsmd_utils_handler_ok
, NULL
, SIM_UNKNOWN
, NULL
},
240 //Test modem is alive
241 { REPLY_COMMAND
, "AT\r\n", 5000,
243 gsmd_modem_handler_alive
, NULL
, SIM_UNKNOWN
, NULL
},
246 { SET_PDU_MODE
, "AT+CMGF=0\r\n", 100,
248 gsmd_utils_handler_ok
, NULL
, SIM_READY
, NULL
},
250 //Test modem is alive
251 { SOFT_RESET
, "ATZ\r\n", 5000,
253 gsmd_modem_handler_alive
, NULL
, SIM_UNKNOWN
, NULL
},
255 { 0, NULL
, 100, TRUE
, 1,
256 NULL
, NULL
, SIM_UNKNOWN
, NULL
},
258 }, *command_p
= commands
;
261 static const SymbolTable
263 { "TIME_OUT", SYMBOL_TIME_OUT
,},
264 { "OK", SYMBOL_OK
, },
265 { "ERROR", SYMBOL_ERROR
, },
266 { "RING", SYMBOL_RING
, },
267 { "NO", SYMBOL_NO
, },
268 { "ANSWER", SYMBOL_ANSWER
, },
269 { "CARRIER", SYMBOL_CARRIER
, },
270 { "BUSY", SYMBOL_BUSY
, },
271 { "READY", SYMBOL_READY
, },
272 { "CME", SYMBOL_CME
, },
273 { "CMS", SYMBOL_CMS
, },
274 { "CPIN", SYMBOL_CPIN
, },
275 { "CPAS", SYMBOL_CPAS
, },
276 { "CSQ", SYMBOL_CSQ
, },
277 { "CMUT", SYMBOL_CMUT
, },
278 { "CLIP", SYMBOL_CLIP
, },
279 { "CCWA", SYMBOL_CCWA
, },
280 { "CRING", SYMBOL_CRING
, },
281 { "CMTI", SYMBOL_CMTI
, },
282 { "CRSL", SYMBOL_CRSL
, },
283 { "CMGW", SYMBOL_CMGW
, },
284 { "PIN", SYMBOL_PIN
, },
285 { "PUK", SYMBOL_PUK
, },
287 }, *symbol_p
= symbols
;
291 void gsmd_modem_set_up_interface(Modem
*modem
)
293 modem
->modem_if
= g_new0(ModemInterface
, 1);
294 modem
->modem_if
->priv
= (gpointer
)modem
;
297 static void gsmd_modem_cache_destroy(gpointer data
)
299 GValue
*value
= data
;
300 g_value_unset(value
);
304 /*Allocate Modem structure*/
305 /* return NULL, if failed*/
306 Modem
* gsmd_modem_allocate()
308 ModemInterface
*modem
= NULL
;
309 Modem
*modem_priv
= g_try_new0 (Modem
, 1);
312 g_warning("%s : Failed to allocate a modem structure.", __func__
);
316 gsmd_modem_set_up_interface(modem_priv
);
318 modem
= modem_priv
->modem_if
;
320 modem_priv
->vendor_handle
= NULL
;
321 modem_priv
->is_timeout
= FALSE
;
323 modem
->status
= MODEM_UNINITIALIZED
;
324 modem
->devices
= NULL
;
330 modem
->scanner
= g_scanner_new (NULL
);
331 if (!modem
->scanner
) {
332 g_warning("%s : Failed to set a scanner for the modem.", __func__
);
336 modem
->scanner
->config
->symbol_2_token
= TRUE
;
337 modem
->scanner
->config
->numbers_2_int
= TRUE
;
338 modem
->scanner
->config
->skip_comment_single
= FALSE
;
339 modem
->scanner
->config
->cpair_comment_single
= "";
340 /* the character to skip*/
342 //Add commands list into hash table
343 modem_priv
->commands_table
= g_hash_table_new(NULL
,NULL
);
344 if (!modem_priv
->commands_table
) {
345 g_warning("%s : Failed to set command table for the modem.", __func__
);
348 modem
->cache
= g_hash_table_new_full(NULL
,
351 gsmd_modem_cache_destroy
);
352 gsmd_utils_table_insert_int(modem
->cache
,
353 GSMD_MODEM_KEY_NETWORK_STATUS
,
356 modem
->call
= g_try_new0 (CallInterface
, 1);
359 modem
->call_ipc
= g_try_new0 (CallIPCInterface
, 1);
360 if (!modem
->call_ipc
)
362 modem
->sms
= g_try_new0 (SMSInterface
, 1);
365 modem
->sms_ipc
= g_try_new0 (SMSIPCInterface
, 1);
368 modem
->device
= g_try_new0 (DeviceInterface
, 1);
371 modem
->device_ipc
= g_try_new0 (DeviceIPCInterface
, 1);
372 if (!modem
->device_ipc
)
375 modem
->network
= g_try_new0 (NetworkInterface
, 1);
378 modem
->network_ipc
= g_try_new0 (NetworkIPCInterface
, 1);
379 if (!modem
->network_ipc
)
381 modem
->pdp
= g_try_new0 (PDPInterface
, 1);
384 modem
->pdp_ipc
= g_try_new0 (PDPIPCInterface
, 1);
387 modem
->phonebook
= g_try_new0 (PhonebookInterface
, 1);
388 if (!modem
->phonebook
)
390 modem
->phonebook_ipc
= g_try_new0 (PhonebookIPCInterface
, 1);
391 if (!modem
->phonebook_ipc
)
393 modem
->sim
= g_try_new0 (SIMInterface
, 1);
396 modem
->sim_ipc
= g_try_new0 (SIMIPCInterface
, 1);
404 g_warning("%s: error", __func__
);
406 g_free (modem
->device
);
407 g_free (modem
->device_ipc
);
409 g_free (modem
->sms_ipc
);
410 g_free (modem
->call
);
411 g_free (modem
->call_ipc
);
412 g_free (modem
->network
);
413 g_free (modem
->network_ipc
);
415 g_free (modem
->pdp_ipc
);
416 g_free (modem
->phonebook
);
417 g_free (modem
->phonebook_ipc
);
419 g_hash_table_destroy (modem
->cache
);
423 if (modem_priv
->commands_table
)
424 g_hash_table_destroy (modem_priv
->commands_table
);
425 if (modem_priv
->modem_if
->scanner
)
426 g_scanner_destroy (modem
->scanner
);
434 * Finds the correct vendor handler
435 * @param modem modem to attach the handler
436 * @param vendor the vendor's name. E.g. "telit"
437 * @return TRUE if load was successful, otherwise FALSE
439 gboolean
gsmd_modem_load_vendor_handler (Modem
* modem
, const gchar
* vendor
)
441 VendorInit vendor_init
;
443 GString
* vendor_name
= NULL
;
444 const gchar
*plugindir
= g_getenv("GSMD2PLUGINDIR");
445 //perform vendor init
446 //vendor_telit_unsolicite_handler_init (modem);
450 g_debug("%s : Vendor: %s", __func__
, vendor
);
451 vendor_name
= g_string_new ("");
454 plugindir
= GSMD2PLUGINDIR
;
456 g_string_printf (vendor_name
, "%s/libvendor%s.so", plugindir
, vendor
);
457 modem
->vendor_handle
= dlopen (vendor_name
->str
,RTLD_LAZY
);
458 g_string_free (vendor_name
, TRUE
);
459 if (!modem
->vendor_handle
) {
460 g_debug ("Vendor %s not found from %s",vendor
, plugindir
);
462 fprintf (stderr
,"%s\n", error
);
467 vendor_init
= dlsym (modem
->vendor_handle
,"vendor_handle_init");
468 if ((error
= dlerror()) != NULL
) {
469 fprintf (stderr
, "%s\n", error
);
470 dlclose (modem
->vendor_handle
);
474 return vendor_init (modem
->modem_if
, modem
->vendor
);
477 void gsmd_modem_init_standard_at_handler(ModemInterface
* modem
)
479 g_debug("%s", __func__
);
481 while (symbol_p
->symbol_name
) {
482 g_scanner_add_symbol (modem
->scanner
, symbol_p
->symbol_name
,
483 GINT_TO_POINTER(symbol_p
->symbol_token
));
487 while (command_p
->command
) {
488 gsmd_modem_register_command (modem
,command_p
);
493 void gsmd_modem_clear_queue_func(gpointer data
,
496 AtCommandContext
*at
= (AtCommandContext
*)data
;
497 gsmd_utils_send_error(at
, GSMD_ERROR_RESET
, "Reseting modem");
498 if (at
->timeout_event_id
!= 0) {
499 g_debug("%s : Removing timeout id: %d",
501 at
->timeout_event_id
);
503 g_source_remove(at
->timeout_event_id
);
505 gsmd_at_command_context_free(at
);
510 * @brief Closes all serial ports
512 * @param modem pointer to modem whose serial ports to close
514 void gsmd_modem_close_serial_ports(Modem
*modem
)
516 g_debug("%s",__func__
);
519 if (modem
->serial_devices
) {
520 for (i
=0;i
<modem
->serial_devices
->len
;i
++) {
521 SerialDevice
*serial
= g_array_index(modem
->serial_devices
,SerialDevice
*,i
);
522 gsmd_serial_free(serial
->serial
);
523 g_free(serial
->serial_data
);
524 g_queue_foreach(serial
->commandQueue
,gsmd_modem_clear_queue_func
,NULL
);
525 g_queue_free(serial
->commandQueue
);
527 g_array_free(modem
->serial_devices
,TRUE
);
528 modem
->serial_devices
= NULL
;
531 modem
->modem_if
->status
= MODEM_UNINITIALIZED
;
535 gboolean
gsmd_modem_init_serial_ports(Modem
*modem
)
537 g_debug("%s",__func__
);
539 //Make sure we aren't initializing the modem twice
540 if (modem
->modem_if
->status
!= MODEM_UNINITIALIZED
)
543 modem
->modem_if
->status
= MODEM_SERIAL_INIT
;
547 g_assert(modem
->modem_if
);
548 g_assert(modem
->modem_if
->devices
);
550 modem
->serial_devices
= g_array_new(TRUE
,TRUE
,sizeof(SerialDevice
*));
553 GList
*device_it
= modem
->modem_if
->devices
;
555 gchar
*device
= device_it
->data
;
556 g_debug("Adding device %s",device
);
557 gint device_fd
= modem
->vendor
->init_serial( modem
->vendor
, device
);
560 g_warning ("%s : init_serial failed\n",
565 Serial
*serial
= gsmd_serial_open_port (device_fd
);
567 g_warning("%s : Failed to open device %s",
570 //open failed, release the resource
571 gsmd_modem_close (modem
->modem_if
);
574 SerialData
*serial_data
= g_new0(SerialData
,1);
575 serial_data
->modem
= modem
;
576 serial_data
->device_index
= i
;
578 gsmd_serial_register_trigger( serial
, "\r\n",
580 (gpointer
)serial_data
,
582 gsmd_serial_register_trigger( serial
, "\r",
584 (gpointer
)serial_data
,
586 gsmd_serial_register_trigger( serial
, "\n",
588 (gpointer
)serial_data
,
591 SerialDevice
*serial_device
= g_new0(SerialDevice
, 1);
592 serial_device
->serial
= serial
;
593 serial_device
->serial_data
= serial_data
;
594 serial_device
->commandQueue
= g_queue_new();
595 g_array_append_val(modem
->serial_devices
,serial_device
);
596 device_it
= g_list_next(device_it
);
600 if ( modem
->vendor
->wakeup_modem
) {
601 if (modem
->vendor
->wakeup_modem(modem
->vendor
)) {
602 gsmd_modem_post_alive_test(modem
->modem_if
,TRUE
);
605 gsmd_modem_post_alive_test(modem
->modem_if
,TRUE
);
612 * @brief Opens a modem device.
614 * Before using modem, this function must be called to open modem and
615 * get modem device struct pointer
617 * @param devices list of device file names
618 * @param vendor The libname name of the vendor
619 * for example "telit"
620 * @param no_cache should caching not be used
621 * @param ipc_init pointer to ipc initialization function
622 * @param interface_devices a list that maps interfaces to devices
623 * @return pointer to modem interface struct
625 ModemInterface
* gsmd_modem_open (gchar
**devices
,
630 int *interface_devices
)
633 Modem
* modem
= gsmd_modem_allocate();
634 modem
->modem_if
->no_cache
= no_cache
;
635 modem
->modem_if
->conf_file
= conf
;
636 gchar
*device
= NULL
;
645 gsmd_modem_init (modem
->modem_if
);
647 modem
->modem_if
->ipc_data
= ipc_init(modem
->modem_if
);
649 if (!modem
->modem_if
->ipc_data
) {
650 g_warning("Cannot initialize ipc!\n");
655 if (!gsmd_modem_load_vendor_handler (modem
, vendor
)) {
656 g_warning ("Can't find the vendor or vendor init failed: %s\n", vendor
);
662 gsmd_modem_init_standard_at_handler(modem
->modem_if
);
667 g_debug("%s : '%s'", __func__
, device
);
668 modem
->modem_if
->devices
= g_list_append(modem
->modem_if
->devices
,device
);
673 if (!gsmd_modem_init_serial_ports(modem
))
677 if( !gsmd_modem_assign_device_indices(modem
->modem_if
,interface_devices
) ) {
678 gsmd_modem_close(modem
->modem_if
);
682 return modem
->modem_if
;
685 void gsmd_modem_change_sim_status(ModemInterface
*modem
, SIMStatus status
)
688 Modem
*modem_priv
= (Modem
*)modem
->priv
;
689 if ( modem
->sim_status
< SIM_READY
690 && status
>= SIM_READY
) {
691 if ( modem_priv
->vendor
->init_at_sim_ready
) {
692 modem_priv
->vendor
->init_at_sim_ready (modem_priv
->vendor
);
694 gsmd_modem_general_at_init_sim_ready(modem
);
697 modem
->sim_status
= status
;
700 void gsmd_modem_serial_devices_free(Modem
*modem
)
703 if (modem
->serial_devices
) {
704 for (i
=0;i
<modem
->serial_devices
->len
;i
++) {
705 SerialDevice
*device
= g_array_index(modem
->serial_devices
,SerialDevice
*,i
);
706 /* //ask vendor to close it */
707 /* if (modem->vendor->close_serial) */
708 /* modem->vendor->close_serial(modem->vendor, */
710 /* else //or close it ourselves */
711 /* close(serial->fd); */
712 gsmd_serial_free(device
->serial
);
713 g_queue_foreach(device
->commandQueue
,gsmd_modem_clear_queue_func
,NULL
);
714 g_queue_free(device
->commandQueue
);
715 g_free(device
->serial_data
);
719 g_array_free(modem
->serial_devices
,FALSE
);
720 modem
->serial_devices
= NULL
;
727 * @param modem The pointer to the modem device struct which to be close
729 void gsmd_modem_close (ModemInterface
* modem
)
731 Modem
*modem_priv
= (Modem
*)modem
->priv
;
732 g_assert (modem_priv
);
733 g_debug("%s", __func__
);
735 if (modem_priv
->vendor_handle
)
736 dlclose (modem_priv
->vendor_handle
);
737 g_free (modem
->call
);
738 g_free (modem
->call_ipc
);
741 g_free (modem
->sms_ipc
);
743 gsmd_network_deinitialize(modem
);
744 g_free (modem
->network
);
745 g_free (modem
->network_ipc
);
747 g_free (modem
->device
);
748 g_free (modem
->device_ipc
);
751 g_free (modem
->pdp_ipc
);
754 gsmd_phonebook_deinitialize(modem
);
755 g_free (modem
->phonebook
);
756 g_free (modem
->phonebook_ipc
);
758 gsmd_sim_deinitialize(modem
);
760 g_free (modem
->sim_ipc
);
762 g_hash_table_destroy (modem
->cache
);
764 g_scanner_destroy (modem
->scanner
);
765 g_hash_table_destroy (modem_priv
->commands_table
);
767 gsmd_modem_serial_devices_free(modem_priv
);
770 GList
*list
= modem
->calls
;
772 Call
*call
= (Call
*)list
->data
;
774 list
= g_list_next( list
);
776 g_list_free(modem
->calls
);
779 g_key_file_free(modem
->conf_file
);
785 /************************service function**************************************/
787 SerialDevice
* gsmd_modem_get_serial_device_index(Modem
*modem
,guint device_index
)
790 g_assert(modem
->serial_devices
);
791 if( modem
->serial_devices
->len
> device_index
) {
792 return g_array_index(modem
->serial_devices
, SerialDevice
*, device_index
);
794 g_warning("%s : Invalid index: %d. We have %d device(s)",
795 __func__
, device_index
, modem
->serial_devices
->len
);
800 SerialDevice
* gsmd_modem_get_serial_device(Modem
*modem
,InterfaceType interface
)
803 g_assert(modem
->serial_devices
);
804 guint device_index
= modem
->modem_if
->interface_devices
[interface
];
805 return gsmd_modem_get_serial_device_index(modem
, device_index
);
809 * @brief Sends initializing at commands to the modem
811 * @param modem modem to initialize
813 void gsmd_modem_general_at_init (ModemInterface
* modem
)
816 gsmd_modem_post_at_command_id (modem
,
818 NULL
, NULL
, NULL
, NULL
,
822 gsmd_modem_post_at_command_id (modem
,
824 NULL
, NULL
, NULL
, NULL
,
828 gsmd_modem_post_at_command_id( modem
,
830 NULL
, NULL
, NULL
, NULL
,
834 gsmd_modem_post_at_command_id( modem
,
836 NULL
, NULL
, NULL
, NULL
,
840 gsmd_modem_post_at_command_id( modem
,
842 NULL
, NULL
, NULL
, NULL
,
846 gsmd_modem_post_at_command_id( modem
,
848 NULL
, NULL
, NULL
, NULL
,
852 gsmd_modem_post_at_command_id (modem
,
854 NULL
, NULL
, NULL
, NULL
,
859 * @brief Sends initializing at commands that need sim_status >=
860 * SIM_READY to the modem
862 * @param modem modem to initialize
864 void gsmd_modem_general_at_init_sim_ready (ModemInterface
* modem
)
867 gsmd_modem_post_at_command_id (modem
,
873 gsmd_modem_post_at_command_id (modem
,
875 NULL
, NULL
, NULL
, NULL
,
879 gsmd_modem_post_at_command_id (modem
,
881 NULL
, NULL
, NULL
, NULL
,
884 gsmd_modem_post_at_command_id (modem
,
886 NULL
, NULL
, NULL
, NULL
,
890 gsmd_modem_post_at_command_id (modem
,
892 NULL
, NULL
, NULL
, NULL
,
896 gsmd_modem_post_at_command_id (modem
,
898 NULL
, NULL
, NULL
, NULL
,
904 * @brief Gets current command's ipc data
906 * @param modem modem device struct pointer
907 * @return pointer to ipc data
909 gpointer
* gsmd_modem_get_current_ipc_data (ModemInterface
*modem
,
910 InterfaceType interface
)
913 AtCommandContext
* at
= gsmd_modem_get_current_at_command(modem
,interface
);
920 * @brief Get AT command processed currently
922 * @param modem modem device struct pointer
924 * @return atcommand that is currently processed
926 AtCommandContext
* gsmd_modem_get_current_at_command_index (ModemInterface
*modem
,
930 Modem
*modem_priv
= (Modem
*)modem
->priv
;
931 g_assert (modem_priv
);
932 g_assert (modem_priv
->serial_devices
);
933 SerialDevice
*device
= gsmd_modem_get_serial_device_index( modem_priv
, device_index
);
935 return g_queue_peek_head(device
->commandQueue
);
939 * @brief Get AT command processed currently
941 * @param modem modem device struct pointer
943 * @return atcommand that is currently processed
945 AtCommandContext
* gsmd_modem_get_current_at_command (ModemInterface
*modem
,
946 InterfaceType interface
)
949 Modem
*modem_priv
= (Modem
*)modem
->priv
;
950 g_assert (modem_priv
);
951 g_assert (modem_priv
->serial_devices
);
952 SerialDevice
*device
= gsmd_modem_get_serial_device( modem_priv
, interface
);
954 return g_queue_peek_head(device
->commandQueue
);
959 * @brief Send AT command to head of the queue
961 * Diffrent from modem_add_command, forces command to be the first in
964 * @param modem modem device struct pointer
965 * @param at AT command to send
968 void gsmd_modem_send_command_force_next (Modem
*modem
,
969 AtCommandContext
*at
,
970 InterfaceType interface
)
975 SerialDevice
*device
= gsmd_modem_get_serial_device( modem
, interface
);
978 AtCommandContext
*current_at
= g_queue_pop_head ( device
->commandQueue
);
979 g_queue_push_tail ( device
->commandQueue
, at
);
981 g_queue_push_head (device
->commandQueue
, current_at
);
988 * @brief Adds an modem alive test command (AT) or soft reset (ATZ) to the first of the queue
989 * ignoring unoverrideable commands and processes it
991 * @param modem pointer to modem device struct
992 * @param reset if TRUE, send ATZ instead of AT
993 * @return TRUE if it was put first
995 gboolean
gsmd_modem_post_alive_test (ModemInterface
*modem_if
, gboolean reset
)
997 g_debug("%s",__func__
);
999 Modem
*modem
= (Modem
*)modem_if
->priv
;
1001 g_assert(modem
->serial_devices
);
1002 SerialDevice
*device
= gsmd_modem_get_serial_device( modem
, INTERFACE_GENERAL
);
1005 AtCommandContext
*at
= NULL
;
1007 g_assert(modem
->modem_if
->status
< MODEM_READY
);
1008 at
= gsmd_at_command_context_new_from_id(modem
->modem_if
,
1016 at
= gsmd_at_command_context_new_from_id(modem
->modem_if
,
1024 g_queue_push_head (device
->commandQueue
, at
);
1025 gsmd_modem_process_next_command(modem
,INTERFACE_GENERAL
);
1031 * @brief Add a custom AT command to command queue. Overrides all (overrideable)
1032 * commands in the queue and thus tries to run it as soon as possible.
1034 * @param modem pointer to modem device struct
1035 * @param command AT command string
1036 * for example, "ATD1234567;"
1037 * @param handler The AT command response handler function
1038 * @param data data to write with the command
1039 * @param retry retry times
1040 * @param timeout timeout in milliseconds
1041 * @param overrideable can this command be overriden (true) or must it run
1042 * uninterrupted (false)
1045 gboolean
gsmd_modem_post_at_command_and_override (ModemInterface
*modem
,
1046 AtCommandContext
*new_at
,
1047 InterfaceType interface
)
1050 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1051 g_assert(modem_priv
->serial_devices
);
1053 SerialDevice
*device
= gsmd_modem_get_serial_device( modem_priv
, interface
);
1056 g_warning("%s : improper device index",__func__
);
1060 AtCommandContext
*current_at
= gsmd_modem_get_current_at_command ( modem
,
1063 //Most commands require PIN to be set
1064 if (new_at
->command
->required_state
> modem
->sim_status
) {
1065 if (new_at
->error_function
) {
1066 gsmd_utils_send_error(new_at
,
1068 "SIM AUTHENTICATION ERROR");
1069 g_debug("%s : Command %s wanted pin state to be %d, but it is only %d",
1071 new_at
->command
->command
,
1072 new_at
->command
->required_state
,
1078 //If no commands in queue, insert this one and process the queue
1080 g_debug("%s : No commands in queue, no need to override",__func__
);
1081 g_queue_push_tail (device
->commandQueue
, new_at
);
1082 gsmd_modem_process_next_command(modem_priv
,interface
);
1086 //if there are commands in the queue and we can override the first one, break it and push ours first
1087 if (current_at
->command
->overrideable
) {
1088 g_debug("%s : Overriding current command",__func__
);
1089 //Remove timeout for the previous command
1090 if (current_at
->timeout_event_id
!= 0) {
1091 g_debug("%s : Removing timeout id: %d", __func__
, current_at
->timeout_event_id
);
1092 g_source_remove(current_at
->timeout_event_id
);
1095 g_queue_push_head (device
->commandQueue
, new_at
);
1096 gsmd_modem_send_command_raw (modem
,"+++\r\n",interface
);
1097 //Process the new command
1098 gsmd_modem_process_next_command(modem_priv
,interface
);
1099 } else { //if the current command isn't overrideable push our new command second in line
1100 g_debug("%s : Current command can't be overridden, moving next in queue",
1102 g_queue_pop_head(device
->commandQueue
);
1103 g_queue_push_head(device
->commandQueue
, new_at
);
1104 g_queue_push_head(device
->commandQueue
,current_at
);
1114 * @brief Add a custom AT command to command queue
1116 * @param modem pointer to modem device struct
1117 * @param at custom at command to add
1120 gboolean
gsmd_modem_post_at_command ( ModemInterface
*modem
,
1121 AtCommandContext
*at
,
1122 InterfaceType interface
)
1126 gsmd_utils_print_data(__func__
,"command: ",at
->command
->command
);
1128 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1129 if ( !modem_priv
->serial_devices
) {
1130 //If serial ports aren't initialized then initialize them
1131 gsmd_modem_init_serial_ports(modem_priv
);
1133 // modem is not ready so fail this request
1137 if (modem
->status
< MODEM_INITIALIZING
) {
1138 gsmd_utils_print_data(__func__
,
1139 "Modem is uninitialized, unable to add command: ",
1140 at
->command
->command
);
1142 g_debug("%s : Unable to add command %s because modem is uninitialized",
1143 __func__,at->command->command);
1145 gsmd_utils_send_error(at
, GSMD_ERROR_RESET
, "Modem not ready yet");
1146 gsmd_at_command_context_free(at
);
1152 AtCommandContext
*current_at
= gsmd_modem_get_current_at_command(modem
,
1155 SerialDevice
*device
= gsmd_modem_get_serial_device( modem_priv
, interface
);
1161 g_queue_push_tail (device
->commandQueue
, at
);
1165 g_debug("%s : process next command", __func__
);
1166 gsmd_modem_process_next_command(modem_priv
,interface
);
1174 gboolean
gsmd_modem_post_at_command_id ( ModemInterface
* modem
,
1175 AtCommandID command_id
,
1178 ErrorFunction error_function
,
1179 gpointer error_data
,
1180 InterfaceType interface
,
1181 GHashTable
*handler_data
)
1183 AtCommandContext
*at
= gsmd_at_command_context_new_from_id( modem
,
1190 return gsmd_modem_post_at_command (modem
, at
,interface
);
1193 gboolean
gsmd_modem_post_at_command_id_and_override ( ModemInterface
* modem
,
1194 AtCommandID command_id
,
1197 ErrorFunction error_function
,
1198 gpointer error_data
,
1199 InterfaceType interface
,
1200 GHashTable
*handler_data
)
1202 AtCommandContext
*at
= gsmd_at_command_context_new_from_id( modem
,
1209 return gsmd_modem_post_at_command_and_override (modem
, at
,interface
);
1214 * @brief Create new AT command struct
1216 * @param command AT command string
1218 AtCommandContext
* gsmd_at_command_context_new (AtCommand
*at
,
1221 ErrorFunction error_function
,
1222 gpointer error_data
,
1223 GHashTable
*handler_data
)
1225 return gsmd_at_command_context_new_full(at
,
1235 * @brief Create new AT command struct
1237 * @param command AT command string
1239 AtCommandContext
* gsmd_at_command_context_new_full (AtCommand
*atcmd
,
1242 GHashTable
*handler_data
,
1243 ErrorFunction error_function
,
1244 gpointer error_data
)
1246 AtCommandContext
*at
= NULL
;
1247 at
= g_slice_new0 (AtCommandContext
);
1249 g_warning ("Failed to create new AtCommandContext.\n");
1252 at
->command
= atcmd
;
1255 at
->command_param
= g_strdup(param
);
1256 at
->retry_counter
= atcmd
->retry
;
1257 at
->timeout_event_id
= 0;
1258 at
->ipc_data
= ipc_data
;
1259 at
->error_function
= error_function
;
1260 at
->error_data
= error_data
;
1262 at
->handler_data
= gsmd_utils_create_hash_table();
1264 at
->handler_data
= handler_data
;
1268 if ( at
->error_function
&& !at
->error_data
) {
1269 g_warning("%s : AT command '%s' has error function but no error data!",
1270 __func__
, atcmd
->command
);
1276 AtCommandContext
* gsmd_at_command_context_new_from_id (ModemInterface
*modem
,
1280 ErrorFunction error_function
,
1281 gpointer error_data
,
1282 GHashTable
*handler_data
)
1284 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1285 AtCommandContext
*at
= NULL
;
1286 AtCommand
*command
= (AtCommand
*) g_hash_table_lookup(modem_priv
->commands_table
,
1287 GINT_TO_POINTER(cmd_id
));
1290 at
= gsmd_at_command_context_new_full(command
,
1300 * @brief Free the AT command struct
1302 * @param at The AT command pointer
1304 void gsmd_at_command_context_free (AtCommandContext
* at
)
1306 if (at
== NULL
) return;
1307 if (at
->command_param
)
1308 g_free(at
->command_param
);
1310 if (at
->command
->free_function
) {
1311 at
->command
->free_function(at
);
1314 g_hash_table_destroy(at
->handler_data
);
1315 g_slice_free (AtCommandContext
,at
);
1319 * @brief Function called after a command has been finished.
1321 * AtCommand will be removed from queue and freed.
1323 * @param modem pointer to the modem
1324 * @param interface device whose command to finish
1325 * @param test_alive should test alive command be sent
1327 static void gsmd_modem_finish_command (Modem
* modem
,
1328 InterfaceType interface
,
1329 gboolean test_alive
)
1331 g_debug("%s\n",__func__
);
1332 SerialDevice
*device
= gsmd_modem_get_serial_device( modem
, interface
);
1337 GQueue
*queue
= device
->commandQueue
;
1339 AtCommandContext
*at
= g_queue_pop_head (queue
);
1342 gsmd_utils_print_data(__func__
,
1343 "Removing command ",
1344 at
->command
->command
);
1346 //g_debug("%s : %s",__func__,at->command->command);
1347 if (at
->timeout_event_id
!= 0) {
1348 g_debug("%s : Removing timeout id: %d", __func__
, at
->timeout_event_id
);
1349 g_source_remove(at
->timeout_event_id
);
1351 gsmd_at_command_context_free (at
);
1354 g_debug("Got no next command to finish\n");
1356 // if command handler (e.g. some vendor command)
1357 // marked the modem not alive
1358 if ( modem
->modem_if
->status
== MODEM_RESET
) {
1359 gsmd_modem_close_serial_ports(modem
);
1360 gsmd_modem_init_serial_ports(modem
);
1361 } else if (test_alive
) {
1362 g_debug("%s : testing that modem is alive",__func__
);
1363 gsmd_modem_post_alive_test(modem
->modem_if
, FALSE
);
1365 g_debug("%s : processing next command",__func__
);
1366 gsmd_modem_process_next_command(modem
,interface
);
1371 * @brief Returns serial data from specified device index
1373 * @param modem pointer to modem
1374 * @param interface device whose serial data to get
1375 * @return specified device's serial data or NULL if none found
1377 static SerialData
*gsmd_modem_get_serial_data(Modem
*modem
, InterfaceType interface
)
1380 g_assert(modem
->serial_devices
);
1381 SerialDevice
*device
= gsmd_modem_get_serial_device(modem
, interface
);
1383 return device
->serial_data
;
1388 static void gsmd_modem_write_complete(WriteData
*write
, gpointer data
)
1390 g_debug("%s", __func__
);
1391 AtCommandContext
*at
= (AtCommandContext
*)data
;
1392 at
->write_complete
= TRUE
;
1396 static void gsmd_modem_print_single_command(gpointer data,gpointer user_data)
1398 AtCommandContext* at = data;
1399 g_debug("%s : %s",__func__,at->command->command);
1402 static void gsmd_modem_print_commands(Modem* modem, InterfaceType interface)
1405 GQueue *queue = NULL;
1406 if ( modem->commandQueues->len > device_index ) {
1407 queue = g_array_index(modem->commandQueues,
1411 g_debug("%s : Commands: ",__func__);
1414 g_queue_foreach(queue,gsmd_modem_print_single_command,NULL);
1420 * @brief Takes the next command from command queue and processes it
1422 * @param modem whose next command to process
1424 static void gsmd_modem_process_next_command (Modem
* modem
, InterfaceType interface
)
1426 g_debug("%s: device: %d",__func__
,interface
);
1427 AtCommandContext
*at
= gsmd_modem_get_current_at_command ( modem
->modem_if
,
1430 if (modem
->vendor
->command_prepare
) {
1431 at
= modem
->vendor
->command_prepare(modem
->vendor
,modem
->modem_if
,at
);
1433 gsmd_utils_print_data(__func__
,
1434 "Running command_prepare AT command: ",
1435 at
->command
->command
);
1438 g_debug("%s : Running command_prepare AT command: '%s'",
1440 at->command->command);
1442 SerialDevice
*device
= gsmd_modem_get_serial_device(modem
, interface
);
1444 GQueue
*queue
= device
->commandQueue
;
1445 g_queue_push_head (queue
, at
);
1450 //Get current command again to allow vendor to insert their own command
1451 at
= gsmd_modem_get_current_at_command ( modem
->modem_if
,
1455 g_debug("%s : No commands in queue", __func__
);
1458 //Most commands require PIN code to be set
1459 if (at
->command
->required_state
> modem
->modem_if
->sim_status
) {
1460 g_debug("%s : sim status: %d, command '%s' requires: %d",
1461 __func__
, modem
->modem_if
->sim_status
,
1462 at
->command
->command
, at
->command
->required_state
);
1463 if (at
->error_function
) {
1464 gsmd_utils_send_error(at
,
1466 "SIM AUTHENTICATION ERROR");
1469 gsmd_modem_finish_command(modem
, interface
, FALSE
);
1473 AtCommandPrepare prepare
= at
->command
->prepare
;
1474 gboolean prepare_ok
= TRUE
;
1476 gsmd_utils_print_data(__func__
,
1477 "Processing command ",
1478 at
->command
->command
);
1481 modem
->is_timeout
= TRUE
;//set the timeout flag
1483 GString
*command
= g_string_new (at
->command
->command
);
1486 if (at
->command_param
) {
1487 g_string_printf(command
,at
->command
->command
,
1494 prepare_ok
= (*prepare
)(modem
->modem_if
);
1496 // TODO handle failed prepare
1497 if ( !prepare_ok
) {
1498 g_warning("%s: Prepare failed!", __func__
);
1501 WriteData
*data
= g_try_new0(WriteData
,1);
1502 data
->command
= g_strdup(command
->str
);
1506 data
->timeout
= at
->command
->timeout
+ TIME_OUT_PADDING
;
1510 data
->timeoutid
= &at
->timeout_event_id
;
1511 data
->timeout_data
= gsmd_modem_get_serial_data(modem
,
1513 data
->timeout_function
= &gsmd_modem_timeout_handle
;
1514 data
->write_complete_data
= at
;
1515 data
->write_complete_function
= &gsmd_modem_write_complete
;
1516 gsmd_modem_serial_queue_write (modem
->modem_if
, data
,interface
);
1517 g_string_free(command
,TRUE
);
1522 * @brief Initializes scanner for modem's input
1524 * @param modem whose input to scan
1527 void gsmd_modem_scanner_init (ModemInterface
*modem
, GString
*str
)
1529 GScanner
* scanner
= modem
->scanner
;
1530 g_scanner_input_text (scanner
, str
->str
, str
->len
);
1531 g_scanner_get_next_token (scanner
);
1532 g_scanner_peek_next_token (scanner
);
1536 * @brief Function to handle reading serial port
1538 * @param io io to read from
1539 * @param condition condition
1540 * @param data pointer to modem struct
1541 * @return always returns true
1543 void gsmd_modem_data_in (GString
*buffer
, gpointer data
)
1545 SerialData
*serial
= (SerialData
*)data
;
1546 Modem
*modem
= serial
->modem
;
1547 ModemInterface
*modem_if
= modem
->modem_if
;
1548 AtCommandHandlerStatus status
= AT_HANDLER_DONT_UNDERSTAND
;
1549 AtCommandHandler handler
= NULL
;
1550 AtCommandContext
*at
= NULL
;
1553 at
= gsmd_modem_get_current_at_command_index ( modem_if
, serial
->device_index
);
1554 if ( at
&& !at
->write_complete
) {
1555 g_debug("%s : Got input, but current command has not been written.", __func__
);
1558 if (at
&& at
->command
) {
1559 if ( at
->handler
) {
1560 handler
= at
->handler
;
1561 } else if ( at
->command
->handler
) {
1562 handler
= at
->command
->handler
;
1564 handler
= &gsmd_utils_handler_ok
;
1567 GString
*debug_str
= g_string_new("");
1568 g_string_printf(debug_str
,"Received from port %d: ",serial
->device_index
);
1570 gsmd_utils_print_data(__func__
,
1573 g_string_free(debug_str
,TRUE
);
1575 if ( modem
->vendor
->data_in
) {
1576 modem
->vendor
->data_in(modem_if
, at
, buffer
);
1578 gsmd_modem_scanner_init (modem_if
, buffer
);
1582 status
= (*handler
)(modem_if
, at
, buffer
);
1584 case AT_HANDLER_DONE
:
1585 case AT_HANDLER_DONE_ERROR
:
1586 //if handled then process next command if there is
1587 modem
->is_timeout
= FALSE
;
1588 g_debug("Done or done error");
1589 gsmd_modem_finish_command(modem
,
1590 serial
->device_index
,
1593 case AT_HANDLER_ERROR
:
1594 modem
->is_timeout
= FALSE
;
1595 gsmd_modem_finish_command(modem
,
1596 serial
->device_index
,
1598 // run unsolicite because we don't know if the message
1599 // belonged to handler or not
1600 gsmd_modem_handler_unsolicite( modem_if
, NULL
, buffer
);
1602 case AT_HANDLER_NEED_MORE
:
1604 case AT_HANDLER_DONT_UNDERSTAND
:
1605 gsmd_modem_handler_unsolicite( modem_if
, NULL
, buffer
);
1607 case AT_HANDLER_RETRY
:
1608 gsmd_modem_retry_current_command( modem
,
1609 serial
->device_index
);
1614 if (gsmd_modem_handler_unsolicite( modem_if
, NULL
, buffer
) ==
1616 modem
->is_timeout
= FALSE
;
1628 * @brief Sms indocator parser
1630 * @param scanner whose data to parse
1631 * @return sms indicator
1633 gint
gsmd_modem_sms_indicator_parse (GScanner
* scanner
)
1635 g_debug("%s",__func__
);
1636 //input: CMTI: "SM", 1
1638 if (scanner
->token
== SYMBOL_CMTI
) {
1639 g_scanner_get_next_token (scanner
);// get ,
1640 g_scanner_get_next_token (scanner
);//get s
1641 g_scanner_get_next_token (scanner
);//get m
1642 g_scanner_get_next_token (scanner
);//get ,
1643 pos
= scanner
->value
.v_int
;
1644 //g_message("sms pos is %d\n",pos);
1650 void gsmd_modem_register_command (ModemInterface
*modem
,
1651 const AtCommand
*command
)
1653 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1654 g_hash_table_insert(modem_priv
->commands_table
,
1655 GINT_TO_POINTER(command
->cmd_id
),
1659 Trigger
* gsmd_modem_serial_register_trigger(ModemInterface
*modem
,
1660 const gchar
*trigger_str
,
1661 SerialDataIn handler
,
1664 InterfaceType interface
)
1666 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1667 SerialDevice
*device
= gsmd_modem_get_serial_device(modem_priv
, interface
);
1673 g_debug("%s : Using default handler/data", __func__
);
1674 handler
= &gsmd_modem_data_in
;
1675 data
= device
->serial_data
;
1678 return gsmd_serial_register_trigger(device
->serial
,
1686 * @brief Queue a new write to serial port
1688 * @param modem pointer to modem interface
1689 * @param data writedata that contains timeout information
1690 * and the data to write to serial port
1691 * @param interface_index which interface to be used to write command
1693 void gsmd_modem_serial_queue_write ( ModemInterface
*modem
,
1695 InterfaceType interface
)
1697 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1698 SerialDevice
*device
= gsmd_modem_get_serial_device(modem_priv
, interface
);
1700 gsmd_serial_queue_write( device
->serial
, data
);
1702 g_warning("%s : Writing data to improper serial device %d",
1704 device
->serial_data
->device_index
);
1709 * @brief Writes data directly to serial port
1711 * @param modem pointer to modem interface
1712 * @param data writedata that contains timeout information
1713 * and the data to write to serial port
1714 * @param interface_index which interface to be used to write command
1716 void gsmd_modem_serial_write ( ModemInterface
*modem
,
1718 InterfaceType interface
)
1720 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1721 SerialDevice
*device
= gsmd_modem_get_serial_device(modem_priv
, interface
);
1723 gsmd_serial_write( device
->serial
, data
);
1725 g_warning("%s : Writing data to improper serial device %d",
1727 device
->serial_data
->device_index
);
1733 * @brief Write command directly to serial port
1735 * @param modem modem device struct pointer
1736 * @param command AT command to write
1737 * @param interface which interface to be used to write command
1739 static void gsmd_modem_send_command_raw ( ModemInterface
*modem
,
1740 const gchar
*command
,
1741 InterfaceType interface
)
1743 WriteData
*data
= g_try_new0(WriteData
,1);
1744 data
->command
= g_strdup(command
);
1745 data
->timeoutid
= NULL
;
1747 data
->timeout_data
= NULL
;
1748 data
->timeout_function
= NULL
;
1749 gsmd_modem_serial_write(modem
,data
,interface
);
1753 * @brief Write command directly to serial port
1755 * @param modem modem device struct pointer
1756 * @param command AT command to write
1757 * @param interface which interface to be used to write command
1759 void gsmd_modem_serial_write_simple ( ModemInterface
*modem
,
1760 const gchar
*command
,
1761 InterfaceType interface
)
1763 WriteData
*data
= g_try_new0(WriteData
,1);
1764 data
->command
= g_strdup(command
);
1765 data
->timeoutid
= NULL
;
1767 data
->timeout_data
= NULL
;
1768 data
->timeout_function
= NULL
;
1769 gsmd_modem_serial_write(modem
,data
,interface
);
1773 * @brief Initializes modem
1775 * @param modem pointer to modem to initialize
1777 static void gsmd_modem_init (ModemInterface
* modem
)
1779 Modem
*modem_priv
= (Modem
*)modem
->priv
;
1781 modem_priv
->vendor
= g_new0(VendorInterface
, 1);
1783 gsmd_device_init (modem
);
1784 gsmd_pdp_init (modem
);
1785 gsmd_sim_init (modem
);
1786 gsmd_phonebook_init (modem
);
1787 gsmd_network_init (modem
);
1788 gsmd_call_init (modem
);
1789 gsmd_sms_init (modem
);
1793 gsmd_modem_error_quark (void)
1795 static GQuark quark
;
1797 quark
= g_quark_from_static_string ("gsmd_error");
1803 * @brief Timeout handler
1805 * @param data pointer to Modem, it will be freed by this function
1806 * @return always returns false
1808 static gboolean
gsmd_modem_timeout_handle (gpointer data
)
1810 SerialData
*serial
= (SerialData
*) data
;
1811 guint device_index
= serial
->device_index
;
1812 AtCommandHandlerStatus handled
= AT_HANDLER_DONT_UNDERSTAND
;
1813 Modem
* modem
= serial
->modem
;
1814 AtCommandHandler handler
;
1815 AtCommandContext
*at
= gsmd_modem_get_current_at_command_index ( modem
->modem_if
,
1819 g_warning("%s : No current command!",__func__
);
1822 g_debug("%s: timeout id: %d, userdata: %p",__func__
,at
->timeout_event_id
, data
);
1823 // Setting timeout_event_id to 0 as it is removed when we return FALSE here.
1824 at
->timeout_event_id
= 0;
1825 g_assert( at
->command
);
1826 handler
= at
->command
->handler
;
1828 g_debug("Timeout on command %s\n",at
->command
->command
);
1830 if (modem
->is_timeout
) {
1831 modem
->is_timeout
= FALSE
;//clear the timeout flag
1833 //If it has a handler, test if it can handle TIME_OUT
1835 //copy TIME_OUT string to input buffer
1836 GString
*timeout_buffer
= g_string_new (TIME_OUT
) ;//
1837 gsmd_modem_scanner_init (modem
->modem_if
, timeout_buffer
);
1838 g_debug("Running command's handler for TIME_OUT");
1839 handled
= (*handler
)(modem
->modem_if
, at
, timeout_buffer
);
1840 g_string_free (timeout_buffer
, TRUE
);
1843 //if it couldn't handle it or didn't have a handler, let
1844 //unsolicite handler take care of it
1846 if (!handler
|| (handled
!= AT_HANDLER_DONE
&& handled
!= AT_HANDLER_DONE_ERROR
)) {
1847 gsmd_utils_send_error(at
,
1853 gsmd_modem_finish_command(modem
,device_index
, TRUE
);
1858 /***********************end of service function********************************/
1862 * @brief Change network status and use ipc data if new commands are issued
1864 * @param modem pointer to modem struct
1865 * @param status new network status
1866 * @param error_function error function to call if error occurs
1867 * @param error_data data to be supplied to error function call
1869 void gsmd_modem_change_network_status_data(ModemInterface
*modem
,
1870 NetworkStatus status
,
1872 ErrorFunction error_function
,
1873 gpointer error_data
)
1875 //TODO check that these assumptions are sane
1876 /* Simplified assumptions for actions for new statuses
1877 NETWORK_UNREGISTERED -> clear provider name, send empty status signal
1878 NETWORK_REGISTERED -> ask provider name and signal strength
1879 NETWORK_BUSY -> send empty status signal
1880 NETWORK_DENIED -> send empty status signal
1881 NETWORK_UNKNOWN -> send empty status signal
1882 NETWORK_ROAMING -> ask provider name and signal strength
1885 GString
* message
= g_string_new ("");
1886 g_string_printf(message
, "%d",status
);
1890 gsmd_utils_table_insert_int(modem
->cache
,
1891 GSMD_MODEM_KEY_NETWORK_STATUS
,
1895 case NETWORK_UNREGISTERED
:
1897 case NETWORK_DENIED
:
1898 case NETWORK_UNKNOWN
:
1899 if (modem
->network
->provider_name
) {
1900 g_string_free(modem
->network
->provider_name
,TRUE
);
1902 modem
->network
->provider_name
= g_string_new("");
1903 modem
->network_ipc
->status(modem
->network_ipc
,
1904 modem
->network
->provider_name
->str
,
1908 case NETWORK_ROAMING
:
1909 case NETWORK_REGISTERED
:
1910 gsmd_modem_post_at_command_id( modem
,
1924 g_string_free(message
,TRUE
);
1928 * @brief Change network status
1930 * @param modem modem interface pointer
1933 void gsmd_modem_change_network_status(ModemInterface
*modem
,
1934 NetworkStatus status
)
1936 gsmd_modem_change_network_status_data(modem
,status
,
1943 void gsmd_modem_handle_network_status(ModemInterface
*modem
,
1946 GError
**error
= NULL
;
1947 GRegex
*regex
= g_regex_new ("\\+CREG:\\s(?<status>[0-5]),?(?<lac>\\d*),?(?<id>\\d*)",
1951 GMatchInfo
*match_info
;
1952 NetworkStatus status
= NETWORK_UNKNOWN
;
1953 gchar
*match
= NULL
;
1955 if (g_regex_match (regex
, response
->str
, 0, &match_info
)) {
1956 if (gsmd_utils_match_exists(match_info
,"status")) {
1957 match
= g_match_info_fetch_named(match_info
,
1959 status
= g_ascii_digit_value(match
[0]);
1960 gsmd_modem_change_network_status(modem
,status
);
1965 g_match_info_free (match_info
);
1966 g_regex_unref (regex
);
1971 * @brief Handle's clip messages
1972 * Creates a new call with unknown call id
1974 * @param modem modem whose clip to handle
1975 * @param response string with CLIP
1978 void gsmd_modem_handle_incoming_call(ModemInterface
*modem
,
1981 g_debug("%s",__func__
);
1983 +CLIP: "040123456789",128,"",128,"",0
1985 \+CLIP:\s"(\+?\w+)".*
1988 GError
**error
= NULL
;
1989 GRegex
*regex
= g_regex_new ("\\+CLIP:\\s(?<phone>\"\\+?\\w+\")",
1993 GMatchInfo
*match_info
;
1994 gchar
*match
= NULL
;
1997 if (g_regex_match (regex
, response
->str
, 0, &match_info
)) {
1998 if (gsmd_utils_match_exists(match_info
,"phone")) {
1999 match
= g_match_info_fetch_named(match_info
,
2002 gchar
*number
= NULL
;
2003 if (g_str_equal(match
,"\"\""))
2004 number
= g_strdup("Unknown number");
2006 GString
*temp
= g_string_new(&match
[1]);
2007 g_string_erase(temp
,temp
->len
-1,1);
2008 number
= g_strdup(temp
->str
);
2009 g_string_free(temp
,TRUE
);
2012 g_debug("%s : incoming call from : %s",__func__
,number
);
2014 Call
*call
= gsmd_utils_find_call_number(modem
,number
);
2016 call
= gsmd_utils_new_call(modem
,
2018 "", //TODO type ignored
2022 gsmd_utils_call_send_status(modem
,
2031 g_debug("Didn't understand +clip");
2034 g_match_info_free (match_info
);
2035 g_regex_unref (regex
);
2040 * @brief Finds first call with incoming status and sends call status signal
2041 * Should be called when ring message is received from gsm modem.
2043 * @param modem modem who sent ring message
2046 void gsmd_modem_handle_ring(ModemInterface
*modem
)
2048 Call
*call
= gsmd_utils_find_first_call_status(modem
,CALL_INCOMING
);
2050 gsmd_utils_call_send_status(modem
,
2058 * @brief Handles CCWA (call waiting) messages from modem
2060 * @param modem modem whose call waiting message to handle
2061 * @param response string with CCWA
2064 void gsmd_modem_handle_call_waiting(ModemInterface
*modem
,
2068 +CCWA: "0401234567",129,1,"",0
2073 GError
**error
= NULL
;
2074 GRegex
*regex
= g_regex_new ("\\+CCWA:\\s\"(?<phone>\\+?\\d+)\"",
2078 GMatchInfo
*match_info
;
2079 gchar
*match
= NULL
;
2081 if (g_regex_match (regex
, response
->str
, 0, &match_info
)) {
2082 if (gsmd_utils_match_exists(match_info
,"phone")) {
2083 match
= g_match_info_fetch_named(match_info
,
2086 Call
*call
= gsmd_utils_find_call_number(modem
,match
);
2088 call
= gsmd_utils_new_call(modem
,
2090 "", //TODO type ignored
2095 gsmd_utils_call_send_status(modem
,
2103 g_debug("Didn't understand +ccwa");
2106 g_match_info_free (match_info
);
2107 g_regex_unref (regex
);
2111 * @brief Parses clcc line and applies information to modem's calls
2112 * Can also create new calls if necessary.
2114 * @param modem pointer to modem whose calls to modify
2115 * @param clcc line returned by clcc
2117 void gsmd_modem_apply_current_call(ModemInterface
*modem
, const gchar
*clcc
)
2120 Test data with clip and ecam:
2121 +CLIP: "044123456",128,"",128,"",0
2127 +CLIP: "044123456",128,"",128,"",0
2130 +CLCC: 1,1,4,0,0,"044123456",128,""
2132 Test data with two calls
2133 +CLCC: 1,0,0,0,0,"+35840123456",145,""
2134 +CLCC: 2,1,5,0,0,"044654321",128,""
2138 In the first example #ECAM has call id 0
2139 but CLCC says call id is 1
2140 Call id can't be trusted to be call->vendor_id,
2141 but vendor_id _could_ be clcc's id -1
2143 \+CLCC:\s\d+,(\d),(\d),(\d),\d,"(\+?\d+)"
2146 GError
**error
= NULL
;
2147 GRegex
*regex
= g_regex_new ("\\+CLCC:\\s(?<index>\\d+),(?<direction>\\d),(?<state>\\d),(?<mode>\\d),\\d,\"(?<number>\\+?\\d+)\"",
2151 GMatchInfo
*match_info
;
2153 if (g_regex_match (regex
, clcc
, 0, &match_info
)) {
2154 if (gsmd_utils_match_exists(match_info
,"index")) {
2155 gint id
= gsmd_utils_fetch_match_int(match_info
,
2158 gint state
= gsmd_utils_fetch_match_int(match_info
,
2161 gchar
*number
= g_match_info_fetch_named(match_info
,
2164 //phone number types might cause a problem if modem
2165 //automatically converts them to national/international
2166 //format. This would cause the call to not be found
2167 Call
*call
= gsmd_utils_find_call_number(modem
,number
);
2169 call
= gsmd_utils_new_call(modem
,number
,"",CALL_IDLE
);
2171 //this is merely a guess and should be removed
2172 call
->vendor_id
= id
-1;
2177 call
->status
= CALL_CONNECTED
;
2180 call
->status
= CALL_HOLD
;
2184 call
->status
= CALL_CALLING
;
2188 call
->status
= CALL_INCOMING
;
2192 //Mode is currently ignored
2193 g_debug("%s: Got a call to/from %s with status %s",
2196 gsmd_utils_call_status_to_string(call
->status
));
2204 g_match_info_free (match_info
);
2205 g_regex_unref (regex
);
2210 * @brief Iterates all calls in current calls list in handler data
2211 * and calls gsmd_modem_apply_current_call on each of them
2213 * @param modem modem who own's the calls to parse
2214 * @param table GHashtable containing pointer to current calls list under
2215 * GSMD_MODEM_KEY_CALL_STATUS_ARRAY key
2217 void gsmd_modem_current_calls_parse(ModemInterface
*modem
,GHashTable
*table
)
2222 GValue
*val
= g_hash_table_lookup(table
,
2223 GSMD_MODEM_KEY_CALL_STATUS_ARRAY
);
2228 GList
*list
= g_value_get_pointer(val
);
2231 gchar
*line
= list
->data
;
2232 gsmd_modem_apply_current_call(modem
,line
);
2233 list
= g_list_next( list
);
2238 * @brief Frees current calls array from given at command
2240 * @param at at command context to free current calls array
2243 void gsmd_modem_current_calls_free(AtCommandContext
*at
)
2248 GValue
*val
= g_hash_table_lookup(at
->handler_data
,
2249 GSMD_MODEM_KEY_CALL_STATUS_ARRAY
);
2254 list
= g_value_get_pointer(val
);
2258 list
= g_list_next( list
);
2261 g_list_free(g_value_get_pointer(val
));
2265 AtCommandHandlerStatus
gsmd_modem_handler_current_calls(ModemInterface
*modem
,
2266 AtCommandContext
*at
,
2269 g_debug("%s",__func__
);
2270 GError
**error
= NULL
;
2271 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)",
2275 AtCommandHandlerStatus status
= AT_HANDLER_DONT_UNDERSTAND
;
2276 GMatchInfo
*match_info
;
2280 if (g_regex_match (regex
, response
->str
, 0, &match_info
)) {
2281 if (gsmd_utils_match_exists(match_info
,"index")) {
2284 val
= g_hash_table_lookup(at
->handler_data
,
2285 GSMD_MODEM_KEY_CALL_STATUS_ARRAY
);
2287 list
= g_value_get_pointer(val
);
2289 list
= g_list_append(list
,g_strdup(response
->str
));
2291 gsmd_utils_table_insert_pointer(at
->handler_data
,
2292 GSMD_MODEM_KEY_CALL_STATUS_ARRAY
,
2296 status
= AT_HANDLER_NEED_MORE
;
2297 } else if (gsmd_utils_match_exists(match_info
,"error")) {
2298 gsmd_utils_send_error(at
,
2300 "FAILED TO READ CURRENT CALL LIST");
2301 status
= AT_HANDLER_DONE_ERROR
;
2302 } else if (gsmd_utils_match_exists(match_info
,"timeout")) {
2303 gsmd_utils_send_error(at
,
2305 "TIMEOUT WHEN READING CURRENT CALL LIST");
2306 status
= AT_HANDLER_DONE_ERROR
;
2307 } else if (gsmd_utils_match_exists(match_info
,"ok")) {
2309 val
= g_hash_table_lookup(at
->handler_data
,GSMD_MODEM_KEY_CALL_STATUS_ARRAY
);
2312 gsmd_modem_current_calls_parse(modem
,at
->handler_data
);
2316 status
= AT_HANDLER_DONE
;
2322 g_match_info_free (match_info
);
2323 g_regex_unref (regex
);
2331 * @brief Handler for command to test if modem is alive
2333 * @param modem pointer to modem interface
2334 * @param at current at command's context
2335 * @param response message to handle
2336 * @return handler status
2339 AtCommandHandlerStatus
gsmd_modem_handler_alive(ModemInterface
*modem
,
2340 AtCommandContext
*at
,
2343 g_debug("%s",__func__
);
2344 Modem
*modem_priv
= (Modem
*)modem
->priv
;
2345 GScanner
* scanner
= modem
->scanner
;
2347 //we've got a response, modem is alive. Start initializations
2348 if (scanner
->token
== SYMBOL_OK
) {
2349 if (modem
->status
== MODEM_SERIAL_INIT
) {
2350 modem
->status
= MODEM_INITIALIZING
;
2352 if ( modem_priv
->vendor
->init_at
) {
2353 modem_priv
->vendor
->init_at (modem_priv
->vendor
);
2355 gsmd_modem_general_at_init(modem
);
2358 return AT_HANDLER_DONE
;
2361 //Modem didn't reply or replied with an error
2362 if (scanner
->token
== SYMBOL_TIME_OUT
||
2363 scanner
->token
== SYMBOL_ERROR
) {
2364 modem
->status
= MODEM_UNINITIALIZED
;
2365 modem
->sim_status
= SIM_UNKNOWN
;
2367 //Ask vendor if it can deal with an unresponsive modem
2368 if (modem_priv
->vendor
->not_responding
&&
2369 modem_priv
->vendor
->not_responding(modem_priv
->vendor
))
2370 return AT_HANDLER_RETRY
;
2372 gsmd_modem_close_serial_ports(modem_priv
);
2373 return AT_HANDLER_DONE
;
2377 return AT_HANDLER_DONT_UNDERSTAND
;
2381 * @brief Handles unsolicited messages such as +CREG.
2383 * Unsolicite mesaage is an unexpected message or reply or a reply a
2384 * command's handler didn't understand.
2386 * @param modem pointer to modem interface
2387 * @param at current at command's context
2388 * @param response message to handle
2389 * @return handler status
2392 AtCommandHandlerStatus
gsmd_modem_handler_unsolicite (ModemInterface
*modem
,
2393 AtCommandContext
*at
,
2396 Modem
*modem_priv
= (Modem
*)modem
->priv
;
2397 GScanner
* scanner
= modem
->scanner
;
2399 g_debug("%s", __func__
);
2403 if (g_scanner_eof(scanner
))
2404 return AT_HANDLER_DONE
;
2406 //Let vendor override unsolicite messages first
2407 if (modem_priv
->vendor
->unsolicite_handler
) { //if there is vendor handler
2409 AtCommandHandlerStatus status
;
2410 g_debug("%s: Running vendor_unsolicite_handler", __func__
);
2411 //if vendor handled it, then we dont need to handle it ourselves
2412 status
= modem_priv
->vendor
->unsolicite_handler (modem
, NULL
, response
);
2413 if ( status
!= AT_HANDLER_DONT_UNDERSTAND
) {
2414 g_debug("%s: vendor_unsolicite_handler understood", __func__
);
2418 gsmd_modem_scanner_init (modem
, response
);
2422 g_debug("%s: Running our default handler", __func__
);
2424 switch (scanner
->token
) {
2426 g_scanner_get_next_token (scanner
);
2427 switch (scanner
->token
) {
2429 gsmd_modem_handle_call_waiting(modem
,response
);
2430 case SYMBOL_CLIP
://display the incoming call phoneNo
2431 gsmd_modem_handle_incoming_call(modem
,response
);
2433 case SYMBOL_CRING
://display +CRING: VOICE
2434 gsmd_modem_handle_ring(modem
);
2437 gsmd_modem_handle_network_status(modem
,response
);
2439 case SYMBOL_CMTI
://sms indicator
2440 g_debug("%s: CMTI", __func__
);
2441 sms_pos
= gsmd_modem_sms_indicator_parse (scanner
);
2442 if (sms_pos
> 0 && modem
->sms_ipc
->incoming_message
) {
2443 modem
->sms_ipc
->incoming_message(modem
->sms_ipc
,
2450 g_warning ("Got unrecognized unsolicited symbol: %s\n",
2456 * NOTE! Handling NO CARRIER and BUSY have to be overridden in
2457 * vendor unsolicite handler if multiple concurrent calls are to be
2458 * implemented. By default we assume that only concurrent call
2459 * is possible and we remove the first call in both previously
2462 case SYMBOL_BUSY
://remote hangup the call
2463 g_debug("%s: BUSY", __func__
);
2464 call
= gsmd_utils_call_get_current(modem
);
2467 gsmd_utils_remove_call(modem
,call_id
, TRUE
);
2471 case SYMBOL_RING
://handled in CLIP
2476 g_scanner_get_next_token(scanner
);
2477 if (scanner
->token
== SYMBOL_CARRIER
) {
2478 call
= gsmd_utils_call_get_current(modem
);
2483 gsmd_utils_remove_call(modem
,call_id
, TRUE
);
2486 g_scanner_unexp_token (scanner
,
2501 return AT_HANDLER_DONE
;
2503 /**********************End of Default handler**********************************/
2507 * @brief Re-excute current AT command at the tail of command queue
2509 * @param modem Modem device struct pointer
2511 void gsmd_modem_retry_current_command (Modem
* modem
, InterfaceType interface
)
2513 g_debug("%s: device: %d", __func__
,interface
);
2515 g_assert ( modem
->serial_devices
);
2516 AtCommandContext
*at
= gsmd_modem_get_current_at_command ( modem
->modem_if
,
2518 modem
->is_timeout
= FALSE
;
2521 //Remove old timeout
2522 if (at
->timeout_event_id
!= 0) {
2523 g_debug("%s : Removing timeout id: %d", __func__
, at
->timeout_event_id
);
2524 g_source_remove(at
->timeout_event_id
);
2525 at
->timeout_event_id
= 0;
2529 if (at
->retry_counter
> 0) {
2530 g_debug("Retrying command %s",at
->command
->command
);
2531 at
->retry_counter
--;
2532 gsmd_modem_process_next_command (modem
,interface
);
2534 g_debug("Finished retrying command %s",at
->command
->command
);
2535 gsmd_modem_finish_command(modem
,interface
,FALSE
);
2543 gboolean
gsmd_modem_cancel_command_id(ModemInterface
*modem
,
2545 InterfaceType interface
)
2547 Modem
* modem_priv
= (Modem
*)modem
->priv
;
2548 SerialDevice
*device
= gsmd_modem_get_serial_device(modem_priv
, interface
);
2550 GQueue
* queue
= device
->commandQueue
;
2553 gboolean res
= FALSE
;
2555 gint len
= g_queue_get_length (queue
);
2557 AtCommandContext
* at
= NULL
;
2558 for (i
=0; i
< len
; i
++) { //the tail should not be remove which is handling
2559 at
= (AtCommandContext
*) g_queue_peek_nth (queue
, i
);
2560 if ( at
->command
->cmd_id
== cmd_id
) {
2561 //g_queue_remove (queue, (gpointer) at);
2562 list
= g_list_append (list
, at
);
2567 g_queue_remove (queue
, list
->data
);
2568 gsmd_at_command_context_free(list
->data
);
2569 list
= g_list_next (list
);
2574 gboolean
gsmd_modem_assign_device_indices(ModemInterface
*modem
, int *indices
)
2577 for (i
=0;i
<INTERFACE_LAST
;i
++) {
2578 SerialDevice
*device
= gsmd_modem_get_serial_device_index((Modem
*)modem
->priv
,indices
[i
]);
2582 modem
->interface_devices
[i
]=indices
[i
];
2587 guint
gsmd_modem_get_interface_device_index(ModemInterface
*modem
,
2588 InterfaceType interface
)
2591 return modem
->interface_devices
[interface
];
2593 AtCommand
* gsmd_modem_get_command (ModemInterface
*modem
,
2596 Modem
*modem_priv
= (Modem
*)modem
->priv
;
2597 return (AtCommand
*)g_hash_table_lookup(modem_priv
->commands_table
,
2598 GINT_TO_POINTER(cmd_id
));
2601 void gsmd_modem_reset(ModemInterface
*modem
)
2603 g_debug("%s",__func__
);
2606 modem
->status
= MODEM_RESET
;