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"
39 static TelSapResult __imc_sap_convert_cme_error_tel_sap_result(const TcoreAtResponse *at_resp)
41 TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
43 GSList *tokens = NULL;
47 if (!at_resp || !at_resp->lines) {
48 err("Invalid response data");
52 line = (const gchar *)at_resp->lines->data;
53 tokens = tcore_at_tok_new(line);
54 if (g_slist_length(tokens) > 0) {
58 resp_str = g_slist_nth_data(tokens, 0);
60 err("Invalid CME Error data");
61 tcore_at_tok_free(tokens);
64 cme_err = atoi(resp_str);
65 dbg("CME Error: [%d]", cme_err);
70 result = TEL_SAP_RESULT_OPERATION_NOT_PERMITTED;
74 result = TEL_SAP_RESULT_ONGOING_CALL;
78 result = TEL_SAP_RESULT_FAILURE_NO_REASON;
81 tcore_at_tok_free(tokens);
86 static TelSapResult __map_sap_status_to_result(int sap_status)
90 return TEL_SAP_RESULT_SUCCESS;
92 return TEL_SAP_RESULT_FAILURE_NO_REASON;
94 return TEL_SAP_RESULT_CARD_NOT_ACCESSIBLE;
96 return TEL_SAP_RESULT_CARD_ALREADY_POWERED_OFF;
98 return TEL_SAP_RESULT_CARD_REMOVED;
100 return TEL_SAP_RESULT_CARD_ALREADY_POWERED_ON;
102 return TEL_SAP_RESULT_DATA_NOT_AVAILABLE;
104 return TEL_SAP_RESULT_NOT_SUPPORTED;
106 return TEL_SAP_RESULT_FAILURE_NO_REASON;
111 static gboolean on_notification_imc_sap_status(CoreObject *co,
112 const void *event_info, void *user_data)
114 GSList *tokens = NULL;
115 GSList *lines = NULL;
116 const char *line = NULL;
117 TelSapCardStatus status;
121 lines = (GSList *) event_info;
122 if (g_slist_length(lines) != 1) {
123 err("unsolicited msg but multiple lines");
127 line = (char *)lines->data;
128 tokens = tcore_at_tok_new(line);
129 tcore_check_return_value(tokens != NULL, FALSE);
131 status = atoi(g_slist_nth_data(tokens, 0));
135 status = TEL_SAP_CARD_STATUS_UNKNOWN;
138 status = TEL_SAP_CARD_STATUS_RESET;
141 status = TEL_SAP_CARD_STATUS_NOT_ACCESSIBLE;
144 status = TEL_SAP_CARD_STATUS_REMOVED;
147 status = TEL_SAP_CARD_STATUS_INSERTED;
150 status = TEL_SAP_CARD_STATUS_RECOVERED;
153 status = TEL_SAP_CARD_STATUS_NOT_ACCESSIBLE;
157 tcore_at_tok_free(tokens);
158 tcore_object_send_notification(co,
159 TCORE_NOTIFICATION_SAP_STATUS,
160 sizeof(TelSapCardStatus), &status);
165 static void on_response_imc_sap_req_connect(TcorePending *p,
166 guint data_len, const void *data, void *user_data)
168 const TcoreAtResponse *at_resp = data;
169 CoreObject *co = tcore_pending_ref_core_object(p);
170 ImcRespCbData *resp_cb_data = user_data;
171 TelSapResult result = TEL_SAP_RESULT_UNABLE_TO_ESTABLISH;
172 unsigned int max_msg_size = 0;
175 tcore_check_return_assert(co != NULL);
176 tcore_check_return_assert(resp_cb_data != NULL);
178 if (at_resp && at_resp->success) {
179 result = TEL_SAP_RESULT_SUCCESS;
180 memcpy(&max_msg_size, IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data), sizeof(unsigned int));
183 result = __imc_sap_convert_cme_error_tel_sap_result(at_resp);
186 dbg("Request to sap connection : [%s]",
187 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
189 /* Invoke callback */
190 if (resp_cb_data->cb)
191 resp_cb_data->cb(co, (gint)result, &max_msg_size, resp_cb_data->cb_data);
193 /* Free callback data */
194 imc_destroy_resp_cb_data(resp_cb_data);
197 static void on_response_imc_sap_req_disconnect(TcorePending *p,
198 guint data_len, const void *data, void *user_data)
200 const TcoreAtResponse *at_resp = data;
201 CoreObject *co = tcore_pending_ref_core_object(p);
202 ImcRespCbData *resp_cb_data = user_data;
203 TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
206 tcore_check_return_assert(co != NULL);
207 tcore_check_return_assert(resp_cb_data != NULL);
209 if (at_resp && at_resp->success) {
210 result = TEL_SAP_RESULT_SUCCESS;
213 result = __imc_sap_convert_cme_error_tel_sap_result(at_resp);
216 dbg("Request to sap connection : [%s]",
217 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
219 /* Invoke callback */
220 if (resp_cb_data->cb)
221 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
223 /* Free callback data */
224 imc_destroy_resp_cb_data(resp_cb_data);
227 static void on_response_imc_sap_get_atr(TcorePending *p,
228 guint data_len, const void *data, void *user_data)
230 const TcoreAtResponse *at_resp = data;
231 CoreObject *co = tcore_pending_ref_core_object(p);
232 ImcRespCbData *resp_cb_data = user_data;
233 TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
234 TelSapAtr atr_resp = {0,};
238 if (at_resp && at_resp->success) {
241 GSList *tokens = NULL;
244 if (at_resp->lines == NULL) {
245 err("invalid response recieved");
249 line = (const char*)at_resp->lines->data;
250 tokens = tcore_at_tok_new(line);
251 if (g_slist_length(tokens) < 1) {
252 err("invalid response message");
253 tcore_at_tok_free(tokens);
256 atr_data = (char *) g_slist_nth_data(tokens, 1);
257 atr_resp.atr_len = strlen(atr_data);
258 if (atr_resp.atr_len > TEL_SAP_ATR_LEN_MAX) {
259 err(" invalid atr data length");
260 tcore_at_tok_free(tokens);
263 memcpy(atr_resp.atr, atr_data, atr_resp.atr_len);
265 result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0)));
266 tcore_at_tok_free(tokens);
269 result = __imc_sap_convert_cme_error_tel_sap_result(at_resp);
273 dbg("Request to get sap atr : [%s]",
274 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
276 /* Invoke callback */
277 if (resp_cb_data->cb)
278 resp_cb_data->cb(co, (gint)result, &atr_resp, resp_cb_data->cb_data);
280 /* Free callback data */
281 imc_destroy_resp_cb_data(resp_cb_data);
284 static void on_response_imc_sap_req_transfer_apdu(TcorePending *p,
285 guint data_len, const void *data, void *user_data)
287 const TcoreAtResponse *at_resp = data;
288 CoreObject *co = tcore_pending_ref_core_object(p);
289 ImcRespCbData *resp_cb_data = user_data;
290 TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
291 TelSapApduResp apdu_resp = {0,};
295 if (at_resp && at_resp->success) {
299 GSList *tokens = NULL;
302 if (at_resp->lines == NULL) {
303 err("invalid response recieved");
307 line = (const char*)at_resp->lines->data;
308 tokens = tcore_at_tok_new(line);
309 if (g_slist_length(tokens) < 1) {
310 err("invalid response message");
311 tcore_at_tok_free(tokens);
315 apdu_data = (char *) g_slist_nth_data(tokens, 1);
316 apdu_resp.apdu_resp_len = strlen(apdu_data);
317 if (apdu_resp.apdu_resp_len > TEL_SAP_APDU_RESP_LEN_MAX) {
318 err(" invalid apdu data length");
319 tcore_at_tok_free(tokens);
322 memcpy(apdu_resp.apdu_resp, apdu_data, apdu_resp.apdu_resp_len);
324 sap_status = atoi(g_slist_nth_data(tokens, 0));
326 /* In this case modem does not provide sap_status 5 ('Card already powered ON'),
327 instead it will provide status 5 ('Data not available') and 6 ('Not Supported'),
328 So to align 'sap_status' value with __map_sap_status_to_result(), it is increased by 1.
330 result = __map_sap_status_to_result(sap_status + 1);
332 result = __map_sap_status_to_result(sap_status);
334 tcore_at_tok_free(tokens);
337 result = __imc_sap_convert_cme_error_tel_sap_result(at_resp);
341 dbg("Request to transfer apdu : [%s]",
342 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
344 /* Invoke callback */
345 if (resp_cb_data->cb)
346 resp_cb_data->cb(co, (gint)result, &apdu_resp, resp_cb_data->cb_data);
348 /* Free callback data */
349 imc_destroy_resp_cb_data(resp_cb_data);
352 static void on_response_imc_sap_req_power_operation(TcorePending *p,
353 guint data_len, const void *data, void *user_data)
355 const TcoreAtResponse *at_resp = data;
356 CoreObject *co = tcore_pending_ref_core_object(p);
357 ImcRespCbData *resp_cb_data = user_data;
358 TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
362 if (at_resp && at_resp->success) {
364 GSList *tokens = NULL;
367 if (at_resp->lines == NULL) {
368 err("invalid response recieved");
372 line = (const char*)at_resp->lines->data;
373 tokens = tcore_at_tok_new(line);
374 if (g_slist_length(tokens) < 1) {
375 err("invalid response message");
376 tcore_at_tok_free(tokens);
379 result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0)));
380 tcore_at_tok_free(tokens);
383 result = __imc_sap_convert_cme_error_tel_sap_result(at_resp);
387 dbg("Request to sap power operation : [%s]",
388 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
390 /* Invoke callback */
391 if (resp_cb_data->cb)
392 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
394 /* Free callback data */
395 imc_destroy_resp_cb_data(resp_cb_data);
398 static void on_response_imc_sap_get_cardreader_status(TcorePending *p,
399 guint data_len, const void *data, void *user_data)
401 const TcoreAtResponse *at_resp = data;
402 CoreObject *co = tcore_pending_ref_core_object(p);
403 ImcRespCbData *resp_cb_data = user_data;
404 TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
405 TelSapCardStatus card_status = TEL_SAP_CARD_STATUS_UNKNOWN;
408 if (at_resp && at_resp->success) {
410 GSList *tokens = NULL;
411 unsigned char card_reader_status;
415 if (at_resp->lines == NULL) {
416 err("invalid response recieved");
420 line = (const char*)at_resp->lines->data;
421 tokens = tcore_at_tok_new(line);
422 if (g_slist_length(tokens) < 1) {
423 err("invalid response message");
424 tcore_at_tok_free(tokens);
427 result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0)));
429 card_reader_status = (unsigned char)atoi(g_slist_nth_data(tokens, 1));
430 card_reader_status = card_reader_status >> 3;
431 for (count = 8; count > 3; count--) { //check bit 8 to 3
432 /*TODO - Need to map card reader status to TelSapCardStatus.
433 if ((card_reader_status & 0x80) == TRUE) { //Check most significant bit
434 //card_status = TEL_SAP_CARD_STATUS_UNKNOWN;
438 card_reader_status = card_reader_status << 1; //left shift by 1
440 tcore_at_tok_free(tokens);
443 result = __imc_sap_convert_cme_error_tel_sap_result(at_resp);
447 dbg("Request to get card reader status : [%s]",
448 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
450 /* Invoke callback */
451 if (resp_cb_data->cb)
452 resp_cb_data->cb(co, (gint)result, &card_status, resp_cb_data->cb_data);
454 /* Free callback data */
455 imc_destroy_resp_cb_data(resp_cb_data);
461 * Operation - switch the modem to the BT SAP server mode.
464 * AT-Command: AT+ XBCON = <op_mode>, <change_mode>, <reject_mode>
467 * 0 - BT SAP Server modes
468 * 1 - BT SAP Client mode (Client mode is currently not supported)
470 * 0 - gracefully, or Time out
473 * 0 - Reject is not allowed.
474 * 1 - Reject is allowed.
476 * Success: (No Result)
479 * +CME ERROR: <error>
481 static TelReturn imc_sap_req_connect(CoreObject *co, unsigned int max_msg_size,
482 TcoreObjectResponseCallback cb, void *cb_data)
484 ImcRespCbData *resp_cb_data;
487 /* Response callback data */
488 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
489 &max_msg_size, sizeof(unsigned int));
491 /* Send Request to modem */
492 ret = tcore_at_prepare_and_send_request(co,
493 "AT+XBCON=0,0,0", NULL,
494 TCORE_AT_COMMAND_TYPE_NO_RESULT,
496 on_response_imc_sap_req_connect, resp_cb_data,
497 on_send_imc_request, NULL);
498 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_connect");
504 * Operation - disconnects BT SAP.
507 * AT-Command: AT+ XBDISC
510 * Success: (No Result)
513 * +CME ERROR: <error>
515 static TelReturn imc_sap_req_disconnect(CoreObject *co, TcoreObjectResponseCallback cb,
518 ImcRespCbData *resp_cb_data;
521 /* Response callback data */
522 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
525 /* Send Request to modem */
526 ret = tcore_at_prepare_and_send_request(co,
528 TCORE_AT_COMMAND_TYPE_NO_RESULT,
530 on_response_imc_sap_req_disconnect, resp_cb_data,
531 on_send_imc_request, NULL);
532 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_disconnect");
538 * Operation - In BT SAP server mode, request the ATR from the stack to the Application.
541 * AT-Command: AT+ XBATR
544 * Success: +XBATR: <status>, <data_ATR>
548 * 0 OK, request processed correctly
549 * 1 No Reason defined
550 * 2 Card not accessible
551 * 3 Card (already) powered off
553 * 6 Data Not available
556 * Hex Data (an array of bytes)
559 * +CME ERROR: <error>
561 static TelReturn imc_sap_get_atr(CoreObject *co, TcoreObjectResponseCallback cb,
564 ImcRespCbData *resp_cb_data;
567 /* Response callback data */
568 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
571 /* Send Request to modem */
572 ret = tcore_at_prepare_and_send_request(co,
573 "AT+XBATR", "+XBATR:",
574 TCORE_AT_COMMAND_TYPE_SINGLELINE,
576 on_response_imc_sap_get_atr, resp_cb_data,
577 on_send_imc_request, NULL);
578 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_get_atr");
584 * Operation - BT SAP server mode, Forward command APDU from application to SIM.
587 * AT-Command: AT+ XBAPDU = <data: command_APDU >
589 * <data: command_APDU >
590 * Hex Data (an array of bytes). CP supports Command_APDU up to 261 bytes long.
593 * Success: +XBAPDU: <status>, [<data:Response_APDU>]
597 * 0 OK, request processed correctly
598 * 1 No Reason defined
599 * 2 Card not accessible
600 * 3 Card (already) powered off
602 * 5 Data not available
604 * <data:Response_APDU>
605 * Hex Data (an array of bytes). CP supports Response_APDU up to 258 bytes long
607 * +CME ERROR: <error>
609 static TelReturn imc_sap_req_transfer_apdu(CoreObject *co, const TelSapApdu *apdu_data,
610 TcoreObjectResponseCallback cb, void *cb_data)
612 ImcRespCbData *resp_cb_data;
617 at_cmd = g_strdup_printf("AT+XBAPDU=\"%s\"", apdu_data->apdu);
619 /* Response callback data */
620 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
623 /* Send Request to modem */
624 ret = tcore_at_prepare_and_send_request(co,
626 TCORE_AT_COMMAND_TYPE_SINGLELINE,
628 on_response_imc_sap_req_transfer_apdu, resp_cb_data,
629 on_send_imc_request, NULL);
630 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_transfer_apdu");
636 static TelReturn imc_sap_req_transport_protocol(CoreObject *co, TelSimSapProtocol protocol,
637 TcoreObjectResponseCallback cb, void *cb_data)
639 err("Operation not supported");
640 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
644 * Operation - In BT SAP server mode, Power ON,OFF and Reset the SIM.
647 * AT-Command: AT+ XBPWR =<action>
655 * Success: + XBPWR: <status>
659 * 0 OK, Request processed correctly
660 * 1 Error no reason defined
661 * 2 Card not Accessible
662 * 3 Card already powered OFF
664 * 5 Card already powered ON
665 * 6 Data Not vailable
668 * +CME ERROR: <error>
670 static TelReturn imc_sap_req_power_operation(CoreObject *co, TelSapPowerMode power_mode,
671 TcoreObjectResponseCallback cb, void *cb_data)
673 ImcRespCbData *resp_cb_data;
674 TelReturn ret = TEL_RETURN_FAILURE;
678 if(power_mode == TEL_SAP_SIM_POWER_ON_REQ) {
680 } else if(power_mode == TEL_SAP_SIM_POWER_OFF_REQ) {
682 } else if (power_mode == TEL_SAP_SIM_RESET_REQ) {
685 err("invalid power mode");
690 at_cmd = g_strdup_printf("AT+XBPWR=%d", action);
692 /* Response callback data */
693 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
696 /* Send Request to modem */
697 ret = tcore_at_prepare_and_send_request(co,
699 TCORE_AT_COMMAND_TYPE_SINGLELINE,
701 on_response_imc_sap_req_power_operation, resp_cb_data,
702 on_send_imc_request, NULL);
703 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_power_operation");
710 * Operation - In BT SAP server mode, get the Card reader Status.
713 * AT-Command: AT+XBCRDSTAT
716 * Success: +XBCRDSTAT: <status>, <card_reader_status>
720 * 0 OK, Request processed correctly
721 * 1 Error no reason defined
722 * 2 Card not Accessible
723 * 3 Card already powered OFF
725 * 5 Card already powered ON
726 * 6 Data Not vailable
728 * <card_reader_status>
729 * One byte. It represents card reader identity and status.
730 * The value of this byte indicates the identity and status of a card reader.
731 * Bits 1-3 = identity of card reader x.
732 * bit 4, 0 = Card reader is not removable, 1 = Card reader is removable
733 * bit 5, 0 = Card reader is not present, 1 = Card reader is present
734 * bit 6, 0 = Card reader present is not ID-1 size, 1 = Card reader present is ID-1 size
735 * bit 7, 0 = No card present, 1 = Card is present in reader
736 * bit 8, 0 = No card powered, 1 = Card in reader is powered
738 * +CME ERROR: <error>
740 static TelReturn imc_sap_get_cardreader_status(CoreObject *co, TcoreObjectResponseCallback cb,
743 ImcRespCbData *resp_cb_data;
746 /* Response callback data */
747 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
750 /* Send Request to modem */
751 ret = tcore_at_prepare_and_send_request(co,
752 "AT+XBCRDSTAT", "+XBCRDSTAT:",
753 TCORE_AT_COMMAND_TYPE_SINGLELINE,
755 on_response_imc_sap_get_cardreader_status, resp_cb_data,
756 on_send_imc_request, NULL);
757 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_get_cardreader_status");
763 static TcoreSapOps imc_sap_ops = {
764 .req_connect = imc_sap_req_connect,
765 .req_disconnect = imc_sap_req_disconnect,
766 .get_atr = imc_sap_get_atr,
767 .req_transfer_apdu = imc_sap_req_transfer_apdu,
768 .req_transport_protocol = imc_sap_req_transport_protocol,
769 .req_power_operation = imc_sap_req_power_operation,
770 .get_cardreader_status = imc_sap_get_cardreader_status
773 gboolean imc_sap_init(TcorePlugin *p, CoreObject *co)
778 tcore_sap_set_ops(co, &imc_sap_ops);
781 tcore_object_add_callback(co, "+XBCSTAT", on_notification_imc_sap_status, NULL);
787 void imc_sap_exit(TcorePlugin *p, CoreObject *co)