Serial handling fixes
[gsmd2.git] / vendor / ti-calypso-neo1973.c
blob1979099807ddc5d66cd67ef7579aa10e1afeca9e
1 /*
2 * ti-calypso-neo1973.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 <termios.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <string.h>
35 #include <glib.h>
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,
47 AtCommandContext *at,
48 GString *response);
50 static void neo1973_data_in (ModemInterface *modem,
51 AtCommandContext *at,
52 GString *data);
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,
62 AtCommandContext *at,
63 GString *response);
64 static void neo1973_get_dtmf_duration(CallInterface *call,
65 gpointer ipc_data);
67 enum {
68 NEO_INIT = VENDOR_COMMAND,
69 NEO_WAKEUP,
70 NEO_COPS,
71 NEO_ENABLE_CALL_PROGRESS
73 static const AtCommand
74 commands[] = {
75 //Vendor command
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},
78 //Vendor command
79 { NEO_WAKEUP, "\x1a\r\n" , 100,
80 TRUE, 3,
81 neo1973_handler_wakeup, NULL,SIM_UNKNOWN },
82 //Vendor command
83 { NEO_COPS, "AT+COPS\r\n" , 180000,
84 TRUE, 3,
85 gsmd_utils_handler_ok, NULL,SIM_UNKNOWN,NULL },
86 //Vendor command
87 { NEO_ENABLE_CALL_PROGRESS, "AT%CPI=4\r\n" , 5000,
88 TRUE, 3,
89 gsmd_utils_handler_ok,NULL, SIM_UNKNOWN,NULL },
90 { 0, NULL, 100,
91 TRUE, 1, NULL, NULL, SIM_UNKNOWN,NULL },
92 }, *command_p = commands;
94 enum {
95 SYMBOL_CPI = VENDOR_SYMBOL
98 static const SymbolTable
99 symbols[] = {
100 { "CPI", SYMBOL_CPI, },//vendor command
101 { NULL, 0, },
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,
113 GString *response);
114 } Neo1973;
116 #define GSMD_VENDOR_KEY_CPI "cpi"
118 typedef enum {
119 CPI_SETUP = 0,
120 CPI_DISCONNECT = 1,
121 CPI_ALERT = 2,
122 CPI_CALL_PROCEED = 3,
123 CPI_SYNC = 4,
124 CPI_PROGRESS = 5,
125 CPI_CALL_CONNECTED = 6,
126 CPI_RELEASE = 7,
127 CPI_REJECT = 8,
128 CPI_UNKNOWN = 9,
129 } CpiState;
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);
142 if( error == NULL) {
143 g_debug("%s : control-device: %s", __func__, bool ? "yes": "no");
144 priv->control_device = bool;
145 } else {
146 g_debug("%s : control-device error: %s", __func__, error->message);
147 g_error_free( error );
148 error = NULL;
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__);
158 return FALSE;
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;
176 return TRUE;
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);
189 return FALSE;
191 static gboolean neo1973_wakeup_modem (VendorInterface* vendor)
193 g_debug("%s", __func__);
194 g_timeout_add_seconds(3,
195 neo1973_wakeup,
196 neo1973_priv);
197 return FALSE;
199 static AtCommandHandlerStatus neo1973_handler_wakeup (ModemInterface *modem,
200 AtCommandContext *at,
201 GString *response)
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,
233 NEO_WAKEUP,
234 NULL,
235 NULL,
236 NULL,
237 NULL,
238 NULL );
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);
246 return NULL;
249 static gboolean neo1973_at_init (VendorInterface* vendor)
251 ModemInterface *modem = neo1973_priv->modem;
252 g_assert(modem);
253 g_debug("%s", __func__);
255 // POWER_ON here is need because, for some odd reason,
256 // sequence
257 // at+cpin?
258 // +CPIN: SIM PIN
259 // OK
260 // at+cpin="<pin>"
261 // OK
262 // at+cfun=1
263 // +CME ERROR: 11 (PIN required)
264 // but sequence
265 // at+cfun=1
266 // +CME ERROR: 11 (PIN required)
267 // at+cpin?
268 // +CPIN: SIM PIN
269 // OK
270 // at+cpin="<pin>"
271 // OK
272 // at+cfun=1
273 // OK
275 gsmd_modem_post_at_command_id (modem,
276 POWER_ON,
277 NULL, NULL, NULL, NULL,
278 INTERFACE_GENERAL,
279 NULL);
280 gsmd_modem_post_at_command_id (modem,
281 NEO_INIT,
282 NULL, NULL, NULL, NULL,
283 INTERFACE_GENERAL,
284 NULL);
285 gsmd_modem_post_at_command_id (modem,
286 ENABLE_CMEE,
287 NULL, NULL, NULL, NULL,
288 INTERFACE_GENERAL,
289 NULL);
290 gsmd_modem_post_at_command_id (modem,
291 NETWORK_REGISTER,
292 NULL, NULL, NULL, NULL,
293 INTERFACE_GENERAL,
294 NULL);
295 gsmd_modem_general_at_init (modem);
297 return TRUE;
300 static gboolean neo1973_at_init_sim_ready (VendorInterface* vendor)
302 ModemInterface *modem = neo1973_priv->modem;
303 g_assert(modem);
304 g_debug("%s", __func__);
306 gsmd_modem_post_at_command_id (modem,
307 SMS_INIT,
308 NULL, NULL, NULL, NULL,
309 INTERFACE_GENERAL,
310 NULL);
311 gsmd_modem_post_at_command_id (modem,
312 POWER_ON,
313 NULL, NULL, NULL, NULL,
314 INTERFACE_GENERAL,
315 NULL);
316 gsmd_modem_post_at_command_id (modem,
317 NEO_COPS,
318 NULL, NULL, NULL, NULL,
319 INTERFACE_GENERAL,
320 NULL);
321 gsmd_modem_post_at_command_id (modem,
322 NEO_ENABLE_CALL_PROGRESS,
323 NULL, NULL, NULL, NULL,
324 INTERFACE_GENERAL,
325 NULL);
326 gsmd_modem_general_at_init_sim_ready (modem);
328 return TRUE;
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",
337 NULL
339 static const gchar *file_contents[] = {
340 "1",
341 "0",
342 "1",
343 "0",
344 "1",
345 NULL
347 static gint neo1973_serial_init (VendorInterface *vendor, const gchar *device)
349 gint i = 0;
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");
354 if( f ) {
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]);
360 fclose(f);
361 g_usleep(G_USEC_PER_SEC);
362 } else {
363 g_debug("Failed to open file: %s", files[i]);
366 i++;
368 g_usleep(G_USEC_PER_SEC);
370 return gsmd_utils_default_serial_init(device,
371 CS8 | CRTSCTS | CREAD | B115200,
372 B115200);
375 /********************************/
377 static void neo1973_data_in (ModemInterface *modem,
378 AtCommandContext *at,
379 GString *data)
381 g_get_current_time(&neo1973_priv->last_data_in);
384 static void neo1973_get_dtmf_duration(CallInterface *call,
385 gpointer ipc_data)
387 // It seems that Neo1973 modem does not support AT+VTD command
388 GError *error = g_error_new(GSMD_ERROR,
389 GSMD_ERROR_NOTSUPPORTED,
390 "Not supported");
391 neo1973_priv->modem->call_ipc->send_dtmf_error(neo1973_priv->modem->call_ipc,
392 ipc_data,
393 error);
394 g_error_free(error);
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));
404 symbol_p ++;
407 //add the command to the modem command table
408 while (command_p->command) {
409 gsmd_modem_register_command(modem, command_p);
410 command_p++;
412 vendor->unsolicite_handler = neo1973_unsolicite_handler;
415 static void neo1973_cpi_parse (GScanner* scanner,
416 gint* call_id,
417 CpiState *state)
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
430 } else {
431 g_warning ("%s : unexpexted symbol", __func__);
435 void neo1973_handle_voice_cpi(ModemInterface *modem,
436 CpiState state,
437 gint vendor_id)
440 at%cpi=4
441 atd1234567890;
444 %CPI: 1,9,0,0,0,0,"1234567890",129,,0xc5ff,0 (unknown)
446 %CPRI: 1,2
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)
453 <ring>
455 <answer>
456 %CPI: 1,6,0,1,0,0,"1234567890",129,,0xc500,0 (connected)
457 <hangup>
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)
462 NO CARRIER
464 %CPI: 1,7,1,0,0,0,"1234567890",129,,0x 510,0 (release)
466 ---------------------------------------------
467 <call>
468 %CPRI: 1,2
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)
474 RING
476 +CLIP: "1234567890",129,,,,0
478 %CPI: 1,4,0,1,1,0,"1234567890",129,,0xc506,0 (sync)
480 RING
482 +CLIP: "1234567890",129,,,,0
484 RING
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 -------------------------------------------------------------
499 atd1234567890;
502 %CPI: 1,9,0,0,0,0,"1234567890",129,,0xc5ff,0 (unknown)
504 %CPRI: 1,2
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)
511 <ring>
512 <hangup>
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)
517 BUSY
519 %CPI: 1,7,1,0,0,0,"1234567890",129,,0x 511,0 (release)
524 Call *call = NULL;
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);
532 switch (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);
536 if( !call ) {
537 g_debug("%s : No call found?", __func__);
538 break;
541 if (modem->call_ipc->call_status) {
542 //TODO add properties
543 modem->call_ipc->call_status(modem->call_ipc,
544 call->id,
545 "active",
546 properties);
549 call->status = CALL_CONNECTED;
550 break;
552 case CPI_REJECT:
553 case CPI_DISCONNECT:
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);
557 if( call ) {
558 gsmd_utils_remove_call_vendor_id(modem,vendor_id,TRUE);
559 } else {
560 g_debug("%s : Cannot find call with vendor id %d", __func__, vendor_id);
562 break;
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);
567 if( !call ) {
568 g_debug("%s : No call found?", __func__);
569 break;
571 if (modem->call_ipc->call_status) {
572 gsmd_utils_table_insert_string(properties,
573 GSMD_MODEM_KEY_PHONE_NUMBER,
574 call->number->str);
576 modem->call_ipc->call_status(modem->call_ipc,
577 call->id,
578 "outgoing",
579 properties);
581 break;
582 case CPI_UNKNOWN:
583 g_debug("%s: CPI_UNKNOWN",__func__);
584 break;
585 case CPI_PROGRESS:
586 g_debug("%s: CPI_PROGRESS",__func__);
587 break;
588 case CPI_SYNC:
589 g_debug("%s: CPI_SYNC",__func__);
590 call = gsmd_utils_find_call_vendor_id(modem,vendor_id);
591 if( !call ) {
592 gsmd_utils_set_unknown_vendor_id(modem,vendor_id);
593 call = gsmd_utils_find_call_vendor_id(modem,vendor_id);
594 if( !call ) {
595 g_debug("%s : No call found?", __func__);
596 break;
599 break;
600 case CPI_ALERT:
601 g_debug("%s: CPI_ALERT",__func__);
602 break;
603 case CPI_SETUP:
604 g_debug("%s: CPI_SETUP",__func__);
605 break;
608 g_hash_table_destroy(properties);
610 static AtCommandHandlerStatus neo1973_unsolicite_handler (ModemInterface *modem,
611 AtCommandContext *at,
612 GString *response)
614 // only reponse for parse the vendor token such as %CPI
615 gint vendor_id = -1;
616 GScanner* scanner = modem->scanner;
617 CpiState state = CPI_UNKNOWN;
618 g_debug("%s",__func__);
620 switch (scanner->token) {
622 case '%':
623 g_scanner_get_next_token(scanner);
625 switch (scanner->token) {
626 case SYMBOL_CPI:
627 //%CPRI: 1,2
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;
632 default:
633 break;
635 default:
636 break;
638 return AT_HANDLER_DONT_UNDERSTAND;