4 * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
28 #include <core_object.h>
37 #include "imc_common.h"
40 #define STATUS_INCOMING 4
41 #define STATUS_WAITING 5
42 #define STATUS_CONNECTED 7
44 #define find_call_object(co, call_id, call_obj) \
46 call_obj = tcore_call_object_find_by_id(co, call_id); \
48 err("unable to find call object"); \
53 struct imc_set_volume_info {
58 static gchar *xdrv_set_volume[] = {
66 /*Forward Declarations*/
67 static void on_response_imc_call_default(TcorePending *p,
68 guint data_len, const void *data, void *user_data);
70 static TelReturn __call_list_get(CoreObject *co, gboolean flag);
72 static void __on_response_imc_call_end_cause(TcorePending *p,
73 guint data_len, const void *data, void *user_data);
75 static TelCallType __call_type(int type)
81 return TEL_CALL_TYPE_VOICE;
84 return TEL_CALL_TYPE_VIDEO;
87 err("invalid call type, returning default call type as voice");
88 return TEL_CALL_TYPE_VOICE;
92 static TelCallState __call_state(int state)
98 return TEL_CALL_STATE_ACTIVE;
101 return TEL_CALL_STATE_HELD;
104 return TEL_CALL_STATE_DIALING;
107 return TEL_CALL_STATE_ALERT;
111 return TEL_CALL_STATE_INCOMING;
114 return TEL_CALL_STATE_IDLE;
118 static void __call_branch_by_status(CoreObject *co, CallObject *call_obj,
119 TelCallState call_state)
121 unsigned int call_id;
122 TelCallType call_type;
124 TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
125 dbg("Call State[%d]", call_state);
127 if (tcore_call_object_get_state(call_obj, &state) == FALSE) {
128 err("unable to get call status");
132 if (call_state == state) {
133 dbg("current call state and existing call state are same");
137 if (tcore_call_object_get_call_type(call_obj, &call_type) == FALSE) {
138 err("unable to get call type");
142 if (tcore_call_object_get_id(call_obj, &call_id) == FALSE) {
143 err("unable to get call id");
148 tcore_call_object_set_state(call_obj, call_state);
150 if (call_type == TEL_CALL_TYPE_VOICE) {
151 /* voice call notification */
152 switch (call_state) {
153 case TEL_CALL_STATE_ACTIVE:
154 command = TCORE_NOTIFICATION_CALL_STATUS_ACTIVE;
157 case TEL_CALL_STATE_HELD:
158 command = TCORE_NOTIFICATION_CALL_STATUS_HELD;
161 case TEL_CALL_STATE_DIALING:
162 command = TCORE_NOTIFICATION_CALL_STATUS_DIALING;
165 case TEL_CALL_STATE_ALERT:
166 command = TCORE_NOTIFICATION_CALL_STATUS_ALERT;
169 case TEL_CALL_STATE_INCOMING:
170 case TEL_CALL_STATE_WAITING: {
171 TelCallIncomingInfo incoming = {0,};
173 incoming.call_id = call_id;
174 tcore_call_object_get_cli_validity(call_obj, &incoming.cli_validity);
175 tcore_call_object_get_number(call_obj, incoming.number);
176 tcore_call_object_get_cni_validity(call_obj, &incoming.cni_validity);
177 tcore_call_object_get_name(call_obj, incoming.name);
178 tcore_call_object_get_mt_forward(call_obj, &incoming.forward);
179 tcore_call_object_get_active_line(call_obj, &incoming.active_line);
181 /* Send notification */
182 tcore_object_send_notification(co,
183 TCORE_NOTIFICATION_CALL_STATUS_INCOMING,
184 sizeof(TelCallIncomingInfo), &incoming);
188 case TEL_CALL_STATE_IDLE: {
189 /* Send AT+CEER command*/
190 ImcRespCbData *resp_cb_data = NULL;
193 /* Response callback data */
194 resp_cb_data = imc_create_resp_cb_data(NULL, NULL, &call_id, sizeof(call_id));
196 /* Send Request to modem */
197 ret = tcore_at_prepare_and_send_request(co,
199 TCORE_AT_COMMAND_TYPE_SINGLELINE,
201 __on_response_imc_call_end_cause, resp_cb_data,
202 on_send_imc_request, NULL);
203 if (ret != TEL_RETURN_SUCCESS) {
204 warn("Failed to send request");
205 TelCallStatusIdleNoti idle;
207 idle.call_id = call_id;
208 idle.cause = TEL_CALL_END_CAUSE_NONE;
210 /* Send notification */
211 tcore_object_send_notification(co,
212 TCORE_NOTIFICATION_CALL_STATUS_IDLE,
213 sizeof(TelCallStatusIdleNoti), &idle);
215 imc_destroy_resp_cb_data(resp_cb_data);
218 /* Free Call object */
219 tcore_call_object_free(co, call_obj);
225 else if (call_type == TEL_CALL_TYPE_VIDEO) {
226 /* video call notification */
227 switch (call_state) {
228 case TEL_CALL_STATE_ACTIVE:
229 command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ACTIVE;
232 case TEL_CALL_STATE_HELD:
233 err("invalid state");
236 case TEL_CALL_STATE_DIALING:
237 command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_DIALING;
240 case TEL_CALL_STATE_ALERT:
241 command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ALERT;
244 case TEL_CALL_STATE_INCOMING:
245 case TEL_CALL_STATE_WAITING:
246 command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_INCOMING;
249 case TEL_CALL_STATE_IDLE: {
250 TelCallStatusIdleNoti idle;
252 idle.call_id = call_id;
253 idle.cause = TEL_CALL_END_CAUSE_NONE;
255 /* Send notification */
256 tcore_object_send_notification(co,
257 TCORE_NOTIFICATION_VIDEO_CALL_STATUS_IDLE,
258 sizeof(TelCallStatusIdleNoti), &idle);
260 /* Free Call object */
261 tcore_call_object_free(co, call_obj);
266 err("Unknown Call type: [%d]", call_type);
269 if (command != TCORE_NOTIFICATION_UNKNOWN)
270 tcore_object_send_notification(co, command, sizeof(call_id), &call_id);
273 static void __handle_call_list_get(CoreObject *co, gboolean flag, void *data)
281 GSList *tokens = NULL;
286 char number[TEL_CALL_CALLING_NUMBER_LEN_MAX +1] = {0,};
287 GSList *lines = data;
288 CallObject *call_obj = NULL;
290 while (lines != NULL) {
291 line = (char *)lines->data;
292 /* point to next node */
294 /* free previous tokens*/
295 tcore_at_tok_free(tokens);
297 tokens = tcore_at_tok_new(line);
300 resp = g_slist_nth_data(tokens, 0);
302 err("Invalid call_id");
305 call_id = atoi(resp);
308 resp = g_slist_nth_data(tokens, 1);
310 err("Invalid direction");
313 direction = (atoi(resp) == 0) ? 1 : 0;
316 resp = g_slist_nth_data(tokens, 2);
318 err("Invalid state");
321 state = __call_state(atoi(resp));
324 resp = g_slist_nth_data(tokens, 3);
326 err("Invalid call_type");
329 call_type = __call_type(atoi(resp));
332 resp = g_slist_nth_data(tokens, 4);
340 resp = g_slist_nth_data(tokens, 5);
342 err("Number is NULL");
344 /* Strike off double quotes */
345 num = tcore_at_tok_extract(resp);
346 dbg("Number: [%s]", num);
349 resp = g_slist_nth_data(tokens, 6);
351 err("Invalid num type");
353 num_type = atoi(resp);
354 /* check number is international or national. */
355 ton = ((num_type) >> 4) & 0x07;
356 if (ton == 1 && num[0] != '+') {
357 /* international number */
359 memcpy(&number[1], num, strlen(num));
361 memcpy(number, num, strlen(num));
367 dbg("Call ID: [%d] Direction: [%s] Call Type: [%d] Multi-party: [%s] "
368 "Number: [%s] TON: [%d] State: [%d]",
369 call_id, (direction ? "Outgoing" : "Incoming"), call_type,
370 (mpty ? "YES" : "NO"), number, ton, state);
372 call_obj = tcore_call_object_find_by_id(co, call_id);
373 if (NULL == call_obj) {
374 call_obj = tcore_call_object_new(co, call_id);
375 if (NULL == call_obj) {
376 err("unable to create call object");
381 /* Set Call parameters */
382 tcore_call_object_set_type(call_obj, call_type);
383 tcore_call_object_set_direction(call_obj, direction);
384 tcore_call_object_set_multiparty_state(call_obj, mpty);
385 tcore_call_object_set_cli_info(call_obj, TEL_CALL_CLI_VALIDITY_VALID, number);
386 tcore_call_object_set_active_line(call_obj, TEL_CALL_ACTIVE_LINE1);
388 __call_branch_by_status(co, call_obj, state);
390 tcore_call_object_set_state(call_obj, state);
394 /* internal notification operation */
395 static void __on_notification_imc_call_incoming(CoreObject *co, unsigned int call_id,
399 CallObject *call_obj = NULL;
402 /* check call with incoming status already exist */
403 list = tcore_call_object_find_by_status(co, TEL_CALL_STATE_INCOMING);
405 err("Incoming call already exist! Skip...");
410 call_obj = tcore_call_object_find_by_id(co, call_id);
411 if (call_obj != NULL) {
412 err("Call object for Call ID [%d] already exist! Skip...", call_id);
416 /* Create new Call object */
417 call_obj = tcore_call_object_new(co, (unsigned int)call_id);
418 if (NULL == call_obj) {
419 err("Failed to create Call object");
423 /* Make request to get current Call list */
424 __call_list_get(co, TRUE);
427 static void __on_notification_imc_call_status(CoreObject *co, unsigned int call_id,
428 unsigned int call_state, void *user_data)
430 CallObject *call_obj = NULL;
433 state = __call_state(call_state);
434 dbg("state [%d]", state);
437 case TEL_CALL_STATE_ACTIVE: {
438 find_call_object(co, call_id, call_obj);
439 /* Send notification to application */
440 __call_branch_by_status(co, call_obj, state);
444 case TEL_CALL_STATE_HELD: {
445 find_call_object(co, call_id, call_obj);
446 /* Send notification to application */
447 __call_branch_by_status(co, call_obj, state);
451 case TEL_CALL_STATE_DIALING: {
452 call_obj = tcore_call_object_find_by_id(co, call_id);
454 call_obj = tcore_call_object_new(co, call_id);
456 err("unable to create call object");
460 /* Make request to get current call list.Update CallObject with <number>
461 * and send notification to application */
462 __call_list_get(co, TRUE);
466 case TEL_CALL_STATE_ALERT: {
467 find_call_object(co, call_id, call_obj);
468 /* Send notification to application */
469 __call_branch_by_status(co, call_obj, TEL_CALL_STATE_ALERT);
473 case TEL_CALL_STATE_IDLE: {
474 find_call_object(co, call_id, call_obj);
475 /* Send notification to application */
476 __call_branch_by_status(co, call_obj, state);
481 err("invalid call status");
486 /*internal response operation */
487 static void __on_response_imc_call_list_get(TcorePending *p, guint data_len, const void *data,
490 const TcoreAtResponse *at_resp = data;
491 CoreObject *co = tcore_pending_ref_core_object(p);
492 ImcRespCbData *resp_cb_data = user_data;
493 GSList *lines = NULL;
494 TelCallResult result = TEL_CALL_RESULT_FAILURE;
495 gboolean *flag = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
499 tcore_check_return_assert(co != NULL);
500 tcore_check_return_assert(resp_cb_data != NULL);
502 if (at_resp && at_resp->success) {
503 if (NULL == at_resp->lines) {
504 err("invalid response received");
508 lines = (GSList *) at_resp->lines;
509 count = g_slist_length(lines);
510 dbg("Total records : %d", count);
512 err("Call count is zero");
515 result = TEL_CALL_RESULT_SUCCESS;
518 /* parse +CLCC notification parameter */
519 __handle_call_list_get(co, *flag, lines);
526 /*internal request operation */
527 static TelReturn __send_call_request(CoreObject *co, TcoreObjectResponseCallback cb,
528 void *cb_data, gchar *at_cmd, gchar *func_name)
530 ImcRespCbData *resp_cb_data;
533 /* Response callback data */
534 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, func_name,
535 strlen(func_name) + 1);
537 /* Send Request to modem */
538 ret = tcore_at_prepare_and_send_request(co,
540 TCORE_AT_COMMAND_TYPE_NO_RESULT,
542 on_response_imc_call_default, resp_cb_data,
543 on_send_imc_request, NULL);
544 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, func_name);
552 * Operation - Get current call list.
555 * AT-Command: AT+CLCC
559 *[+CLCC: <id1>, <dir>, <stat>, <mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>]]]
563 * +CME ERROR: <error>
565 static TelReturn __call_list_get(CoreObject *co, gboolean flag)
567 ImcRespCbData *resp_cb_data;
568 TelReturn ret = TEL_RETURN_FAILURE;
572 err("Core Object is NULL");
576 /* Response callback data */
577 resp_cb_data = imc_create_resp_cb_data(NULL, NULL, &flag, sizeof(gboolean));
579 /* Send Request to modem */
580 ret = tcore_at_prepare_and_send_request(co,
582 TCORE_AT_COMMAND_TYPE_MULTILINE,
584 __on_response_imc_call_list_get, resp_cb_data,
585 on_send_imc_request, NULL);
586 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get current call list");
591 static TelCallResult __convert_imc_extended_err_tel_call_result(gint error)
595 * 1 - unassigned (unallocated) number.
596 * 28 - invalid number format (incomplete number).
597 * 96 - invalid mandatory information.
598 * 258 - Invalid parameters.
599 * 371 - Invalid mandatory info.
600 * 257 - Out of memory.
602 * 42 - switching equipment congestion
603 * 287 - MM network failure unspecified.
606 dbg("CEER Error: [%d]", error);
614 return TEL_CALL_RESULT_INVALID_PARAMETER;
616 return TEL_CALL_RESULT_MEMORY_FAILURE;
618 return TEL_CALL_RESULT_FDN_RESTRICTED;
622 return TEL_CALL_RESULT_NETWORK_BUSY;
624 return TEL_CALL_RESULT_FAILURE;
628 static TelCallEndCause __convert_imc_extended_err_call_end_cause(gint error)
632 * 1 - unassigned (unallocated) number.
633 * 3 - No route to destination.
634 * 16 - operator determined barring.
636 * 18 - no user responding.
637 * 19 - user alerting, no answer.
638 * 21 - call rejected.
639 * 22 - number changed
640 * 27 - destination out of order.
641 * 28 - invalid number format (incomplete number).
642 * 29 - facility rejected
643 * 34 - no circuit / channel available.
644 * 38 - network out of order
645 * 41 - temporary failure
646 * 44 - requested circuit / channel not available.
647 * 50 - requested facility not subscribed
648 * 68 - ACM equal to or greater than ACMmax
650 dbg("Call end-cause: [%d]", error);
653 return TEL_CALL_END_CAUSE_UNASSIGNED_NUMBER;
655 return TEL_CALL_END_CAUSE_NO_ROUTE_TO_DEST;
657 return TEL_CALL_END_CAUSE_OPERATOR_DETERMINED_BARRING;
659 return TEL_CALL_END_CAUSE_NORMAL_CALL_CLEARING;
661 return TEL_CALL_END_CAUSE_USER_BUSY;
663 return TEL_CALL_END_CAUSE_NO_USER_RESPONDING;
665 return TEL_CALL_END_CAUSE_USER_ALERTING_NO_ANSWER;
667 return TEL_CALL_END_CAUSE_CALL_REJECTED;
669 return TEL_CALL_END_CAUSE_NUMBER_CHANGED;
671 return TEL_CALL_END_CAUSE_DESTINATION_OUT_OF_ORDER;
673 return TEL_CALL_END_CAUSE_INVALID_NUMBER_FORMAT;
675 return TEL_CALL_END_CAUSE_FACILITY_REJECTED;
677 return TEL_CALL_END_CAUSE_NO_CIRCUIT_CHANNEL_AVAILABLE;
679 return TEL_CALL_END_CAUSE_NETWORK_OUT_OF_ORDER;
681 return TEL_CALL_END_CAUSE_TEMPORARY_FAILURE;
683 return TEL_CALL_END_CAUSE_SWITCHING_EQUIPMENT_CONGESTION;
685 return TEL_CALL_END_CAUSE_REQUESTED_CIRCUIT_CHANNEL_NOT_AVAILABLE;
687 return TEL_CALL_END_CAUSE_REQUESTED_FACILITY_NOT_SUBSCRIBED;
689 return TEL_CALL_END_CAUSE_ACM_GEQ_ACMMAX;
692 return TEL_CALL_END_CAUSE_SERVICE_OPTION_OUT_OF_ORDER;
694 return TEL_CALL_END_CAUSE_FAILED;
698 static TelCallResult __convert_imc_xdrv_result_tel_call_result(gint xdrv_err)
701 * 0 - Command was executed without any error.
702 * 1 - One of the parameters is out of range.
703 * 2 - The function doesn’t exist for this driver.
704 * 3 - The group is not supported.
705 * 4 - The internal state of the driver is not allowing to process the command.
706 * 5 - The driver interface function for the command is not available.
707 * 6 - The corresponding driver for the command retuns an error.
708 * 7 - Timeout occured when expecting response from the corresponding driver.
709 * 8 - The driver is not supported for this product.
710 * 12 - No of parameteres passed for the command is mismatch with the rquirements.
711 * 13 - The given command to xdrv is invalid.
712 * 14 - Any internal error in xdrv like out of memory.
715 dbg("XDRV result: [%d]", xdrv_err);
720 return TEL_CALL_RESULT_INVALID_PARAMETER;
722 return TEL_CALL_RESULT_MEMORY_FAILURE;
724 return TEL_CALL_RESULT_OPERATION_NOT_SUPPORTED;
731 * Operation - call status notification from network.
732 * notification message format:
733 * +XCALLSTAT: <call_id><stat>
736 * indicates the call identification (GSM02.30 4.5.5.1)
740 * 2 dialling (MO call)
741 * 3 alerting (MO call; ringing for the remote party)
742 * 4 ringing (MT call)
743 * 5 waiting (MT call)
745 * 7 connected (indicates the completion of a call setup first time
746 * for MT and MO calls this is reported in addition to state active)
748 static gboolean on_notification_imc_call_status(CoreObject *co, const void *data,
751 GSList *tokens = NULL;
752 GSList *lines = NULL;
753 const char *line = NULL;
754 char *state = NULL, *call_handle = NULL;
755 unsigned int status, call_id;
759 lines = (GSList *) data;
761 err("Invalid response received");
764 line = (char *) (lines->data);
765 tokens = tcore_at_tok_new(line);
767 call_handle = g_slist_nth_data(tokens, 0);
768 if (NULL == call_handle) {
769 err("call id missing from %XCALLSTAT indication");
772 call_id = atoi(call_handle);
773 state = g_slist_nth_data(tokens, 1);
775 err("call state is missing from %XCALLSTAT indication");
778 status = atoi(state);
779 dbg("call id[%d], status[%d]", call_id, status);
782 case STATUS_INCOMING:
784 __on_notification_imc_call_incoming(co, call_id, user_data);
787 case STATUS_CONNECTED: /* ignore Connected state. */
788 dbg("ignore connected state");
792 __on_notification_imc_call_status(co, call_id, status, user_data);
797 tcore_at_tok_free(tokens);
802 * Operation - SS network initiated notification.
804 * notification message format:
805 * +CSSU: <code2>[<index> [,<number>,<type>]]
807 * (it is manufacturer specific, which of these codes are supported):
808 * 0 this is a forwarded call (MT call setup)
809 * 1 this is a CUG call (<index> present) (MT call setup)
810 * 2 call has been put on hold (during a voice call)
811 * 3 call has been retrieved (during a voice call)
812 * 4 multiparty call entered (during a voice call)
813 * 5 Call has been released - not a SS notification (during a voice call)
814 * 6 forward check SS message received (can be received whenever)
815 * 7 call is being connected (alerting) with the remote party in alerting state
816 * in explicit call transfer operation
817 * (during a voice call)
818 * 8 call has been connected with the other remote party in explicit call transfer
819 * operation (during a voice call or MT call setup)
820 * 9 this is a deflected call (MT call setup)
821 * 10 additional incoming call forwarded
823 * refer Closed user group +CCUG
825 * string type phone of format specified by <type>
827 * type of address octet in integer format.
829 static gboolean on_notification_imc_call_ss_cssu_info(CoreObject *co, const void *event_data,
832 GSList *tokens = NULL;
833 TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
842 if (1 != g_slist_length((GSList *) event_data)) {
843 err("unsolicited msg but multiple line");
847 cmd = (char *) ((GSList *) event_data)->data;
848 dbg("ss notification message[%s]", cmd);
850 tokens = tcore_at_tok_new(cmd);
853 resp = g_slist_nth_data(tokens, 0);
855 err("Code2 is missing from +CSSU indication");
856 tcore_at_tok_free(tokens);
862 /* parse [ <index>, <number> <type>] */
863 if ((resp = g_slist_nth_data(tokens, 1)))
866 if ((resp = g_slist_nth_data(tokens, 2))) {
867 /* Strike off double quotes */
868 number = tcore_at_tok_extract(resp);
871 dbg("+CSSU: <code2> = %d <index> = %d <number> = %s ", code2, index, number);
873 /* <code2> - other values will be ignored */
876 command = TCORE_NOTIFICATION_CALL_INFO_MT_FORWARDED;
879 command = TCORE_NOTIFICATION_CALL_INFO_HELD;
882 command = TCORE_NOTIFICATION_CALL_INFO_ACTIVE;
885 command = TCORE_NOTIFICATION_CALL_INFO_JOINED;
889 command = TCORE_NOTIFICATION_CALL_INFO_TRANSFERED;
892 command = TCORE_NOTIFICATION_CALL_INFO_MT_DEFLECTED;
895 dbg("Unsupported +CSSU notification : %d", code2);
899 if (command != TCORE_NOTIFICATION_UNKNOWN)
900 tcore_object_send_notification(co, command, 0, NULL);
901 tcore_at_tok_free(tokens);
908 * Operation - SS network initiated notification.
909 * notification message format:
910 * +CSSI : <code1>[,<index>]
913 * 0 unconditional call forwarding is active
914 * 1 some of the conditional call forwarding are active
915 * 2 call has been forwarded
917 * 4 this is a CUG call (also <index> present)
918 * 5 outgoing calls are barred
919 * 6 incoming calls are barred
920 * 7 CLIR suppression rejected
921 * 8 call has been deflected
924 * refer Closed user group +CCUG.
926 static gboolean on_notification_imc_call_ss_cssi_info(CoreObject *co, const void *event_data,
929 GSList *tokens = NULL;
930 TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
938 if (1 != g_slist_length((GSList *) event_data)) {
939 err("unsolicited msg but multiple line");
942 cmd = (char *) ((GSList *) event_data)->data;
943 dbg("ss notification message[%s]", cmd);
945 tokens = tcore_at_tok_new(cmd);
947 resp = g_slist_nth_data(tokens, 0);
949 err("<code1> is missing from %CSSI indication");
950 tcore_at_tok_free(tokens);
956 /* parse [ <index>] */
957 if ((resp = g_slist_nth_data(tokens, 1)))
960 dbg("+CSSI: <code1> = %d <index> = %d ", code1, index);
962 /* <code1> - other values will be ignored */
965 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_UNCONDITIONAL;
968 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_CONDITIONAL;
971 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARDED;
974 command = TCORE_NOTIFICATION_CALL_INFO_MO_WAITING;
977 command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_OUTGOING;
980 command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_INCOMING;
983 command = TCORE_NOTIFICATION_CALL_INFO_MO_DEFLECTED;
986 dbg("Unsupported +CSSI notification : %d", code1);
990 if (command != TCORE_NOTIFICATION_UNKNOWN)
991 tcore_object_send_notification(co, command, 0, NULL);
992 tcore_at_tok_free(tokens);
997 static gboolean on_notification_imc_call_clip_info(CoreObject *co, const void *data,
1001 /* TODO - handle +CLIP notification*/
1006 static void __on_response_imc_call_handle_error_report(TcorePending *p,
1007 guint data_len, const void *data, void *user_data)
1009 const TcoreAtResponse *at_resp = data;
1010 CoreObject *co = tcore_pending_ref_core_object(p);
1011 ImcRespCbData *resp_cb_data = user_data;
1012 TelCallResult result = TEL_CALL_RESULT_FAILURE;
1013 GSList *tokens = NULL;
1016 tcore_check_return_assert(co != NULL);
1017 tcore_check_return_assert(resp_cb_data != NULL);
1019 if (at_resp && at_resp->success) {
1020 GSList *resp_data = NULL;
1024 resp_data = at_resp->lines;
1026 err("invalid response data received");
1030 tokens = tcore_at_tok_new(resp_data->data);
1031 resp_str = g_slist_nth_data(tokens, 0);
1033 err("In extended error report - <category> missing");
1036 dbg("category[%s]", resp_str);
1038 resp_str = g_slist_nth_data(tokens, 1);
1040 err("In extended error report - <cause> missing");
1043 error = atoi(resp_str);
1044 dbg("Cause: [%d] description: [%s]", error, g_slist_nth_data(tokens, 2));
1046 result = __convert_imc_extended_err_tel_call_result(error);
1047 dbg("result: [%d]", result);
1049 err("Response - [NOK]");
1053 dbg("%s: [%s]", IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data),
1054 (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1056 /* Invoke callback */
1057 if (resp_cb_data->cb)
1058 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1060 /* Free callback data */
1061 imc_destroy_resp_cb_data(resp_cb_data);
1064 tcore_at_tok_free(tokens);
1067 static void __on_response_imc_call_end_cause(TcorePending *p,
1068 guint data_len, const void *data, void *user_data)
1070 const TcoreAtResponse *at_resp = data;
1071 CoreObject *co = tcore_pending_ref_core_object(p);
1072 ImcRespCbData *resp_cb_data = user_data;
1073 TelCallStatusIdleNoti idle;
1074 TcoreNotification command;
1075 TelCallEndCause cause = TEL_CALL_END_CAUSE_NONE;
1077 GSList *tokens = NULL;
1081 tcore_check_return_assert(co != NULL);
1082 tcore_check_return_assert(resp_cb_data != NULL);
1083 call_id = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1085 if (at_resp && at_resp->success) {
1086 GSList *resp_data = NULL;
1090 resp_data = at_resp->lines;
1092 err("invalid response data received");
1095 tokens = tcore_at_tok_new(resp_data->data);
1096 resp_str = g_slist_nth_data(tokens, 0);
1098 err("In extended error report - <category> missing");
1101 dbg("category[%s]", resp_str);
1102 resp_str = g_slist_nth_data(tokens, 1);
1104 err("In extended error report - <cause> missing");
1107 error = atoi(resp_str);
1108 dbg("cause: [%d] description: [%s]", error, g_slist_nth_data(tokens, 2));
1110 cause = __convert_imc_extended_err_call_end_cause(error);
1111 dbg("cause: [%d]", cause);
1114 err("RESPONSE - [NOK]");
1117 command = TCORE_NOTIFICATION_CALL_STATUS_IDLE;
1118 idle.call_id = *call_id;
1122 /* Send notification */
1123 tcore_object_send_notification(co, command,
1124 sizeof(TelCallStatusIdleNoti), &idle);
1126 /* Free callback data */
1127 imc_destroy_resp_cb_data(resp_cb_data);
1130 tcore_at_tok_free(tokens);
1132 static void on_response_imc_call_default(TcorePending *p,
1133 guint data_len, const void *data, void *user_data)
1135 const TcoreAtResponse *at_resp = data;
1136 CoreObject *co = tcore_pending_ref_core_object(p);
1137 ImcRespCbData *resp_cb_data = user_data;
1139 TelCallResult result = TEL_CALL_RESULT_FAILURE;
1142 tcore_check_return_assert(co != NULL);
1143 tcore_check_return_assert(resp_cb_data != NULL);
1145 if (at_resp && at_resp->success) {
1146 result = TEL_CALL_RESULT_SUCCESS;
1150 err("ERROR[%s]", at_resp->final_response);
1153 /* Send Request to modem to get extended error report*/
1154 ret = tcore_at_prepare_and_send_request(co,
1155 "AT+CEER", "+CEER:",
1156 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1158 __on_response_imc_call_handle_error_report, resp_cb_data,
1159 on_send_imc_request, NULL);
1162 if (ret == TEL_RETURN_SUCCESS)
1166 dbg("%s: [%s]", IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data),
1167 (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1169 /* Invoke callback */
1170 if (resp_cb_data->cb)
1171 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1173 /* Free callback data */
1174 imc_destroy_resp_cb_data(resp_cb_data);
1177 static void on_response_imc_call_set_volume_info(TcorePending *p,
1178 guint data_len, const void *data, void *user_data)
1180 const TcoreAtResponse *at_resp = data;
1181 CoreObject *co = tcore_pending_ref_core_object(p);
1182 ImcRespCbData *resp_cb_data = user_data;
1183 GSList *tokens = NULL;
1184 GSList *line = NULL;
1185 char *resp_str = NULL;
1188 TelCallResult result = TEL_CALL_RESULT_FAILURE;
1191 tcore_check_return_assert(co != NULL);
1192 tcore_check_return_assert(resp_cb_data != NULL);
1194 if (at_resp && at_resp->success) {
1195 line = at_resp->lines;
1196 tokens = tcore_at_tok_new(line->data);
1198 if (!g_slist_nth_data(tokens, 0)) {
1199 err("group_id missing");
1203 if (!g_slist_nth_data(tokens, 1)) {
1204 err(" function_id missing");
1208 resp_str = g_slist_nth_data(tokens, 2);
1210 err("xdrv result missing");
1213 struct imc_set_volume_info *volume_info;
1218 error = atoi(resp_str);
1220 err("RESPONSE NOK");
1221 result = __convert_imc_xdrv_result_tel_call_result(error);
1225 /* Fetch volume_info from resp_cb_data */
1226 volume_info = (struct imc_set_volume_info *)
1227 IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1228 dbg("volume info index[%d]", volume_info->next_index);
1230 if (xdrv_set_volume[volume_info->next_index] == NULL) {
1231 /*Processing of xdrv commands completed */
1233 result = TEL_CALL_RESULT_SUCCESS;
1235 } else if (volume_info->next_index == 3) {
1236 switch ((volume_info->volume) / 10) {
1270 at_cmd = g_strdup_printf("%s%s",
1271 xdrv_set_volume[volume_info->next_index], vol);
1273 /* Increment index to point to next xdrv command */
1274 volume_info->next_index += 1;
1276 /* Send Request to modem */
1277 ret = tcore_at_prepare_and_send_request(co,
1279 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1281 on_response_imc_call_set_volume_info,
1282 resp_cb_data, on_send_imc_request, NULL);
1283 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info");
1291 dbg("Set Volume Info: [%s]",
1292 (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1294 /* Invoke callback */
1295 if (resp_cb_data->cb)
1296 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1298 imc_destroy_resp_cb_data(resp_cb_data);
1299 tcore_at_tok_free(tokens);
1302 static void on_response_imc_call_set_sound_path(TcorePending *p,
1303 guint data_len, const void *data, void *user_data)
1305 const TcoreAtResponse *at_resp = data;
1306 CoreObject *co = tcore_pending_ref_core_object(p);
1307 ImcRespCbData *resp_cb_data = user_data;
1308 GSList *tokens = NULL;
1309 GSList *line = NULL;
1310 char *resp_str = NULL;
1312 gint xdrv_func_id = -1;
1314 TelCallResult result = TEL_CALL_RESULT_FAILURE;
1317 tcore_check_return_assert(co != NULL);
1318 tcore_check_return_assert(resp_cb_data != NULL);
1320 if (at_resp && at_resp->success) {
1321 line = at_resp->lines;
1322 tokens = tcore_at_tok_new(line->data);
1323 if (!g_slist_nth_data(tokens, 0)) {
1324 err("group_id missing");
1328 if (!(resp_str = g_slist_nth_data(tokens, 1))) {
1329 err("function_id missing");
1332 xdrv_func_id = atoi(resp_str);
1334 if (!(resp_str = g_slist_nth_data(tokens, 2))) {
1335 err("RESPONSE NOK");
1338 error = atoi(resp_str);
1340 err("RESPONSE NOK");
1341 result = __convert_imc_xdrv_result_tel_call_result(error);
1345 if (xdrv_func_id == 4) {
1346 /* Send next command to configure destination device type */
1349 gint *device_type = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1351 at_cmd = g_strdup_printf("AT+XDRV=40,5,2,0,0,0,0,0,1,0,1,0,%d",
1354 ret = tcore_at_prepare_and_send_request(co,
1356 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1358 on_response_imc_call_set_sound_path, resp_cb_data,
1359 on_send_imc_request, NULL);
1360 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_sound_path");
1366 result = TEL_CALL_RESULT_SUCCESS;
1370 dbg("Set Sound Path: [%s]",
1371 (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1373 tcore_at_tok_free(tokens);
1375 /* Invoke callback */
1376 if (resp_cb_data->cb)
1377 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1379 imc_destroy_resp_cb_data(resp_cb_data);
1382 static void on_response_set_sound_path(TcorePending *p, guint data_len,
1383 const void *data, void *user_data)
1385 const TcoreAtResponse *at_resp = data;
1386 ImcRespCbData *resp_cb_data = user_data;
1387 TelCallResult result = TEL_CALL_RESULT_FAILURE;
1388 CoreObject *co_call = tcore_pending_ref_core_object(p);
1390 if (at_resp && at_resp->success)
1391 result = TEL_CALL_RESULT_SUCCESS;
1393 if(resp_cb_data->cb)
1394 resp_cb_data->cb(co_call, (gint)result, NULL, resp_cb_data->cb_data);
1396 imc_destroy_resp_cb_data(resp_cb_data);
1399 static void on_response_imc_call_set_mute(TcorePending *p, guint data_len,
1400 const void *data, void *user_data)
1402 const TcoreAtResponse *at_resp = data;
1403 CoreObject *co = tcore_pending_ref_core_object(p);
1404 ImcRespCbData *resp_cb_data = user_data;
1405 GSList *tokens = NULL;
1406 const char *line = NULL;
1407 char *resp_str = NULL;
1410 TelCallResult result = TEL_CALL_RESULT_FAILURE;
1413 tcore_check_return_assert(co != NULL);
1414 tcore_check_return_assert(resp_cb_data != NULL);
1416 if (at_resp && at_resp->success) {
1417 line = (((GSList *)at_resp->lines)->data);
1418 tokens = tcore_at_tok_new(line);
1420 if (!g_slist_nth_data(tokens, 0)) {
1421 err("group_id missing");
1425 if (!g_slist_nth_data(tokens, 1)) {
1426 err("function_id missing");
1430 if (!(resp_str = g_slist_nth_data(tokens, 2))) {
1431 err("xdrv_result missing");
1435 error = atoi(resp_str);
1437 err(" RESPONSE NOK [%d]", error);
1438 result = __convert_imc_xdrv_result_tel_call_result(error);
1441 result = TEL_CALL_RESULT_SUCCESS;
1445 dbg("Set Mute: [%s]",
1446 (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1447 tcore_at_tok_free(tokens);
1449 /* Invoke callback */
1450 if (resp_cb_data->cb)
1451 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1453 imc_destroy_resp_cb_data(resp_cb_data);
1462 * AT-Command: ATD <num> [I] [G] [;]
1463 * <num> - dialed number
1464 * [I][i] - CLI presentation(supression or invocation)
1465 * [G] - control the CUG supplementary service information for this call.
1476 * +CME ERROR: <error>
1478 static TelReturn imc_call_dial(CoreObject *co, const TelCallDial *dial_info,
1479 TcoreObjectResponseCallback cb, void *cb_data)
1487 if (dial_info->call_type == TEL_CALL_TYPE_VIDEO) {
1488 err("Video call is not supported in imc modem");
1489 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1492 if (!strncmp(dial_info->number, "*31#", 4)) {
1493 dbg("clir suppression");
1495 num = (gchar *)&(dial_info->number[4]);
1496 } else if (!strncmp(dial_info->number, "#31#", 4)) {
1497 dbg("clir invocation");
1499 num = (gchar *)&(dial_info->number[4]);
1503 dbg("no clir string in number");
1505 /* it will be removed when setting application use tapi_ss_set_cli()
1506 * instead of his own vconfkey. (0 : By network, 1 : Show, 2 : Hide)
1508 vconf_get_int("db/ciss/show_my_number", &cli);
1510 dbg("clir invocation from setting application");
1513 dbg("set clir state to default");
1516 num = (gchar *)dial_info->number;
1520 at_cmd = g_strdup_printf("ATD%s%s;", num, clir);
1521 dbg(" at command : %s", at_cmd);
1523 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_dial");
1527 * Operation - Answer/Reject/Replace/hold(current call) & accept incoming call.
1531 * 1. AT-Command: ATA
1536 * +CME ERROR: <error>
1538 * 2. AT-Command: AT+CHLD=[<n>]
1540 * 0 - (deafult)release all held calls or set User Determined User Busy for a waiting/incoming
1541 * call; if both exists then only the waiting call will be rejected.
1542 * 1 - release all active calls and accepts the other (held or waiting)
1543 * Note: In the scenario: An active call, a waiting call and held call, when the active call is
1544 * terminated, we will make the Waiting call as active.
1545 * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/in-coming).
1546 * If only one call exists which is active, place it on hold and if only held call exists make it active call.
1551 * +CME ERROR: <error>
1552 * For more informatiion refer 3GPP TS 27.007.
1554 static TelReturn imc_call_answer(CoreObject *co, TelCallAnswerType ans_type,
1555 TcoreObjectResponseCallback cb, void *cb_data)
1560 if (ans_type == TEL_CALL_ANSWER_ACCEPT) {
1562 at_cmd = g_strdup_printf("%s", "ATA");
1563 }else if (ans_type == TEL_CALL_ANSWER_REJECT) {
1565 at_cmd = g_strdup_printf("%s", "AT+CHLD=0");
1566 } else if (ans_type == TEL_CALL_ANSWER_REPLACE) {
1568 at_cmd = g_strdup_printf("%s", "AT+CHLD=1");
1569 } else if (ans_type == TEL_CALL_ANSWER_HOLD_AND_ACCEPT) {
1571 at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1573 err("Unsupported call answer type");
1574 return TEL_RETURN_FAILURE;
1577 dbg("at command : %s", at_cmd);
1579 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_answer");
1583 * Operation - release all calls/release specific call/release all active
1584 * call/release all held calls.
1587 * 1. AT-Command: AT+CHLD=[<n>]
1589 * 0 - (defualt)release all held calls or set User Determined User -
1590 * Busy for a waiting/incoming.
1591 * call; if both exists then only the waiting call will be rejected.
1592 * 1 - release all active calls and accepts the other (held or waiting).
1593 * 1x - release a specific call (x specific call number as indicated by call id).
1594 * 8 - release all calls.
1599 * +CME ERROR: <error>
1601 static TelReturn imc_call_end(CoreObject *co, const TelCallEnd *end_info,
1602 TcoreObjectResponseCallback cb, void *cb_data)
1607 if (end_info->end_type == TEL_CALL_END_ALL) {
1609 at_cmd = g_strdup_printf("%s", "AT+CHLD=8");
1610 }else if (end_info->end_type == TEL_CALL_END) {
1612 at_cmd = g_strdup_printf("%s%d", "AT+CHLD=1",end_info->call_id);
1613 } else if (end_info->end_type == TEL_CALL_END_ACTIVE_ALL) {
1615 at_cmd = g_strdup_printf("%s", "AT+CHLD=1");
1616 } else if (end_info->end_type == TEL_CALL_END_HOLD_ALL) {
1618 at_cmd = g_strdup_printf("%s", "AT+CHLD=0");
1620 err("Unsupported call end type");
1621 return TEL_RETURN_FAILURE;
1624 dbg("at command : %s", at_cmd);
1626 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_end");
1630 * Operation - send dtmf.
1633 * 1. AT-Command: AT+VTS=<DTMF>,{<DTMF>,<duration>}.
1636 * is a single ASCII character in the set 0-9, #, *, A-D. Even it will support string DTMF.
1638 * integer in range 0-255, meaning 1/10(10 millisec) seconds multiples. The string parameter
1639 * of the command consists of combinations of the following separated by commas:
1640 * NOTE : There is a limit of 50 dtmf tones can be requested through a single VTS command.
1645 * +CME ERROR: <error>
1647 static TelReturn imc_call_send_dtmf(CoreObject *co, const char *dtmf_str,
1648 TcoreObjectResponseCallback cb, void *cb_data)
1651 char *tmp_dtmf = NULL, *dtmf;
1656 //(void) _set_dtmf_tone_duration(o, dup);
1658 /* DTMF digits + comma for each dtmf digit */
1659 tmp_dtmf = tcore_malloc0((strlen(dtmf_str) * 2) + 1);
1660 tcore_check_return_value_assert(tmp_dtmf != NULL, TEL_RETURN_FAILURE);
1661 /* Save initial pointer */
1664 for (count = 0; count < strlen(dtmf_str); count++) {
1665 *tmp_dtmf = dtmf_str[count];
1672 /* last digit is having COMMA , overwrite it with '\0'*/
1673 *(--tmp_dtmf) = '\0';
1675 /* (AT+VTS = <d1>,<d2>,<d3>,<d4>,<d5>,<d6>, ..... <d32> */
1676 at_cmd = g_strdup_printf("AT+VTS=%s", dtmf);
1677 dbg("at command : %s", at_cmd);
1681 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_send_dtmf");
1685 * Operation - call hold.
1688 * 1. AT-Command: AT+CHLD=[<n>]
1691 * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1692 * If only one call exists which is active, place it on hold and if only held call exists
1693 * make it active call
1698 * +CME ERROR: <error>
1700 static TelReturn imc_call_hold(CoreObject *co, TcoreObjectResponseCallback cb,
1707 at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1708 dbg("at command : %s", at_cmd);
1710 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_hold");
1714 * Operation - call active.
1717 * 1. AT-Command: AT+CHLD=[<n>]
1720 * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1721 * If only one call exists which is active, place it on hold and if only held call exists
1722 * make it active call
1727 * +CME ERROR: <error>
1729 static TelReturn imc_call_active(CoreObject *co, TcoreObjectResponseCallback cb,
1735 at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1736 dbg("at command : %s", at_cmd);
1738 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_active");
1742 * Operation - call swap.
1745 * 1. AT-Command: AT+CHLD=[<n>]
1748 * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1749 * If only one call exists which is active, place it on hold and if only held call exists
1750 * make it active call
1755 * +CME ERROR: <error>
1757 static TelReturn imc_call_swap(CoreObject *co, TcoreObjectResponseCallback cb,
1763 at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1764 dbg("at command : %s", at_cmd);
1766 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_swap");
1770 * Operation - call join.
1773 * 1. AT-Command: AT+CHLD=[<n>]
1776 * 3 - adds a held call to the conversation
1781 * +CME ERROR: <error>
1783 static TelReturn imc_call_join(CoreObject *co, TcoreObjectResponseCallback cb,
1789 at_cmd = g_strdup_printf("%s", "AT+CHLD=3");
1790 dbg("at command : %s", at_cmd);
1792 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_join");
1796 * Operation - call split.
1799 * 1. AT-Command: AT+CHLD=[<n>]
1802 * 2x - place all active calls on hold except call x with which communication is supported
1807 * +CME ERROR: <error>
1809 static TelReturn imc_call_split(CoreObject *co, unsigned int call_id,
1810 TcoreObjectResponseCallback cb, void *cb_data)
1815 at_cmd = g_strdup_printf("%s%d", "AT+CHLD=2", call_id);
1816 dbg("at command : %s", at_cmd);
1818 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_split");
1822 * Operation - call transfer.
1825 * 1. AT-Command: AT+CHLD=[<n>]
1828 * 4 connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)
1833 * +CME ERROR: <error>
1835 static TelReturn imc_call_transfer(CoreObject *co, TcoreObjectResponseCallback cb,
1841 at_cmd = g_strdup_printf("%s", "AT+CHLD=4");
1842 dbg("at command : %s", at_cmd);
1844 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_transfer");
1848 * Operation - call deflect.
1851 * 1. AT-Command: AT+CTFR= <number>[,<type>]
1854 * string type phone number
1856 * type of address octet in integer format. It is optional parameter.
1862 * +CME ERROR: <error>
1864 static TelReturn imc_call_deflect(CoreObject *co, const char *deflect_to,
1865 TcoreObjectResponseCallback cb, void *cb_data)
1870 at_cmd = g_strdup_printf("AT+CTFR=%s", deflect_to);
1871 dbg("at command : %s", at_cmd);
1873 return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_deflect");
1876 static TelReturn imc_call_set_active_line(CoreObject *co, TelCallActiveLine active_line,
1877 TcoreObjectResponseCallback cb, void *cb_data)
1882 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1885 static TelReturn imc_call_get_active_line(CoreObject *co, TcoreObjectResponseCallback cb,
1891 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1895 * Operation - Set voule info.
1898 * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1899 * The first command parameter defines the involved driver group.
1900 * The second command parameter defines a certain function in the selected driver group.
1901 * Other parameters are dependent on the first two parameters.
1902 * Nearly all parameters are integer values, also if they are represented by literals.
1903 * Only very few are strings or
1907 * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1908 * The first response parameter defines the involved driver group.
1909 * The second response parameter defines the current function in the selected driver group.
1910 * The third response parameter defines the xdrv_result of the operation.
1911 * Additional response parameters dependent on the first two parameters.
1913 static TelReturn imc_call_set_volume_info(CoreObject *co, const TelCallVolumeInfo *volume_info,
1914 TcoreObjectResponseCallback cb, void *cb_data)
1916 ImcRespCbData *resp_cb_data = NULL;
1919 struct imc_set_volume_info cb_volume_info;
1923 cb_volume_info.next_index = 1;
1924 cb_volume_info.volume = volume_info->volume;
1926 /* Response callback data */
1927 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
1928 &cb_volume_info, sizeof(struct imc_set_volume_info));
1930 at_cmd = g_strdup_printf("%s", xdrv_set_volume[0]);
1932 /* Send Request to modem */
1933 ret = tcore_at_prepare_and_send_request(co,
1935 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1937 on_response_imc_call_set_volume_info, resp_cb_data,
1938 on_send_imc_request, NULL);
1939 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info");
1946 static TelReturn imc_call_get_volume_info(CoreObject *co, TelCallSoundDevice sound_device,
1947 TcoreObjectResponseCallback cb, void *cb_data)
1952 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1956 * Operation - Set sound path.
1959 * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1960 * The first command parameter defines the involved driver group.
1961 * The second command parameter defines a certain function in the selected driver group.
1962 * Other parameters are dependent on the first two parameters.
1963 * Nearly all parameters are integer values, also if they are represented by literals.
1964 * Only very few are strings or
1968 * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1969 * The first response parameter defines the involved driver group.
1970 * The second response parameter defines the current function in the selected driver group.
1971 * The third response parameter defines the xdrv_result of the operation.
1972 * Additional response parameters dependent on the first two parameters.
1975 static TelReturn imc_call_set_sound_path(CoreObject *co, const TelCallSoundPathInfo *sound_path_info,
1976 TcoreObjectResponseCallback cb, void *cb_data)
1978 ImcRespCbData *resp_cb_data = NULL;
1981 gint device_type = -1;
1982 TcorePlugin *plugin = tcore_object_ref_plugin(co);
1983 const char *cp_name = tcore_server_get_cp_name_by_plugin(plugin);
1985 dbg("audio device type - 0x%x", sound_path_info->path);
1987 switch (sound_path_info->path) {
1988 case TEL_SOUND_PATH_HANDSET:
1991 case TEL_SOUND_PATH_HEADSET:
1994 case TEL_SOUND_PATH_HEADSET_3_5PI:
1997 case TEL_SOUND_PATH_SPK_PHONE:
2000 case TEL_SOUND_PATH_HANDSFREE:
2003 case TEL_SOUND_PATH_HEADSET_HAC:
2006 case TEL_SOUND_PATH_BLUETOOTH:
2007 case TEL_SOUND_PATH_STEREO_BLUETOOTH:
2010 case TEL_SOUND_PATH_BT_NSEC_OFF:
2011 case TEL_SOUND_PATH_MIC1:
2012 case TEL_SOUND_PATH_MIC2:
2014 dbg("unsupported device type");
2015 return TEL_RETURN_INVALID_PARAMETER;
2018 if (g_str_has_prefix(cp_name, "imcmodem")) {
2019 /* Response callback data */
2020 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &device_type, sizeof(gint));
2022 at_cmd = g_strdup_printf("AT+XDRV=40,4,3,0,0,0,0,0,1,0,1,0,%d", device_type);
2024 ret = tcore_at_prepare_and_send_request(co,
2026 TCORE_AT_COMMAND_TYPE_SINGLELINE,
2028 on_response_imc_call_set_sound_path, resp_cb_data,
2029 on_send_imc_request, NULL);
2030 IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path");
2033 /* Response callback data */
2034 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
2036 /* Configure modem I2S1 to 8khz, mono, PCM if routing to bluetooth */
2037 if (sound_path_info->path == TEL_SOUND_PATH_BLUETOOTH ||
2038 sound_path_info->path == TEL_SOUND_PATH_STEREO_BLUETOOTH) {
2039 tcore_at_prepare_and_send_request(co,
2040 "AT+XDRV=40,4,3,0,1,0,0,0,0,0,0,0,21",
2041 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2042 NULL, NULL, NULL, NULL, NULL);
2044 tcore_at_prepare_and_send_request(co,
2045 "AT+XDRV=40,5,2,0,1,0,0,0,0,0,0,0,22",
2046 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2047 NULL, NULL, NULL, NULL, NULL);
2049 tcore_at_prepare_and_send_request(co,
2050 "AT+XDRV=40,4,3,0,1,0,8,0,1,0,2,0,21",
2051 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2052 NULL, NULL, NULL, NULL, NULL);
2054 tcore_at_prepare_and_send_request(co,
2055 "AT+XDRV=40,5,2,0,1,0,8,0,1,0,2,0,22",
2056 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2057 NULL, NULL, NULL, NULL, NULL);
2060 /* Configure modem I2S2 and do the modem routing */
2061 tcore_at_prepare_and_send_request(co,
2062 "AT+XDRV=40,4,4,0,0,0,8,0,1,0,2,0,21",
2063 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2064 NULL, NULL, NULL, NULL, NULL);
2066 tcore_at_prepare_and_send_request(co,
2067 "AT+XDRV=40,5,3,0,0,0,8,0,1,0,2,0,22",
2068 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2069 NULL, NULL, NULL, NULL, NULL);
2071 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,0,4",
2072 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2073 NULL, NULL, NULL, NULL, NULL);
2075 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,3,0",
2076 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2077 NULL, NULL, NULL, NULL, NULL);
2079 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,4,2",
2080 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2081 NULL, NULL, NULL, NULL, NULL);
2083 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,5,2",
2084 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2085 NULL, NULL, NULL, NULL, NULL);
2088 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,2,4",
2089 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2090 NULL, NULL, NULL, NULL, NULL);
2092 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,2,3",
2093 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2094 NULL, NULL, NULL, NULL, NULL);
2096 /* amc route: AMC_RADIO_RX => AMC_I2S1_TX */
2097 ret = tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,0,2",
2098 "+XDRV", TCORE_AT_COMMAND_TYPE_SINGLELINE, NULL,
2099 on_response_set_sound_path, resp_cb_data, NULL, NULL);
2101 IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path");
2108 * Operation - Set/Unset mute status.
2111 * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
2112 * The first command parameter defines the involved driver group.
2113 * The second command parameter defines a certain function in the selected driver group.
2114 * Other parameters are dependent on the first two parameters.
2115 * Nearly all parameters are integer values, also if they are represented by literals.
2116 * Only very few are strings or
2120 * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
2121 * The first response parameter defines the involved driver group.
2122 * The second response parameter defines the current function in the selected driver group.
2123 * The third response parameter defines the xdrv_result of the operation.
2124 * Additional response parameters dependent on the first two parameters.
2126 static TelReturn imc_call_set_mute(CoreObject *co, gboolean mute, TcoreObjectResponseCallback cb,
2129 ImcRespCbData *resp_cb_data = NULL;
2135 /* Response callback data */
2136 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
2140 at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,0"); /*MUTE*/
2142 at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,88"); /*UNMUTE*/
2144 /* Send Request to modem */
2145 ret = tcore_at_prepare_and_send_request(co,
2147 TCORE_AT_COMMAND_TYPE_SINGLELINE,
2149 on_response_imc_call_set_mute, resp_cb_data,
2150 on_send_imc_request, NULL);
2151 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_mute");
2158 static TelReturn imc_call_get_mute_status(CoreObject *co, TcoreObjectResponseCallback cb,
2164 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
2168 static TelReturn imc_call_set_sound_recording(CoreObject *co, TelCallSoundRecording sound_rec,
2169 TcoreObjectResponseCallback cb, void *cb_data)
2174 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
2177 static TelReturn imc_call_set_sound_equalization(CoreObject *co, const TelCallSoundEqualization *sound_eq,
2178 TcoreObjectResponseCallback cb, void *cb_data)
2183 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
2186 /* Call Operations */
2187 static TcoreCallOps imc_call_ops = {
2188 .dial = imc_call_dial,
2189 .answer = imc_call_answer,
2190 .end = imc_call_end,
2191 .send_dtmf = imc_call_send_dtmf,
2192 .hold = imc_call_hold,
2193 .active = imc_call_active,
2194 .swap = imc_call_swap,
2195 .join = imc_call_join,
2196 .split = imc_call_split,
2197 .transfer = imc_call_transfer,
2198 .deflect = imc_call_deflect,
2199 .set_active_line = imc_call_set_active_line,
2200 .get_active_line = imc_call_get_active_line,
2201 .set_volume_info = imc_call_set_volume_info,
2202 .get_volume_info = imc_call_get_volume_info,
2203 .set_sound_path = imc_call_set_sound_path,
2204 .set_mute = imc_call_set_mute,
2205 .get_mute_status = imc_call_get_mute_status,
2206 .set_sound_recording = imc_call_set_sound_recording,
2207 .set_sound_equalization = imc_call_set_sound_equalization,
2210 gboolean imc_call_init(TcorePlugin *p, CoreObject *co)
2214 /* Set operations */
2215 tcore_call_set_ops(co, &imc_call_ops);
2218 tcore_object_add_callback(co, "+XCALLSTAT", on_notification_imc_call_status, NULL);
2219 tcore_object_add_callback(co, "+CLIP", on_notification_imc_call_clip_info, NULL);
2220 tcore_object_add_callback(co, "+CSSU", on_notification_imc_call_ss_cssu_info, NULL);
2221 tcore_object_add_callback(co, "+CSSI", on_notification_imc_call_ss_cssi_info, NULL);
2226 void imc_call_exit(TcorePlugin *p, CoreObject *co)