Revert manifest to default one
[profile/ivi/tel-plugin-atmodem.git] / src / desc_at.c
1 /*
2  * tel-plugin-atmodem
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hayoon Ko <hayoon.ko@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <glib.h>
26
27 #include <tcore.h>
28 #include <plugin.h>
29 #include <hal.h>
30 #include <server.h>
31 #include <queue.h>
32
33 #include "s_common.h"
34 #include "s_sim.h"
35 #include "s_ps.h"
36 #include "s_call.h"
37 #include "s_ss.h"
38 #include "s_sms.h"
39 #include "s_network.h"
40 #include "s_modem.h"
41 #include "atchannel.h"
42 #include "at_tok.h"
43
44 static char s_ATBuffer[MAX_AT_RESPONSE+1];
45 static char *s_ATBufferCur = s_ATBuffer;
46
47 struct sms_pdu_control
48 {
49          gboolean sms_pdu_mode;
50
51          int sms_pdu_len;
52          int cum_pdu_len;
53          char* line1 ;
54          char* ppdu ;
55          char* ppdu_marker;
56 };
57
58 static struct sms_pdu_control spc;
59
60 static int s_readCount = 0;
61
62 enum ATCommandType s_type;
63 char *s_responsePrefix= NULL;
64 struct ATResponse *sp_response= NULL;
65
66
67 static const char * s_smsUnsoliciteds[] = {
68     "+CMT:"
69 };
70
71 static int isSMSUnsolicited(const char *line)
72 {
73     unsigned int i;
74
75     for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
76         if (strStartsWith(line, s_smsUnsoliciteds[i])) {
77             return 1;
78         }
79     }
80
81     return 0;
82 }
83
84 static void startSMSBuffering(char* line)
85 {
86         char* temp_line = NULL;
87         int sms_pdu_len;
88
89         spc.line1 = strdup(line);
90
91         temp_line = line;
92
93         at_tok_start(&temp_line);
94         at_tok_nextint(&temp_line, &sms_pdu_len);
95
96         dbg("total pdu length : %d", sms_pdu_len);
97         spc.sms_pdu_len = sms_pdu_len;
98
99         //allocate pdu buffer
100         spc.ppdu = malloc(sizeof(char) *sms_pdu_len);
101         spc.sms_pdu_mode = TRUE;
102         spc.cum_pdu_len = 0;
103 }
104
105 static void stopSMSBuffering()
106 {
107         if(spc.line1 != NULL)
108                 free(spc.line1);
109         spc.line1 = NULL;
110
111         spc.sms_pdu_len = 0;
112         spc.cum_pdu_len =0;
113
114         spc.sms_pdu_mode = FALSE;
115
116         if(spc.ppdu !=NULL)
117                 free(spc.ppdu);
118         spc.ppdu = NULL;
119
120         spc.ppdu_marker = NULL;
121
122         dbg("sms pdu data buffering ended!");
123 }
124
125 static void handleFinalResponse(TcoreHal* hal, const char *line)
126 {
127         dbg("Final response arrived. call response callback");
128
129         // 1. add final rsp string into sp_response
130         sp_response->finalResponse = strdup(line);
131
132         // 1.1 reverse intermediates
133         reverseIntermediates(sp_response);
134
135         // 2. pop head pending from queue -> call callback hung pending(on_response) ->
136         //      release sp_response/s_responsePrefix -> release userRequest/pending -> send next pending from queue
137         //      warning) length have no meaning. data always pointer sp_response
138         tcore_hal_dispatch_response_data(hal, ID_RESERVED_AT, strlen(line), sp_response);
139 }
140
141 static void onUnsolicited (const char *s, TcorePlugin* plugin, char* sms_pdu, int pdu_len)
142 {
143         char *line = NULL, *p= NULL;
144         char *cmd = NULL;
145         struct smsDeliveryPDU smsPdu;
146
147         int id;
148         int status, direction;
149
150 #define STATUS_INCOMING 4
151 #define STATUS_WAITING 5
152
153
154         if(strStartsWith(s,"+CMT:")){
155                 //SMS incoming
156                 cmd = EVENT_SMS_INCOM_MSG;
157
158                 smsPdu.cmdLine = strdup(s);
159                 smsPdu.pdu = malloc(pdu_len);
160                 memcpy(smsPdu.pdu, sms_pdu, pdu_len);
161                 smsPdu.len = pdu_len;
162
163                 tcore_plugin_core_object_event_emit(plugin, cmd, &smsPdu);
164                 free(smsPdu.cmdLine);
165                 free(smsPdu.pdu);
166
167                 return;
168         }
169         /* Ignore unsolicited responses until we're initialized.
170         * This is OK because the RIL library will poll for initial state
171         */
172         else if (strStartsWith(s,"%SCFUN:")){
173         /* SS specific -- modem power status notification */
174                 cmd = EVENT_MODEM_PHONE_STATE;
175         }
176         else if(strStartsWith(s,"%SCSIM:")){
177                 cmd = EVENT_SIM_PIN_STATUS;
178         }
179         else if(strStartsWith(s,"%SCLCC:")){
180                 line = strdup(s);
181                 p = line;
182
183                 at_tok_start(&p);
184                 at_tok_nextint(&p, &id);
185                 at_tok_nextint(&p, &direction);
186                 at_tok_nextint(&p, &status);
187
188                 switch(status){
189                         case STATUS_INCOMING:
190                                 cmd = EVENT_CALL_INCOMING;
191                         break;
192                         case STATUS_WAITING:
193                                 cmd = EVENT_CALL_WAITING;
194                         break;
195                         default:
196                                 cmd = EVENT_CALL_STATUS;
197                         break;
198                 }
199
200                 free(line);
201
202                 dbg("%SCLCC cmd : %d",cmd);
203         }
204         else if (strStartsWith(s,"+CRING:")
205                 || strStartsWith(s,"RING")){
206                 dbg("incoming call notification - wait for SCLCC with status 4");
207                 return;
208         }
209         else if (strStartsWith(s,"CONNECT")){
210                 dbg("call connect notification - wait for SCLCC with status 0");
211                 return;
212         }
213         else if (strStartsWith(s,"NO CARRIER")){
214                 dbg("call release notification - wait for SCLCC with status 7");
215                 return ;
216         }
217         else if(strStartsWith(s,"+CCWA:")){
218                 dbg("call waiting notification - wait for SCLCC with status 5");
219                 return;
220         }
221         else if (strStartsWith(s,"+CREG:")
222                 || strStartsWith(s,"+CGREG:")){
223                 cmd = EVENT_NETWORK_REGISTRATION;
224         }
225         else if (strStartsWith(s,"+CMGS:"))     {
226                 cmd = EVENT_SMS_SEND_ACK;
227         }
228         else if (strStartsWith(s,"%SCDEV:"))    {
229                 cmd = EVENT_SMS_DEVICE_READY;
230         }
231         else if(strStartsWith(s,"+CIEV:")){
232                 cmd = EVENT_NETWORK_ICON_INFO;
233         }
234         else if (strStartsWith(s,"+CSSU:")){
235                 cmd = EVENT_SS_INFO;
236         }
237         else if (strStartsWith(s,"+CUSD:")){
238                 cmd = EVENT_SS_USSD;
239         }
240
241         /* Send Event */
242         if(cmd)
243         {
244                 line = strdup(s);
245                 tcore_plugin_core_object_event_emit(plugin, cmd, line);
246                 free(line);
247         }
248
249 }
250
251 static void processLine(TcoreHal *hal, char *line, TcorePlugin* p)
252 {
253         TcoreQueue* pPendingQueue = NULL;
254         TcorePending* pPending =NULL;
255         gboolean result_status = FALSE;
256         pPendingQueue =(TcoreQueue*)tcore_hal_ref_queue(hal);
257         pPending = (TcorePending*)tcore_queue_ref_head(pPendingQueue); //topmost request
258
259         dbg("processLine -------start");
260
261         if(TCORE_RETURN_SUCCESS == tcore_pending_get_send_status(pPending, &result_status)
262                 && (result_status == FALSE))//request not sent but data comes - Unsolicited msg!
263         {
264                 /* no command pending */
265                 dbg("no command pending. call onUnsolicited()");
266                 onUnsolicited(line, p, NULL, 0);
267         } else if (isFinalResponseSuccess(line)) {
268                 dbg("final response -success. call handleFinalResponse()");
269                 sp_response->success = 1;
270                 handleFinalResponse(hal, line);
271         } else if (isFinalResponseError(line)) {
272                 dbg("final response -ERROR. call handleFinalResponse()");
273                 sp_response->success = 0;
274                 handleFinalResponse(hal, line);
275         } else switch (s_type) {
276                 case NO_RESULT:
277                 {
278                         dbg("[NO_RESULT]:call onUnsolicited()");
279                         onUnsolicited(line, p, NULL, 0);
280                 }
281                 break;
282                 case NUMERIC:
283                 {
284                         if (sp_response->p_intermediates == NULL
285                                 && isdigit(line[0])
286                         ) {
287                                 dbg("[NUMERIC]:line[0] is digit. call addIntermediate()");
288                                 addIntermediate(line);
289                         } else {
290                                 /* either we already have an intermediate response or
291                                 the line doesn't begin with a digit */
292                                 dbg("[NUMERIC]:either we already have an intermediate response or the line doesn't begin with a digit. call onUnsolicited()");
293                                 onUnsolicited(line,p,NULL, 0);
294                         }
295                 }
296                 break;
297                 case SINGLELINE:
298                 {
299                         if (sp_response->p_intermediates == NULL
300                                 && strStartsWith (line, s_responsePrefix)
301                         ) {
302                                 dbg("[SINGLELINE]:line starts with s_responsePrefix. call addIntermediate()");
303                                 addIntermediate(line);
304                         } else {
305                                 /* we already have an intermediate response */
306                                 dbg("[SINGLELINE]:we already have an intermediate response. call onUnsolicited()");
307                                 onUnsolicited(line,p, NULL, 0);
308                         }
309                 }
310                 break;
311                 case MULTILINE:
312                 if (strStartsWith (line, s_responsePrefix)) {
313                         dbg("[MULTILINE]:line starts with s_responsePrefix. call addIntermediate()");
314                         addIntermediate(line);
315                 } else {
316                         dbg("[MULTILINE]:line don't starts with s_responsePrefix. call onUnsolicited()");
317                         onUnsolicited(line,p, NULL, 0);
318                 }
319                 break;
320
321                 default: /* this should never be reached */
322                         err("Unsupported AT command type %d\n", s_type);
323                         onUnsolicited(line,p, NULL, 0);
324                 break;
325         }
326 }
327
328 static gboolean readline(TcoreHal *hal, unsigned int data_len, const void *data, TcorePlugin* p)
329 {
330         char *ret;
331         char *p_read = NULL;
332         char *p_eol = NULL;
333         char *p_marker = NULL;
334         int len, leftover_len;
335
336         char* act_data;
337         int act_len;
338
339         act_data = (char*)data;
340         act_len = data_len;
341
342         dbg("recv string = %s, length : %d", (char*)act_data, act_len);
343         /* this is a little odd. I use *s_ATBufferCur == 0 to
344         * mean "buffer consumed completely". If it points to a character, than
345         * the buffer continues until a \0
346         */
347
348         /*check sms pdu cumulating process - data hijacking*/
349         if(spc.sms_pdu_mode == TRUE)
350         { //continue sms pdu buffering
351                 dbg("resume pdu buffering. pdu size : %d, gathered size : %d",spc.sms_pdu_len,spc.cum_pdu_len);
352                 len = spc.sms_pdu_len - spc.cum_pdu_len; //length needed
353
354                 if(act_len > len){
355                         dbg("whole pdu received - data surplus");
356                         memcpy(spc.ppdu_marker, act_data,len);//data fully copied
357                         spc.cum_pdu_len = spc.cum_pdu_len + len;
358
359                         //change data & datalen
360                         act_data = act_data + len;
361                         act_len = act_len - len;
362                         dbg("recv string changed to = %s, length changed to : %d", (char*)act_data, act_len);
363
364                         onUnsolicited(spc.line1, p, spc.ppdu, spc.sms_pdu_len);
365                         stopSMSBuffering();
366                         dbg("incoming sms handled. back to normal mode & continue");
367                 }
368                 else if(act_len == len){
369                         dbg("exactly whole pdu received");
370
371                         memcpy(spc.ppdu_marker, act_data,len);//data fully copied
372                         spc.cum_pdu_len = spc.cum_pdu_len + len;
373
374                         onUnsolicited(spc.line1, p, spc.ppdu, spc.sms_pdu_len);
375                         stopSMSBuffering();
376                         dbg("all incoming data consumed. return");
377                         return TRUE;
378                 }
379                 else    {
380                         dbg("data received but not sufficient");
381                         memcpy(spc.ppdu_marker, act_data,act_len);
382                         spc.ppdu_marker = spc.ppdu_marker +act_len;
383                         spc.cum_pdu_len = spc.cum_pdu_len + act_len;
384                         dbg("data buffered. wait for more data");
385                         return TRUE;
386                 }
387         }
388
389
390         if (*s_ATBufferCur == '\0')
391         {
392                 /* empty buffer */
393                 s_ATBufferCur = s_ATBuffer;
394                 *s_ATBufferCur = '\0';
395                 p_read = s_ATBuffer;
396         }
397         else
398         {
399                 /* *s_ATBufferCur != '\0' */
400                 /* there's data in the buffer from the last read */
401
402                 // skip over leading newlines
403                 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
404                         s_ATBufferCur++;
405
406                 p_eol = findNextEOL(s_ATBufferCur);
407
408                 if (p_eol == NULL)
409                 {
410                         /* a partial line. move it up and prepare to read more */
411                         unsigned int  len;
412                         len = strlen(s_ATBufferCur);
413
414                         memmove(s_ATBuffer, s_ATBufferCur, len + 1);
415                         p_read = s_ATBuffer + len;
416                         s_ATBufferCur = s_ATBuffer;
417                 }
418                 /* Otherwise, (p_eol !- NULL) there is a complete line  */
419                 else
420                 {
421                         err("this should not be happening - complete data pending??");
422                 }
423
424         }
425
426         if (0 > MAX_AT_RESPONSE - ((p_read - s_ATBuffer)+(int)act_len))
427         {
428                 dbg("ERROR: Input line exceeded buffer\n");
429                 /* ditch buffer and start over again */
430                 s_ATBufferCur = s_ATBuffer;
431                 *s_ATBufferCur = '\0';
432                 p_read = s_ATBuffer;
433         }
434
435         //copy data into buffer
436         memcpy(p_read, act_data, act_len);
437
438         if (act_len <= 0)
439         {
440                 /* read error encountered or EOF reached */
441                 if(act_len == 0) {
442                         err("atchannel: EOF reached");
443                 }
444                 else {
445                         err("invalid data coming");
446                 }
447                 return FALSE;
448         }
449         else
450         {
451                 s_readCount += act_len;
452                 p_read[act_len] = '\0';
453
454                 p_marker = p_read + act_len; //pin the last position of data copy
455         }
456
457
458         do
459         {
460                 // skip over leading newlines
461                 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
462                         s_ATBufferCur++;
463
464                 p_eol = findNextEOL(s_ATBufferCur);
465
466                 if(p_eol !=NULL) /*end of line found!*/
467                 {
468                         /* a full line in the buffer. Place a \0 over the \r and return */
469                         ret = s_ATBufferCur;
470                         *p_eol = '\0';
471                         s_ATBufferCur = p_eol + 1; /* this will always be <= p_read,    */
472                         /* and there will be a \0 at *p_read */
473
474                         dbg("complete line found. process it/n");
475                         dbg("rsp line : %s/n",ret);
476                         if(1 == isSMSUnsolicited(ret))
477                         {
478                                 dbg("start of incoming sms found!!! - next data is PDU");
479                                 startSMSBuffering(ret);
480                                 s_ATBufferCur++; //move starting point by 1 - it goes to the very starting point of PDU
481                                 leftover_len = p_marker - s_ATBufferCur;
482
483                                 dbg("count leftover : %d", leftover_len);
484                                 if(leftover_len <0){
485                                         dbg("pointer address error -serious!");
486                                         return FALSE;
487                                 }
488                                 else if(leftover_len ==0){
489                                         dbg("no pdu received - wait for incoming data");
490                                         spc.cum_pdu_len =0;
491                                         spc.ppdu_marker = spc.ppdu;
492                                 }
493                                 else if(leftover_len >= spc.sms_pdu_len){
494                                         dbg("whole  pdu already received!");
495                                         memcpy(spc.ppdu, s_ATBufferCur, spc.sms_pdu_len);
496                                         spc.cum_pdu_len = spc.sms_pdu_len;
497                                         onUnsolicited(spc.line1, p, spc.ppdu, spc.sms_pdu_len);
498                                         s_ATBufferCur = s_ATBufferCur+spc.sms_pdu_len;
499                                         dbg("move buffercur to point the very end of pdu!");
500                                         stopSMSBuffering();
501                                 }
502                                 else    {
503                                         dbg("staring part of pdu received!");
504                                         memcpy(spc.ppdu, s_ATBufferCur,leftover_len);
505                                         spc.ppdu_marker = spc.ppdu + leftover_len;
506                                         spc.cum_pdu_len = leftover_len;
507                                         s_ATBufferCur = s_ATBufferCur + leftover_len;
508                                 }
509
510                         }
511                         else
512                         {
513                         processLine(hal, ret,p);
514                         }
515                 }
516                 else
517                 {
518                         dbg("complete responses all handled/n");
519                 }
520         }while(p_eol != NULL);
521
522         dbg("all the pending rsp's handled. wait for next incoming data/n");
523         return TRUE;
524 }
525
526 static enum tcore_hook_return on_hal_send(TcoreHal *hal, unsigned int data_len, void *data, void *user_data)
527 {
528         hook_hex_dump(TX, data_len, data);
529         return TCORE_HOOK_RETURN_CONTINUE;
530 }
531
532 static void on_hal_recv(TcoreHal *hal, unsigned int data_len, const void *data, void *user_data)
533 {
534         gboolean ret = FALSE;
535         TcorePlugin *plugin = user_data;
536
537         ret = readline(hal,data_len, data,plugin);
538 }
539
540 static gboolean on_load()
541 {
542         dbg("i'm load!");
543
544         return TRUE;
545 }
546
547 static gboolean on_init(TcorePlugin *p)
548 {
549         TcoreHal *h;
550
551         if (!p)
552                 return FALSE;
553
554         dbg("i'm init!");
555
556         h = tcore_server_find_hal(tcore_plugin_ref_server(p), "vmodem");
557         if (!h)  {
558                 return FALSE;
559         }
560
561         tcore_hal_add_send_hook(h, on_hal_send, p);
562         tcore_hal_add_recv_callback(h, on_hal_recv, p);
563
564         s_modem_init(p, h);
565         s_network_init(p, h);
566         s_sim_init(p, h);
567 //      s_sap_init(p);
568         s_ps_init(p, h);
569         s_call_init(p, h);
570         s_ss_init(p, h);
571         s_sms_init(p, h);
572 //      s_phonebook_init(p);
573 #ifndef TEST_AT_SOCKET
574         tcore_hal_set_power(h, TRUE);
575 #endif
576 //send "CPAS" command to invoke POWER UP NOTI
577         s_modem_send_poweron(p);
578
579         return TRUE;
580 }
581
582 static void on_unload(TcorePlugin *p)
583 {
584         struct global_data *gd;
585
586         if (!p)
587                 return;
588
589         dbg("i'm unload");
590
591         gd = tcore_plugin_ref_user_data(p);
592         if (gd) {
593                 free(gd);
594         }
595 }
596
597 struct tcore_plugin_define_desc plugin_define_desc =
598 {
599         .name = "ATMODEM",
600         .priority = TCORE_PLUGIN_PRIORITY_MID,
601         .version = 1,
602         .load = on_load,
603         .init = on_init,
604         .unload = on_unload
605 };