d8a90073c9230f9d2c216039264dd735e2761d6f
[libsamsung-ipc.git] / tools / modemctrl.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
5  * Copyright (C) 2011 Paul Kocialkowsk <contact@paulk.fr>
6  *
7  * libsamsung-ipc is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * libsamsung-ipc is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <stdbool.h>
26 #include <termios.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <pthread.h>
33 #include <getopt.h>
34
35 #include <samsung-ipc.h>
36
37 #define MODEM_STATE_LPM     0
38 #define MODEM_STATE_NORMAL  2
39 #define MODEM_STATE_SIM_OK  4
40
41 #define DEF_CALL_NUMBER "950"
42 #define DEF_SIM_PIN     "1234"
43
44 int state = MODEM_STATE_LPM;
45 int seq = 0;
46 int in_call = 0;
47 int out_call = 0;
48 int call_done = 0;
49
50 char sim_pin[8];
51
52 int seq_get(void)
53 {
54     if(seq == 0xff)
55         seq = 0x00;
56
57     seq++;
58
59     return seq;
60 }
61
62 void modem_snd_no_mic_mute(struct ipc_client *client)
63 {
64     uint8_t data = 0;
65     ipc_client_send(client, IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET, (void *) &data, 1, seq_get());
66 }
67
68 void modem_snd_clock_ctrl(struct ipc_client *client)
69 {
70     uint8_t data = 0x01;
71     ipc_client_send(client, IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC, (void *) &data, 1, seq_get());
72 }
73
74 void modem_snd_spkr_volume_ctrl(struct ipc_client *client)
75 {
76     uint16_t data = 0x0411;
77     ipc_client_send(client, IPC_SND_SPKR_VOLUME_CTRL, IPC_TYPE_SET, (void *) &data, 2, seq_get());
78 }
79
80 void modem_snd_audio_path_ctrl(struct ipc_client *client)
81 {
82     uint8_t data = 0x01;
83     ipc_client_send(client, IPC_SND_AUDIO_PATH_CTRL, IPC_TYPE_SET, (void *) &data, 1, seq_get());
84 }
85
86
87 void modem_exec_call_out(struct ipc_client *client, char *num)
88 {
89     struct ipc_call_outgoing_data call_out;
90
91     modem_snd_no_mic_mute(client);
92
93     memset(&call_out, 0, sizeof(struct ipc_call_outgoing_data));
94
95     call_out.type = IPC_CALL_TYPE_VOICE;
96     call_out.identity = IPC_CALL_IDENTITY_DEFAULT;
97     call_out.number_length=strlen(num);
98     /* 0x21 = +33 */
99     call_out.prefix=IPC_CALL_PREFIX_NONE; //0x21;//IPC_CALL_PREFIX_NONE;
100     memcpy(call_out.number, num, call_out.number_length);
101
102     ipc_client_send(client, IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (void *) &call_out, sizeof(struct ipc_call_outgoing_data), seq_get());
103
104     out_call = 1;
105
106     modem_snd_no_mic_mute(client);
107     modem_snd_spkr_volume_ctrl(client);
108     modem_snd_audio_path_ctrl(client);
109 }
110
111 void modem_exec_call_answer(struct ipc_client *client)
112 {
113     modem_snd_clock_ctrl(client);
114
115     ipc_client_send(client, IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL, 0, seq_get());
116
117     modem_snd_no_mic_mute(client);
118 }
119
120 void modem_get_call_list(struct ipc_client *client)
121 {
122     ipc_client_send(client, IPC_CALL_LIST, IPC_TYPE_GET, NULL, 0, seq_get());
123
124     modem_snd_no_mic_mute(client);
125 }
126
127 void modem_exec_power_normal(struct ipc_client *client)
128 {
129     uint16_t data = 0x0202;
130     ipc_client_send(client, IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &data, sizeof(data), seq_get());
131 }
132
133 void modem_set_sms_device_ready(struct ipc_client *client)
134 {
135     ipc_client_send(client, IPC_SMS_DEVICE_READY, IPC_TYPE_SET, NULL, 0, seq_get());
136 }
137
138 void modem_set_sec_pin_status(struct ipc_client *client, char *pin1, char *pin2)
139 {
140     struct ipc_sec_sim_status_request_data pin_status;
141     struct ipc_sec_lock_info_request_data lock_info_req;
142
143     printf("[I] Sending PIN1 unlock request\n");
144
145     ipc_sec_sim_status_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin1, pin2);
146     ipc_client_send(client, IPC_SEC_SIM_STATUS, IPC_TYPE_SET, (void *) &pin_status, sizeof(pin_status), seq_get());
147 }
148
149 void modem_response_sec(struct ipc_client *client, struct ipc_message_info *resp)
150 {
151     struct ipc_sec_sim_status_response_data *sim_status;
152     unsigned char type;
153     int status;
154     char *data;
155
156     switch(IPC_COMMAND(resp))
157     {
158         case IPC_SEC_SIM_STATUS :
159             sim_status = (struct ipc_sec_sim_status_response *)resp->data;
160
161             switch(sim_status->status)
162             {
163                 case IPC_SEC_SIM_STATUS_CARD_NOT_PRESENT:
164                     printf("[I] SIM card is definitely absent\n");
165                 break;
166                 case IPC_SEC_SIM_STATUS_LOCK_SC:
167                     switch(sim_status->facility_lock)
168                     {
169                         case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ:
170                             printf("[I] We need the PIN1 to unlock the card!\n");
171                             if(strlen(sim_pin) > 0) {
172                                 modem_set_sec_pin_status(client, sim_pin, NULL);
173                             } else {
174                                 printf("[E] No SIM Pin, use --pin\n");
175                             }
176                         break;
177                         case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ:
178                             printf("[I] Please provide the SIM card PUK!\n");
179                         break;
180                         case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED:
181                             printf("[I] Ouch, the SIM Card is blocked.\n");
182                         break;
183                     }
184                 break;
185                 case IPC_SEC_SIM_STATUS_INIT_COMPLETE:
186                     printf("[3] SIM init complete\n");
187                     if(state == MODEM_STATE_NORMAL)
188                         state = MODEM_STATE_SIM_OK;
189
190                 break;
191                 case IPC_SEC_SIM_STATUS_PB_INIT_COMPLETE:
192                     printf("[I] SIM Phone Book init complete\n");
193                 break;
194             }
195         break;
196         case IPC_SEC_SIM_ICC_TYPE:
197             type = *((char *) resp->data);
198             switch(type)
199             {
200                 case IPC_SEC_SIM_CARD_TYPE_UNKNOWN:
201                     printf("[I] No SIM card type: unknown (absent?)\n");
202                 break;
203                 case IPC_SEC_SIM_CARD_TYPE_SIM:
204                 case IPC_SEC_SIM_CARD_TYPE_USIM:
205                     printf("[I] SIM card found\n");
206                 break;
207             }
208         break;
209     }
210 }
211
212 void modem_response_sms(struct ipc_client *client, struct ipc_message_info *resp)
213 {
214     switch(IPC_COMMAND(resp))
215     {
216         case IPC_SMS_DEVICE_READY:
217             if(state ==  MODEM_STATE_LPM)
218             {
219                 printf("[4] Modem is ready, requesting normal power mode\n");
220                 modem_exec_power_normal(client);
221             }
222             else if(state == MODEM_STATE_SIM_OK)
223             {
224                 printf("[5] Modem is fully ready\n");
225                 modem_set_sms_device_ready(client);
226             }
227         break;
228     }
229 }
230
231 void modem_response_call(struct ipc_client *client, struct ipc_message_info *resp)
232 {
233     struct ipc_call_status_data *stat;
234
235     switch(IPC_COMMAND(resp))
236     {
237         case IPC_CALL_LIST:
238 /*
239             if(in_call)
240                 modem_exec_call_answer(client);
241             if(out_call)
242                 modem_snd_no_mic_mute(client);
243 */
244         break;
245         case IPC_CALL_INCOMING:
246             printf("[I] Got an incoming call!\n");
247             in_call = 1;
248             modem_get_call_list(client);
249         break;
250         case IPC_CALL_STATUS:
251             stat = (struct ipc_call_status_data *)resp->data;
252
253             if(stat->status == IPC_CALL_STATUS_DIALING)
254             {
255                 printf("[I] Sending clock ctrl and restore alsa\n");
256                 modem_snd_clock_ctrl(client);
257 //        system("alsa_ctl -f /data/alsa_state_modem restore");
258
259                 printf("[I] CALL STATUS DIALING!!!\n");
260
261                 modem_snd_spkr_volume_ctrl(client);
262                 modem_snd_audio_path_ctrl(client);
263
264                 modem_get_call_list(client);
265             }
266             if(stat->status == IPC_CALL_STATUS_CONNECTED)
267             {
268                 printf("[I] CALL STATUS CONNECTED!!!\n");
269                 modem_snd_no_mic_mute(client);
270             }
271             if(stat->status == IPC_CALL_STATUS_RELEASED)
272             {
273                 printf("[I] CALL STATUS RELEASED!!!\n");
274                 modem_snd_no_mic_mute(client);
275             }
276         break;
277     }
278 }
279
280 void modem_response_pwr(struct ipc_client *client, struct ipc_message_info *resp)
281 {
282     int state_n;
283
284     switch(IPC_COMMAND(resp))
285     {
286         case IPC_PWR_PHONE_PWR_UP:
287             printf("[2] Phone is powered up (LPM)!\n");
288             state = MODEM_STATE_LPM;
289         break;
290
291         case IPC_PWR_PHONE_STATE:
292             state_n = *((int *)resp->data);
293 #if 0
294             switch(state_n)
295             {
296                 /* FIXME: Broken */
297                 case IPC_PWR_PHONE_STATE_NORMAL:
298                     printf("Power state is now: NORMAL\n");
299                 break;
300                 case IPC_PWR_PHONE_STATE_LPM:
301                     printf("Power state is now: LPM (Low Power Mode)?\n");
302                 break;
303             }
304 #endif
305             state = state_n;
306         break;
307
308     }
309 }
310
311 void modem_response_net(struct ipc_client *client, struct ipc_message_info *resp)
312 {
313     struct ipc_net_regist_response_data *regi;
314     struct ipc_net_plmn_entry *plmn;
315     char mnc[6];
316
317     switch(IPC_COMMAND(resp))
318     {
319         case IPC_NET_REGIST:
320             regi = (struct ipc_net_regist_response*) resp->data;
321             if(regi->status == IPC_NET_REGISTRATION_STATUS_HOME)
322             {
323                 printf("[I] Registered with network successfully!\n");
324
325             }
326         break;
327         case IPC_NET_CURRENT_PLMN:
328
329             memcpy(mnc, (char *)(resp->data + 3), 5);
330             mnc[5]=0;
331             printf("[6] Registered with network! Got PLMN (Mobile Network Code): '%s'\n", mnc);
332 /*
333             if(call_done == 0)
334             {
335                 printf("Requesting outgoing call to %s!\n", DEF_CALL_NUMBER);
336                 modem_exec_call_out(client, DEF_CALL_NUMBER);
337             }
338             call_done = 1;
339 */
340         break;
341     }
342 }
343
344 void modem_response_handle(struct ipc_client *client, struct ipc_message_info *resp)
345 {
346     switch(resp->group)
347     {
348         case IPC_GROUP_NET:
349             modem_response_net(client, resp);
350         break;
351         case IPC_GROUP_PWR:
352             modem_response_pwr(client, resp);
353         break;
354         case IPC_GROUP_SEC:
355             modem_response_sec(client, resp);
356         break;
357         case IPC_GROUP_SMS:
358             modem_response_sms(client, resp);
359         break;
360         case IPC_GROUP_CALL:
361             modem_response_call(client, resp);
362         break;
363         case IPC_GROUP_DISP:
364             if(in_call)
365                 modem_snd_no_mic_mute(client);
366         break;
367     }
368 }
369
370
371 int modem_read_loop(struct ipc_client *client)
372 {
373     struct ipc_message_info resp;
374     int rc;
375
376     memset(&resp, 0, sizeof(resp));
377
378     while(1) {
379         usleep(3000);
380
381         rc = ipc_client_poll(client, NULL);
382         if (rc < 0) {
383             continue;
384         }
385
386         rc = ipc_client_recv(client, &resp);
387         if(rc < 0) {
388             printf("[E] Can't RECV from modem: please run this again\n");
389             break;
390         }
391
392         modem_response_handle(client, &resp);
393
394         if(resp.data != NULL)
395             free(resp.data);
396     }
397
398     return 0;
399 }
400
401 void modem_log_handler(void *user_data, const char *msg)
402 {
403     int i, l;
404     char *message;
405
406     message = strdup(msg);
407     l = strlen(message);
408
409     if(l > 1) {
410         for(i=l ; i > 0 ; i--)
411         {
412             if(message[i] == '\n') {
413                 message[i] = 0;
414             } else if(message[i] != 0) {
415                 break;
416             }
417         }
418
419         printf("[D] %s\n", message);
420     }
421
422     free(message);
423 }
424
425 void modem_log_handler_quiet(void *user_data, const char *msg)
426 {
427     return;
428 }
429
430 int modem_start(struct ipc_client *client)
431 {
432     int rc = -1;
433
434     ipc_client_data_create(client);
435     ipc_client_bootstrap(client);
436
437     usleep(300);
438
439     rc = ipc_client_open(client);
440     if(rc < 0)
441         return -1;
442
443     rc = ipc_client_power_on(client);
444     if(rc < 0)
445         return -1;
446
447     return 0;
448 }
449
450 int modem_stop(struct ipc_client *client)
451 {
452     ipc_client_power_off(client);
453     ipc_client_close(client);
454
455     return 0;
456 }
457
458 void print_help()
459 {
460     printf("usage: modemctrl <command>\n");
461     printf("commands:\n");
462     printf("\tstart                 bootstrap modem and start read loop\n");
463     printf("\tbootstrap             bootstrap modem only\n");
464     printf("\tpower-on              power on the modem\n");
465     printf("\tpower-off             power off the modem\n");
466     printf("arguments:\n");
467     printf("\t--debug               enable debug messages\n");
468     printf("\t--pin=[PIN]           provide SIM card PIN\n");
469 }
470
471 int main(int argc, char *argv[])
472 {
473     struct ipc_client *client_fmt;
474     int c = 0;
475     int opt_i = 0;
476     int rc = -1;
477     int debug = 0;
478
479     struct option opt_l[] = {
480         {"help",    no_argument,        0,  0 },
481         {"debug",   no_argument,        0,  0 },
482         {"pin",     required_argument,  0,  0 },
483         {0,         0,                  0,  0 }
484     };
485
486     if (argc < 2) {
487         print_help();
488         exit(1);
489     }
490
491     while(c >= 0) {
492         c = getopt_long(argc, argv, "", opt_l, &opt_i);
493         if(c < 0)
494             break;
495
496         switch(c) {
497             case 0:
498                 if (strncmp(opt_l[opt_i].name, "help", 4) == 0) {
499                     print_help();
500                     exit(1);
501                 } else if(strcmp(opt_l[opt_i].name, "debug") == 0) {
502                     debug = 1;
503                     printf("[I] Debug enabled\n");
504                 } else if(strcmp(opt_l[opt_i].name, "pin") == 0) {
505                     if(optarg) {
506                         if(strlen(optarg) < 8) {
507                             printf("[I] Got SIM PIN!\n");
508                             memcpy(sim_pin, optarg, 8);
509                         } else {
510                             printf("[E] SIM PIN is too long!\n");
511                             return 1;
512                         }
513                     }
514                 }
515             break;
516         }
517     }
518
519     client_fmt = ipc_client_create(IPC_CLIENT_TYPE_FMT);
520
521     if (client_fmt == 0) {
522         printf("[E] Could not create IPC client; aborting ...\n");
523         goto modem_quit;
524     }
525
526     if (debug == 0)
527         ipc_client_set_log_callback(client_fmt, modem_log_handler_quiet, NULL);
528     else ipc_client_set_log_callback(client_fmt, modem_log_handler, NULL);
529
530     while(opt_i < argc) {
531         if(strncmp(argv[optind], "power-on", 8) == 0) {
532             if (ipc_client_power_on(client_fmt) < 0)
533                 printf("[E] Something went wrong while powering modem on\n");
534             goto modem_quit;
535         } else if(strncmp(argv[optind], "power-off", 9) == 0) {
536             if (ipc_client_power_off(client_fmt) < 0)
537                 printf("[E] Something went wrong while powering modem off\n");
538             goto modem_quit;
539         } else if (strncmp(argv[optind], "bootstrap", 9) == 0) {
540             ipc_client_bootstrap(client_fmt);
541         } else if(strncmp(argv[optind], "start", 5) == 0) {
542             printf("[0] Starting modem on FMT client\n");
543             rc = modem_start(client_fmt);
544             if(rc < 0) {
545                 printf("[E] Something went wrong\n");
546                 modem_stop(client_fmt);
547                 return 1;
548             }
549
550             printf("[1] Starting modem_read_loop on FMT client\n");
551             modem_read_loop(client_fmt);
552
553             modem_stop(client_fmt);
554         } else {
555             printf("[E] Unknown argument: '%s'\n", argv[optind]);
556             print_help();
557             return 1;
558         }
559
560         optind++;
561     }
562
563 modem_quit:
564     if (client_fmt != 0)
565         ipc_client_destroy(client_fmt);
566
567     return 0;
568 }
569
570 // vim:ts=4:sw=4:expandtab