diff --git a/TCardEmulator/.cproject b/TCardEmulator/.cproject new file mode 100644 index 0000000..ec57683 --- /dev/null +++ b/TCardEmulator/.cproject @@ -0,0 +1,455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TCardEmulator/.exportMap b/TCardEmulator/.exportMap new file mode 100644 index 0000000..43e310e --- /dev/null +++ b/TCardEmulator/.exportMap @@ -0,0 +1,4 @@ +{ + global: main; + local: *; +}; diff --git a/TCardEmulator/.gitignore b/TCardEmulator/.gitignore new file mode 100644 index 0000000..65fa71e --- /dev/null +++ b/TCardEmulator/.gitignore @@ -0,0 +1,2 @@ +/Debug +/SA_Report diff --git a/TCardEmulator/.project b/TCardEmulator/.project new file mode 100644 index 0000000..1b8a612 --- /dev/null +++ b/TCardEmulator/.project @@ -0,0 +1,52 @@ + + + TCardEmulator + + + + + + org.tizen.nativecore.apichecker.apicheckerbuilder + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.tizen.nativecore.apichecker.apicheckernature + + + + 1464204018079 + + 26 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-*/.tpk + + + + 1464204018094 + + 6 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-project_def.prop + + + + diff --git a/TCardEmulator/.tproject b/TCardEmulator/.tproject new file mode 100644 index 0000000..8259637 --- /dev/null +++ b/TCardEmulator/.tproject @@ -0,0 +1,12 @@ + + + + + wearable-2.3.1 + + + + + + + diff --git a/TCardEmulator/inc/tcardemulator.h b/TCardEmulator/inc/tcardemulator.h new file mode 100644 index 0000000..7784530 --- /dev/null +++ b/TCardEmulator/inc/tcardemulator.h @@ -0,0 +1,26 @@ +#ifndef __tcardemulator_H__ +#define __tcardemulator_H__ + +#define LOG_TAG "tcardemulator" + +#if !defined(PACKAGE) +#define PACKAGE "com.vsmartcard.tcardemulator" +#endif + +#include +#include + +extern unsigned char *rapdu; +extern size_t rapdu_length; +extern gboolean rapdu_received; + +#define HELLO_ACC_ASPID "/sample/hello" +#define HELLO_ACC_CHANNELID 104 + +void initialize_sap(); +gboolean find_peers(); +gboolean request_service_connection(void); +gboolean terminate_service_connection(void); +gboolean send_data(void *message, unsigned int message_len); + +#endif /* __tcardemulator_H__ */ diff --git a/TCardEmulator/res/accessoryservices.xml b/TCardEmulator/res/accessoryservices.xml new file mode 100644 index 0000000..e73a26d --- /dev/null +++ b/TCardEmulator/res/accessoryservices.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/TCardEmulator/shared/res/ic_launcher.png b/TCardEmulator/shared/res/ic_launcher.png new file mode 100644 index 0000000..b02b6cf Binary files /dev/null and b/TCardEmulator/shared/res/ic_launcher.png differ diff --git a/TCardEmulator/shared/res/tcardemulator.png b/TCardEmulator/shared/res/tcardemulator.png new file mode 100644 index 0000000..9765b1b Binary files /dev/null and b/TCardEmulator/shared/res/tcardemulator.png differ diff --git a/TCardEmulator/shared/res/wallet.xml b/TCardEmulator/shared/res/wallet.xml new file mode 100644 index 0000000..e895b95 --- /dev/null +++ b/TCardEmulator/shared/res/wallet.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/TCardEmulator/src/sap.c b/TCardEmulator/src/sap.c new file mode 100644 index 0000000..f7ef2fb --- /dev/null +++ b/TCardEmulator/src/sap.c @@ -0,0 +1,370 @@ +#include "tcardemulator.h" +#include +#include +#include + +#define HELLO_ACCESSORY_PROFILE_ID "/sample/hello" +#define HELLO_ACCESSORY_CHANNELID 104 + +struct priv { + sap_agent_h agent; + sap_socket_h socket; + sap_peer_agent_h peer_agent; +}; + +static gboolean agent_created = FALSE; + +static struct priv priv_data = { 0 }; + +void on_peer_agent_updated(sap_peer_agent_h peer_agent, + sap_peer_agent_status_e peer_status, + sap_peer_agent_found_result_e result, + void *user_data) +{ + switch (result) { + case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED: + dlog_print(DLOG_INFO, LOG_TAG, "device is not connected"); + break; + + case SAP_PEER_AGENT_FOUND_RESULT_FOUND: + if (peer_status == SAP_PEER_AGENT_STATUS_AVAILABLE) { + priv_data.peer_agent = peer_agent; + dlog_print(DLOG_INFO, LOG_TAG, "Find Peer Success!!"); + request_service_connection(); + } else { + dlog_print(DLOG_INFO, LOG_TAG, "peer agent removed"); + sap_peer_agent_destroy(peer_agent); + } + break; + + case SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND: + dlog_print(DLOG_INFO, LOG_TAG, "service not found"); + break; + + case SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent find timed out"); + break; + + case SAP_PEER_AGENT_FOUND_RESULT_INTERNAL_ERROR: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent find search failed"); + break; + } +} + + +static void on_service_connection_terminated(sap_peer_agent_h peer_agent, + sap_socket_h socket, + sap_service_connection_result_e result, + void *user_data) +{ + switch (result) { + case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED: + dlog_print(DLOG_INFO, LOG_TAG, "disconnected because peer lost"); + break; + + case SAP_CONNECTION_TERMINATED_REASON_DEVICE_DETACHED: + dlog_print(DLOG_INFO, LOG_TAG, "disconnected because device is detached"); + break; + + default: + // fall through + case SAP_CONNECTION_TERMINATED_REASON_UNKNOWN: + dlog_print(DLOG_INFO, LOG_TAG, "disconnected because of unknown reason"); + break; + } + + sap_socket_destroy(priv_data.socket); + priv_data.socket = NULL; +} + + +static void on_data_recieved(sap_socket_h socket, + unsigned short int channel_id, + unsigned int payload_length, + void *buffer, + void *user_data) +{ + dlog_print(DLOG_INFO, LOG_TAG, "received data: %p, len:%d", buffer, payload_length); + unsigned char *p = realloc(rapdu, payload_length); + if (p) { + rapdu = p; + rapdu_length = payload_length; + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "not enough for storing data"); + if (rapdu && rapdu_length >= 2) { + dlog_print(DLOG_ERROR, LOG_TAG, + "not enough memory, returning 0x6D00 as R-APDU"); + rapdu[0] = 0x6D; + rapdu[1] = 0x00; + rapdu_length = 2; + } else { + dlog_print(DLOG_ERROR, LOG_TAG, + "not enough memory, setting R-APDU to nothing"); + rapdu_length = 0; + } + } + + rapdu_received = TRUE; +} + + +static void on_service_connection_created(sap_peer_agent_h peer_agent, + sap_socket_h socket, + sap_service_connection_result_e result, + void *user_data) +{ + switch (result) { + case SAP_CONNECTION_SUCCESS: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent connection is successful, pa :%u", peer_agent); + sap_peer_agent_set_service_connection_terminated_cb(priv_data.peer_agent, + on_service_connection_terminated, + NULL); + + sap_socket_set_data_received_cb(socket, on_data_recieved, peer_agent); + priv_data.socket = socket; + break; + + case SAP_CONNECTION_ALREADY_EXIST: + dlog_print(DLOG_INFO, LOG_TAG, "connection is already exist"); + priv_data.socket = socket; + break; + + case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE: + dlog_print(DLOG_INFO, LOG_TAG, "device is not unreachable"); + break; + + case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT: + dlog_print(DLOG_INFO, LOG_TAG, "invalid peer agent"); + break; + + case SAP_CONNECTION_FAILURE_NETWORK: + dlog_print(DLOG_INFO, LOG_TAG, "network failure"); + break; + + case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent is no response"); + break; + + case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent is rejected"); + break; + + case SAP_CONNECTION_FAILURE_UNKNOWN: + dlog_print(DLOG_INFO, LOG_TAG, "unknown error"); + break; + } +} + +static gboolean _create_service_connection(gpointer user_data) +{ + struct priv *priv = NULL; + sap_result_e result = SAP_RESULT_FAILURE; + + priv = (struct priv *)user_data; + result = sap_agent_request_service_connection(priv->agent, + priv->peer_agent, + on_service_connection_created, + NULL); + + if (result == SAP_RESULT_SUCCESS) { + dlog_print(DLOG_DEBUG, LOG_TAG, "req service conn call succeeded"); + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "req service conn call is failed (%d)", result); + } + + return FALSE; +} + +gboolean request_service_connection(void) +{ + g_idle_add(_create_service_connection, &priv_data); + + dlog_print(DLOG_DEBUG, LOG_TAG, "request_service_connection call over"); + return TRUE; +} + +static gboolean _terminate_service_connection(gpointer user_data) +{ + struct priv *priv = NULL; + sap_result_e result = SAP_RESULT_FAILURE; + + priv = (struct priv *)user_data; + + if (priv->socket) + result = sap_peer_agent_terminate_service_connection(priv->peer_agent); + else { + return FALSE; + } + + if (result == SAP_RESULT_SUCCESS) { + dlog_print(DLOG_DEBUG, LOG_TAG, "req service conn call succeeded"); + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "req service conn call is failed (%d)", result); + } + + return FALSE; +} + +gboolean terminate_service_connection(void) +{ + g_idle_add(_terminate_service_connection, &priv_data); + + return TRUE; +} + +static gboolean _find_peer_agent(gpointer user_data) +{ + struct priv *priv = NULL; + sap_result_e result = SAP_RESULT_FAILURE; + + priv = (struct priv *)user_data; + + result = sap_agent_find_peer_agent(priv->agent, on_peer_agent_updated, NULL); + + if (result == SAP_RESULT_SUCCESS) { + dlog_print(DLOG_DEBUG, LOG_TAG, "find peer call succeeded"); + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "find peer call failed (%d)", result); + } + + return FALSE; +} + +gboolean find_peers() +{ + g_idle_add(_find_peer_agent, &priv_data); + dlog_print(DLOG_DEBUG, LOG_TAG, "find peer called"); + return TRUE; +} + +gboolean send_data(void *message, unsigned int message_len) +{ + int result; + if (priv_data.socket) { + result = sap_socket_send_data(priv_data.socket, + HELLO_ACCESSORY_CHANNELID, message_len, message); + } else { + return FALSE; + } + return TRUE; +} + +static void on_agent_initialized(sap_agent_h agent, + sap_agent_initialized_result_e result, + void *user_data) +{ + switch (result) { + case SAP_AGENT_INITIALIZED_RESULT_SUCCESS: + dlog_print(DLOG_INFO, LOG_TAG, "agent is initialized"); + + priv_data.agent = agent; + agent_created = TRUE; + break; + + case SAP_AGENT_INITIALIZED_RESULT_DUPLICATED: + dlog_print(DLOG_INFO, LOG_TAG, "duplicate registration"); + break; + + case SAP_AGENT_INITIALIZED_RESULT_INVALID_ARGUMENTS: + dlog_print(DLOG_INFO, LOG_TAG, "invalid arguments"); + break; + + case SAP_AGENT_INITIALIZED_RESULT_INTERNAL_ERROR: + dlog_print(DLOG_INFO, LOG_TAG, "internal sap error"); + break; + + default: + dlog_print(DLOG_INFO, LOG_TAG, "unknown status (%d)", result); + break; + } +} + +static void on_device_status_changed(sap_device_status_e status, sap_transport_type_e transport_type, + void *user_data) +{ + switch (transport_type) { + case SAP_TRANSPORT_TYPE_BT: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): bt", transport_type); + break; + + case SAP_TRANSPORT_TYPE_BLE: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): ble", transport_type); + break; + + case SAP_TRANSPORT_TYPE_TCP: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): tcp/ip", transport_type); + break; + + case SAP_TRANSPORT_TYPE_USB: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): usb", transport_type); + break; + + case SAP_TRANSPORT_TYPE_MOBILE: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): mobile", transport_type); + break; + + default: + dlog_print(DLOG_INFO, LOG_TAG, "unknown connectivity type (%d)", transport_type); + break; + } + + switch (status) { + case SAP_DEVICE_STATUS_DETACHED: + + if (priv_data.peer_agent) { + sap_socket_destroy(priv_data.socket); + priv_data.socket = NULL; + sap_peer_agent_destroy(priv_data.peer_agent); + priv_data.peer_agent = NULL; + } + break; + + case SAP_DEVICE_STATUS_ATTACHED: + if (agent_created) { + g_idle_add(_find_peer_agent, &priv_data); + } + break; + + default: + dlog_print(DLOG_INFO, LOG_TAG, "unknown status (%d)", status); + break; + } +} + +gboolean agent_initialize() +{ + int result = 0, i = 1; + gboolean agent_initialized = TRUE; + + do { + if (i > 100) { + agent_initialized = FALSE; + break; + } + result = sap_agent_initialize(priv_data.agent, + HELLO_ACCESSORY_PROFILE_ID, SAP_AGENT_ROLE_CONSUMER, + on_agent_initialized, NULL); + dlog_print(DLOG_DEBUG, LOG_TAG, "sap_agent_initialize >>> %d", result); + i++; + } while (result != SAP_RESULT_SUCCESS); + + return agent_initialized; +} + +void initialize_sap() +{ + sap_agent_h agent = NULL; + + sap_agent_create(&agent); + + if (agent == NULL) + dlog_print(DLOG_ERROR, LOG_TAG, "ERROR in creating agent"); + else + dlog_print(DLOG_INFO, LOG_TAG, "SUCCESSFULLY create sap agent"); + + priv_data.agent = agent; + + sap_set_device_status_changed_cb(on_device_status_changed, NULL); + + agent_initialize(); +} diff --git a/TCardEmulator/src/tcardemulator.c b/TCardEmulator/src/tcardemulator.c new file mode 100644 index 0000000..cf7dc47 --- /dev/null +++ b/TCardEmulator/src/tcardemulator.c @@ -0,0 +1,166 @@ +#include "tcardemulator.h" +#include +#include +#include +#include +#include + +unsigned char *rapdu = NULL; +size_t rapdu_length = 0; +gboolean rapdu_received = FALSE; + + static void +hce_event_cb(nfc_se_h handle, nfc_hce_event_type_e event, + unsigned char *apdu, unsigned int apdu_len, void *user_data) +{ + switch (event) { + case NFC_HCE_EVENT_DEACTIVATED: + // Do something when NFC_HCE_EVENT_DEACTIVATED event arrives + // When the event arrives, apdu and apdu len is NULL and 0 + terminate_service_connection(); + break; + + case NFC_HCE_EVENT_ACTIVATED: + // Do something when NFC_HCE_EVENT_ACTIVATED event arrives + // When the event arrives, apdu and apdu len is NULL and 0 + find_peers(); + break; + + case NFC_HCE_EVENT_APDU_RECEIVED: + rapdu_received = FALSE; + send_data(apdu, apdu_len); + size_t count = 0; + while (!rapdu_received && count < 10) { + dlog_print(DLOG_INFO, LOG_TAG, "waiting for response"); + usleep(100); + count++; + } + nfc_hce_send_apdu_response(handle, rapdu, rapdu_length); + rapdu_received = FALSE; + break; + + default: + // Error handling + break; + } +} + + bool +service_app_create(void *data) +{ + int ret = NFC_ERROR_NONE; + bool r = false; + nfc_se_card_emulation_mode_type_e ce_type; + + ret = nfc_manager_initialize(); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_manager_initialize failed : %d", ret); + goto err; + } + + ret = nfc_se_get_card_emulation_mode(&ce_type); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_get_card_emulation_mode failed : %d", ret); + goto err; + } + + if (ce_type == NFC_SE_CARD_EMULATION_MODE_OFF) { + nfc_se_enable_card_emulation(); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_enable_card_emulation failed : %d", ret); + goto err; + } + } + + ret = nfc_manager_set_hce_event_cb(hce_event_cb, NULL); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_manager_set_hce_event_cb failed : %d", ret); + goto err; + } + + initialize_sap(); + + r = true; + +err: + return r; +} + + void +service_app_terminate(void *data) +{ + int ret = NFC_ERROR_NONE; + + nfc_manager_unset_hce_event_cb(); + + ret = nfc_manager_deinitialize(); + if (ret != NFC_ERROR_NONE) + { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_manager_deinitialize failed : %d", ret); + } + + terminate_service_connection(); + + free(rapdu); + rapdu = NULL; + rapdu_length = 0; + rapdu_received = FALSE; + + return; +} + + void +service_app_control(app_control_h app_control, void *data) +{ + // Todo: add your code here + + return; +} + + void +service_app_low_memory_callback(void *data) +{ + // Todo: add your code here + service_app_exit(); + + return; +} + + void +service_app_low_battery_callback(void *data) +{ + // Todo: add your code here + service_app_exit(); + + return; +} + + int +main(int argc, char* argv[]) +{ + char ad[50] = {0,}; + + service_app_event_callback_s event_callback; + + event_callback.create = service_app_create; + event_callback.terminate = service_app_terminate; + event_callback.app_control = service_app_control; + event_callback.low_memory = service_app_low_memory_callback; + event_callback.low_battery = service_app_low_battery_callback; + +#if 1 + initialize_sap(); + find_peers(); + rapdu_received = FALSE; + unsigned char apdu[] = {0x00, 0xa4, 0x00, 0x00}; + send_data(apdu, sizeof apdu); + size_t count = 0; + while (!rapdu_received && count < 10) { + dlog_print(DLOG_INFO, LOG_TAG, "waiting for response"); + usleep(100); + count++; + } +#endif + + return svc_app_main(argc, argv, &event_callback, ad); +} diff --git a/TCardEmulator/tizen-manifest.xml b/TCardEmulator/tizen-manifest.xml new file mode 100644 index 0000000..f099c89 --- /dev/null +++ b/TCardEmulator/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + ic_launcher.png + + + + + http://developer.samsung.com/tizen/privilege/accessoryprotocol + http://tizen.org/privilege/nfc.cardemulation + + true +