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.
36 #include <glib/gstdio.h>
38 #include "../src/modem.h"
39 #include "../src/utils.h"
40 #include "../src/call_interface.h"
41 #include "ti-calypso-neo1973.h"
43 static void neo1973_unsolicite_handler_init (ModemInterface
* modem
,
44 VendorInterface
*vendor
);
46 static AtCommandHandlerStatus
neo1973_unsolicite_handler (ModemInterface
*modem
,
50 static void neo1973_data_in (ModemInterface
*modem
,
54 static gboolean
neo1973_at_init_sim_ready (VendorInterface
* vendor
);
55 static gboolean
neo1973_at_init (VendorInterface
* vendor
);
56 static gboolean
neo1973_wakeup_modem (VendorInterface
* vendor
);
57 static gint
neo1973_serial_init (VendorInterface
*vendor
, const gchar
*device
);
58 static AtCommandContext
* neo1973_command_prepare ( VendorInterface
*vendor
,
59 ModemInterface
*modem
,
60 AtCommandContext
*command
);
61 static AtCommandHandlerStatus
neo1973_handler_wakeup (ModemInterface
*modem
,
64 static void neo1973_get_dtmf_duration(CallInterface
*call
,
68 NEO_INIT
= VENDOR_COMMAND
,
71 NEO_ENABLE_CALL_PROGRESS
73 static const AtCommand
76 { NEO_INIT
, "AT S7=45 S0=0 L1 V1 X4 &c1 E0 Q0\r\n" , 5000,
77 TRUE
, 0, NULL
,NULL
, SIM_UNKNOWN
,NULL
},
79 { NEO_WAKEUP
, "\x1a\r\n" , 100,
81 neo1973_handler_wakeup
, NULL
,SIM_UNKNOWN
},
83 { NEO_COPS
, "AT+COPS\r\n" , 180000,
85 gsmd_utils_handler_ok
, NULL
,SIM_UNKNOWN
,NULL
},
87 { NEO_ENABLE_CALL_PROGRESS
, "AT%CPI=4\r\n" , 5000,
89 gsmd_utils_handler_ok
,NULL
, SIM_UNKNOWN
,NULL
},
91 TRUE
, 1, NULL
, NULL
, SIM_UNKNOWN
,NULL
},
92 }, *command_p
= commands
;
95 SYMBOL_CPI
= VENDOR_SYMBOL
98 static const SymbolTable
100 { "CPI", SYMBOL_CPI
, },//vendor command
102 }, *symbol_p
= symbols
;
104 typedef struct _Neo1973
{
105 ModemInterface
*modem
;
106 gboolean need_wakeup
;
107 gboolean control_device
;
108 GTimeVal last_data_in
;
110 void (*orig_sim_auth_status
) (SIMIPCInterface
*sim_ipc
, const char *status
);
111 AtCommandHandlerStatus (*orig_call_initiate_handler
) (ModemInterface
*modem
,
112 AtCommandContext
*at
,
116 #define GSMD_VENDOR_KEY_CPI "cpi"
122 CPI_CALL_PROCEED
= 3,
125 CPI_CALL_CONNECTED
= 6,
133 static Neo1973
*neo1973_priv
= NULL
;
135 static void neo1973_read_conf(Neo1973
*priv
)
137 g_debug("%s", __func__
);
138 if( priv
->modem
->conf_file
) {
139 GKeyFile
*conf
= priv
->modem
->conf_file
;
140 GError
*error
= NULL
;
141 gboolean
bool = g_key_file_get_boolean(conf
, "ticalypsoneo1973", "control-device",&error
);
143 g_debug("%s : control-device: %s", __func__
, bool ? "yes": "no");
144 priv
->control_device
= bool;
146 g_debug("%s : control-device error: %s", __func__
, error
->message
);
147 g_error_free( error
);
152 /** vendor_handle_init should be called from modem.c when the lib loaded*/
153 gboolean
vendor_handle_init (ModemInterface
* modem
, VendorInterface
*vendor
)
155 g_debug("%s", __func__
);
156 if ( neo1973_priv
) {
157 g_warning("%s : Already initialized!", __func__
);
160 neo1973_priv
= g_new0(Neo1973
, 1);
161 neo1973_priv
->need_wakeup
= FALSE
;
162 neo1973_priv
->control_device
= TRUE
;
163 neo1973_priv
->modem
= modem
;
164 neo1973_read_conf(neo1973_priv
);
165 vendor
->init_at_sim_ready
= neo1973_at_init_sim_ready
;
166 vendor
->init_at
= neo1973_at_init
;
167 vendor
->data_in
= neo1973_data_in
;
168 vendor
->init_serial
= neo1973_serial_init
;
169 vendor
->wakeup_modem
= neo1973_wakeup_modem
;
170 vendor
->command_prepare
= neo1973_command_prepare
;
171 vendor
->priv
= (gpointer
)neo1973_priv
;
172 neo1973_unsolicite_handler_init (modem
, vendor
);
175 modem
->call
->get_dtmf_duration
= &neo1973_get_dtmf_duration
;
178 /*************************************/
179 /* if need replace default at_command, vendor at_init bellow*/
181 static gboolean
neo1973_wakeup (gpointer data
)
183 Neo1973
*priv
= (Neo1973
*)data
;
184 g_debug("%s",__func__
);
185 if(gsmd_modem_serial_write_simple(priv
->modem
, "\x1a", INTERFACE_GENERAL
)) {
186 g_usleep(0.2*G_USEC_PER_SEC
);
187 gsmd_modem_post_alive_test(priv
->modem
, TRUE
);
191 static gboolean
neo1973_wakeup_modem (VendorInterface
* vendor
)
193 g_debug("%s", __func__
);
194 g_timeout_add_seconds(3,
199 static AtCommandHandlerStatus
neo1973_handler_wakeup (ModemInterface
*modem
,
200 AtCommandContext
*at
,
203 g_debug("%s", __func__
);
204 GScanner
* scanner
= modem
->scanner
;
205 if (scanner
->token
== SYMBOL_OK
) {
206 neo1973_priv
->need_wakeup
= FALSE
;
207 return AT_HANDLER_DONE
;
208 } else if(scanner
->token
== SYMBOL_ERROR
) {
209 neo1973_priv
->need_wakeup
= FALSE
;
210 return AT_HANDLER_DONE_ERROR
;
211 } else if(scanner
->token
== SYMBOL_TIME_OUT
) {
212 g_warning("%s : TIMEOUT", __func__
);
213 neo1973_priv
->need_wakeup
= TRUE
;
214 /* gsmd_modem_reset(modem); */
215 return AT_HANDLER_RETRY
;
217 return AT_HANDLER_DONT_UNDERSTAND
;
220 static AtCommandContext
* neo1973_command_prepare ( VendorInterface
*vendor
,
221 ModemInterface
*modem
,
222 AtCommandContext
*command
)
224 GTimeVal time
= {0,};
225 Neo1973
*priv
= (Neo1973
*)vendor
->priv
;
226 g_get_current_time(&time
);
227 if( priv
->last_data_in
.tv_sec
== 0
228 && command
->command
->cmd_id
!= NEO_WAKEUP
) {
229 g_debug("%s : First wakeup", __func__
);
230 gsmd_modem_serial_write_simple(modem
, "\x1a", INTERFACE_GENERAL
);
231 g_usleep(0.2*G_USEC_PER_SEC
);
232 return gsmd_at_command_context_new_from_id( modem
,
241 if( time
.tv_sec
- priv
->last_data_in
.tv_sec
>= 5) {
242 g_debug("%s : Need wakeup", __func__
);
243 gsmd_modem_serial_write_simple(modem
, "\x1a", INTERFACE_GENERAL
);
244 g_usleep(0.2*G_USEC_PER_SEC
);
249 static gboolean
neo1973_at_init (VendorInterface
* vendor
)
251 ModemInterface
*modem
= neo1973_priv
->modem
;
253 g_debug("%s", __func__
);
255 // POWER_ON here is need because, for some odd reason,
263 // +CME ERROR: 11 (PIN required)
266 // +CME ERROR: 11 (PIN required)
275 gsmd_modem_post_at_command_id (modem
,
277 NULL
, NULL
, NULL
, NULL
,
280 gsmd_modem_post_at_command_id (modem
,
282 NULL
, NULL
, NULL
, NULL
,
285 gsmd_modem_post_at_command_id (modem
,
287 NULL
, NULL
, NULL
, NULL
,
290 gsmd_modem_post_at_command_id (modem
,
292 NULL
, NULL
, NULL
, NULL
,
295 gsmd_modem_general_at_init (modem
);
300 static gboolean
neo1973_at_init_sim_ready (VendorInterface
* vendor
)
302 ModemInterface
*modem
= neo1973_priv
->modem
;
304 g_debug("%s", __func__
);
306 gsmd_modem_post_at_command_id (modem
,
308 NULL
, NULL
, NULL
, NULL
,
311 gsmd_modem_post_at_command_id (modem
,
313 NULL
, NULL
, NULL
, NULL
,
316 gsmd_modem_post_at_command_id (modem
,
318 NULL
, NULL
, NULL
, NULL
,
321 gsmd_modem_post_at_command_id (modem
,
322 NEO_ENABLE_CALL_PROGRESS
,
323 NULL
, NULL
, NULL
, NULL
,
326 gsmd_modem_general_at_init_sim_ready (modem
);
331 static const gchar
*files
[] = {
332 "/sys/bus/platform/devices/neo1973-pm-gsm.0/download",
333 "/sys/bus/platform/devices/neo1973-pm-gsm.0/power_on",
334 "/sys/bus/platform/devices/neo1973-pm-gsm.0/power_on",
335 "/sys/bus/platform/devices/neo1973-pm-gsm.0/reset",
336 "/sys/bus/platform/devices/neo1973-pm-gsm.0/reset",
339 static const gchar
*file_contents
[] = {
347 static gint
neo1973_serial_init (VendorInterface
*vendor
, const gchar
*device
)
350 if( neo1973_priv
->control_device
) {
351 while( files
[i
] && file_contents
[i
] ) {
352 if( g_file_test(files
[i
], G_FILE_TEST_IS_REGULAR
) ) {
353 FILE *f
= g_fopen(files
[i
],"wb");
355 gint len
= strlen(file_contents
[i
]);
356 gint written
= fwrite (file_contents
[i
], 1,len
, f
);
357 if( written
< len
) {
358 g_debug("Failed to write file: %s", files
[i
]);
361 g_usleep(G_USEC_PER_SEC
);
363 g_debug("Failed to open file: %s", files
[i
]);
368 g_usleep(G_USEC_PER_SEC
);
370 return gsmd_utils_default_serial_init(device
,
371 CS8
| CRTSCTS
| CREAD
| B115200
,
375 /********************************/
377 static void neo1973_data_in (ModemInterface
*modem
,
378 AtCommandContext
*at
,
381 g_get_current_time(&neo1973_priv
->last_data_in
);
384 static void neo1973_get_dtmf_duration(CallInterface
*call
,
387 // It seems that Neo1973 modem does not support AT+VTD command
388 GError
*error
= g_error_new(GSMD_ERROR
,
389 GSMD_ERROR_NOTSUPPORTED
,
391 neo1973_priv
->modem
->call_ipc
->send_dtmf_error(neo1973_priv
->modem
->call_ipc
,
396 static void neo1973_unsolicite_handler_init(ModemInterface
*modem
,
397 VendorInterface
*vendor
)
399 g_debug("%s", __func__
);
400 //add the symbol to the modem scanner
401 while (symbol_p
->symbol_name
) {
402 g_scanner_add_symbol (modem
->scanner
, symbol_p
->symbol_name
,
403 GINT_TO_POINTER(symbol_p
->symbol_token
));
407 //add the command to the modem command table
408 while (command_p
->command
) {
409 gsmd_modem_register_command(modem
, command_p
);
412 vendor
->unsolicite_handler
= neo1973_unsolicite_handler
;
415 static void neo1973_cpi_parse (GScanner
* scanner
,
419 /* From http://svn.openmoko.org/trunk/src/target/gsm/src/gsmd/vendor_ti.c (revision 4442) */
420 /* Format: cId, msgType, ibt, tch, dir,[mode],[number],[type],[alpha],[cause],line */
421 g_scanner_get_next_token (scanner
);
422 if (scanner
->token
== ':') {
423 g_scanner_get_next_token (scanner
);
424 *call_id
= scanner
->value
.v_int
;
426 g_scanner_get_next_token (scanner
);//get ;
427 g_scanner_get_next_token (scanner
);
428 *state
= scanner
->value
.v_int
;
429 // TODO handle rest of the data
431 g_warning ("%s : unexpexted symbol", __func__
);
435 void neo1973_handle_voice_cpi(ModemInterface
*modem
,
444 %CPI: 1,9,0,0,0,0,"1234567890",129,,0xc5ff,0 (unknown)
448 %CPI: 1,3,0,0,0,0,"1234567890",129,,0xc5ff,0 (call proceed)
450 %CPI: 1,4,0,1,0,0,"1234567890",129,,0xc506,0 (sync)
452 %CPI: 1,2,1,1,0,0,"1234567890",129,,0xc5ff,0 (alert)
456 %CPI: 1,6,0,1,0,0,"1234567890",129,,0xc500,0 (connected)
458 %CPI: 1,1,1,1,0,0,"1234567890",129,,0x 510,0 (disconnect)
460 %CPI: 1,1,1,0,0,0,"1234567890",129,,0x 510,0 (disconnect)
464 %CPI: 1,7,1,0,0,0,"1234567890",129,,0x 510,0 (release)
466 ---------------------------------------------
470 %CPI: 1,0,0,0,1,0,"1234567890",129,,0xc5ff,0 (setup)
472 %CPI: 1,0,0,1,1,0,"1234567890",129,,0xc506,0 (setup)
476 +CLIP: "1234567890",129,,,,0
478 %CPI: 1,4,0,1,1,0,"1234567890",129,,0xc506,0 (sync)
482 +CLIP: "1234567890",129,,,,0
486 +CLIP: "1234567890",129,,,,0
490 %CPI: 1,6,0,1,1,0,"1234567890",129,,0xc500,0 (connected)
494 %CPI: 1,1,0,0,1,0,"1234567890",129,,0x85ff,0 (disconnect)
496 %CPI: 1,7,0,0,1,0,"1234567890",129,,0x85ff,0 (release)
498 -------------------------------------------------------------
502 %CPI: 1,9,0,0,0,0,"1234567890",129,,0xc5ff,0 (unknown)
506 %CPI: 1,3,0,0,0,0,"1234567890",129,,0xc5ff,0 (call proceed)
508 %CPI: 1,4,0,1,0,0,"1234567890",129,,0xc506,0 (sync)
510 %CPI: 1,2,1,1,0,0,"1234567890",129,,0xc5ff,0 (alert)
513 %CPI: 1,1,1,1,0,0,"1234567890",129,,0x 511,0 (disconnect)
515 %CPI: 1,1,1,0,0,0,"1234567890",129,,0x 511,0 (disconnect)
519 %CPI: 1,7,1,0,0,0,"1234567890",129,,0x 511,0 (release)
525 g_debug("%s : call vendor id: %d, state: %d", __func__
, vendor_id
,state
);
526 GHashTable
*properties
= gsmd_utils_create_hash_table();
529 gsmd_utils_table_insert_int(properties
,GSMD_VENDOR_KEY_CPI
,state
);
533 case CPI_CALL_CONNECTED
://Phone call established
534 g_debug("%s: CPI_CALL_CONNECTED",__func__
);
535 call
= gsmd_utils_find_call_vendor_id(modem
,vendor_id
);
537 g_debug("%s : No call found?", __func__
);
541 if (modem
->call_ipc
->call_status
) {
542 //TODO add properties
543 modem
->call_ipc
->call_status(modem
->call_ipc
,
549 call
->status
= CALL_CONNECTED
;
554 case CPI_RELEASE
://Got disconnected
555 g_debug("%s: CPI_RELEASE, CPI_DISCONNECT or CPI_REJECT",__func__
);
556 call
= gsmd_utils_find_call_vendor_id(modem
,vendor_id
);
558 gsmd_utils_remove_call_vendor_id(modem
,vendor_id
,TRUE
);
560 g_debug("%s : Cannot find call with vendor id %d", __func__
, vendor_id
);
563 case CPI_CALL_PROCEED
://We are calling someone
564 g_debug("%s: CPI_CALL_PROCEED",__func__
);
565 gsmd_utils_set_unknown_vendor_id(modem
,vendor_id
);
566 call
= gsmd_utils_find_call_vendor_id(modem
,vendor_id
);
568 g_debug("%s : No call found?", __func__
);
571 if (modem
->call_ipc
->call_status
) {
572 gsmd_utils_table_insert_string(properties
,
573 GSMD_MODEM_KEY_PHONE_NUMBER
,
576 modem
->call_ipc
->call_status(modem
->call_ipc
,
583 g_debug("%s: CPI_UNKNOWN",__func__
);
586 g_debug("%s: CPI_PROGRESS",__func__
);
589 g_debug("%s: CPI_SYNC",__func__
);
590 call
= gsmd_utils_find_call_vendor_id(modem
,vendor_id
);
592 gsmd_utils_set_unknown_vendor_id(modem
,vendor_id
);
593 call
= gsmd_utils_find_call_vendor_id(modem
,vendor_id
);
595 g_debug("%s : No call found?", __func__
);
601 g_debug("%s: CPI_ALERT",__func__
);
604 g_debug("%s: CPI_SETUP",__func__
);
608 g_hash_table_destroy(properties
);
610 static AtCommandHandlerStatus
neo1973_unsolicite_handler (ModemInterface
*modem
,
611 AtCommandContext
*at
,
614 // only reponse for parse the vendor token such as %CPI
616 GScanner
* scanner
= modem
->scanner
;
617 CpiState state
= CPI_UNKNOWN
;
618 g_debug("%s",__func__
);
620 switch (scanner
->token
) {
623 g_scanner_get_next_token(scanner
);
625 switch (scanner
->token
) {
628 neo1973_cpi_parse(scanner
,&vendor_id
,&state
);
629 g_debug("%s : call vendor id: %d", __func__
, vendor_id
);
630 neo1973_handle_voice_cpi(modem
,state
,vendor_id
);
631 return AT_HANDLER_DONE
;
638 return AT_HANDLER_DONT_UNDERSTAND
;