Wearable native

SAP

This document is a guide for Samsung Accessory Software Development Kit (SDK). It will help you understand the basics of Samsung Accessory Service Framework, and guide you in the design and development of Accessory Services deployable on Samsung Smart Devices running the Samsung Accessory Protocol.

Samsung Accessory Service Framework is supported on multiple connectivity technologies and enables Accessory Devices to interact with Samsung Smart Devices in order to realize your desired use cases. This document does not cover Samsung Accessory Network Protocol, procedures for Discovery, Authentication, or any Service Profile Protocols.

For information on those topics, please consult appropriate documents.

Basic Accessory Service Terms

Samsung Accessory SDK allows you to develop applications on Samsung Smart Devices and Accessory Devices. You can connect Accessory Devices to Samsung Smart Devices without worrying about connectivity issues or network protocols..

You can use Accessory to:

A glossary for the Accessory SDK is listed up in the following table.

Table: Accessory service glossary
Term Description
Accessory service profile An Accessory Service Profile defines the roles of Service Provider and Service Consumer. It also specifies the formats for application-level protocol messages and message sequences between Service Consumers and Service Providers. For example, the Notification Accessory Service Profile defines the JSON schemas for messages used to send and receive notifications between Samsung Smart Devices and compliant Accessory Devices. An Accessory Service Profile also defines message sequences between a notification Service Consumer and a notification Service Provider.
Service provider A Service Provider is an application with a role defined in the associated Accessory Service Profile specification. It accepts incoming Service Connections from Service Consumers and initiates outgoing Service Connections to Service Consumers. A Service Provider registers with the Samsung Accessory Service Framework to advertise its services to Service Consumers on connected Accessory Devices. For example, a notification Service Provider implemented on a Smart Device provides notifications from that Smart Device to interested Service Consumers on connected Accessory Devices.
Service consumer A Service Consumer is an application with a role defined in the associated Accessory Service Profile specification. It discovers a matching Service Provider using the Capability Exchange Protocol, initiates outgoing Service Connections with the matching Service Provider, and accepts Service Connection requests from Service Providers. A Service Consumer uses the information or service provided by the matching Service Provider. It has to register with the Samsung Accessory Service Framework. For example, a notification Service Consumer implemented on an Accessory Device receives notification information from the notification Service Provider on a connected Smart Device.
Accessory peer agent An Accessory Peer Agent is the main interface between the Samsung Accessory Service Framework and the application implementing a Service Provider or Service Consumer. The Samsung Accessory Service Framework views both Service Providers and Service Consumers as Accessory Peer Agents.
Service connection A Service Channel is a logical data channel between a Service Consumer and a Service Provider. The channel ID, data rate, priority, and delivery type distinguish Service Channels from each other. While a Service Connection is a multi-lane highway between a Service Consumer and a Service Provider, the Service Channel is an individual lane of that highway.
Service channel A service channel is a logical data channel between a service consumer and provider. The channel ID, data rate, priority, and delivery type distinguish different service channels from each other. While a service connection is a multi-lane highway between a service consumer and provider, the service channel is an individual lane of that highway.

Accessory Peer Agent States

Accessory Peer Agents (both Service Providers and Service Consumers) are expected to handle concurrent instances, which means it is possible for a Service Provider to accept incoming Service Connections from multiple Service Consumers of the same Accessory Service Profile (E.g. Notification Service) and vice versa. Every accepted Service Connection request will result in the creation of a Service Handle, which represents the dialogue between Service Provider and Service Consumer of the same Accessory Service Profile. Accessory Service Framework establishes one or more Service Channel(s) with the QoS parameters as necessitated by Accessory Service Profile.



Figure: Accessory peer agent state machine

Accessory peer agent state machine

Above Figure illustrates the state machine of an Accessory Peer Agent with one Accessory Peer Agent. For scenarios with more than one Accessory Peer Agents connected, Accessory Peer Agent may be in different states with different remote Accessory Peer Agents. E.g. Connected state for some remote Accessory Peer Agents while in Registered (disconnected) state with other remote Accessory Peer Agents.

  • Service Provider or Service Consumer application is automatically registered with Accessory Service Framework upon installation and enters the Registered state; it is automatically deregistered upon uninstallation and goes to Unregistered state.
  • The Accessory Peer Agent can initiate an outgoing Service Connection with a matching remote Accessory Peer Agent (must belong to the same Accessory Service Profile and have a complementary provider/consumer relation). Upon doing so, it enters Connecting state.
  • If a Service Connection request is accepted by Accessory Peer Agent, then the Service Connection will be established by Accessory Service Framework. The Accessory Peer Agent enters Connected state on success. If the remote Accessory Peer Agent rejects its Service Connection request or in case of failure, the Accessory Peer Agent goes back to Registered state.
  • Service Provider or Service Consumer application is notified when a Service Connection request is received from remote Accessory Peer Agent.
  • Accessory Agent application may decide to accept or reject the incoming Service Connection request. An accepted response results in Service Connection establishment if no failure occurs, causing the Accessory Peer Agent to enter the Connected state. Otherwise (reject Service Connection or failure occurs), it stays in the Registered state.

The following figure shows the connection request flow of the accessory peer agents.

Figure: Connection request flow

Connection request flow

Begin Programming

Relevant APIs in Tizen Accessory SDK

This section briefly explains APIS in SAPD which will help us use underlying framework.

The following callbacks and api's are present.

sap_agent_initialized_cb - This callback is triggered on completion of sap initialization.

sap_agent_deinitialized_cb -This callback is triggered after sap de-initialization is completed.

sap_peer_agent_updated_cb - This callback is triggered when a matching service agent is registered or de-registered in a connected peer. It gives us the peer agent, status and local agent id.

sap_peer_agent_auth_info_received_cb - This callback is triggered to notify the sap_peer_agent_request_auth_info response.

sap_service_connection_requested_cb - This callback is triggered when a remote peer agent requests for a service connection.

sap_service_connection_terminated_cb - This is triggered when the remote peer agent terminates the service connection.

sap_service_connection_established_cb - This callback notifies the status of the requested service connection.

sap_socket_data_received_cb - This callback is used to receive data from an active service connection.

sap_device_status_changed_cb - This callback is triggered when the device state changes, thus indicating device connection and disconnection.

sap_socket_ready_to_send_cb - This callback is triggered when there is space available for the application to send data. Application should wait for this callback if sap_socket_send_data returns failure with BUFFER_FULL.

sap_socket_set_ready_to_send_cb - This API is used to register the callback.

sap_agent_set_service_connection_requested_cb - This API is used to register the callback for the service connection request coming from the remote Accessory Peer Agent.

sap_peer_agent_set_service_connection_terminated_cb - This API is used to register the callback for the service connection termination coming from the remote Accessory Peer Agent.

sap_set_device_status_changed_cb - This API is used to register the callback which is triggered when there is a change in device connection status

sap_socket_set_data_received_cb - This API is used to register the callback sap_socket_data_received_cb, on which data is received by the app.

sap_agent_find_peer_agent - This API is called to locate peer agent on a remote connected device. It uses local agent id as a parameter.

sap_peer_agent_request_auth_info - This API is called to authenticate the remote peer agent before creating a service connection. This is an optional step

sap_agent_create - This function is called by the application to get a new instance of sap agent.

sap_agent_initialize - This function is called by the application to get the agent id assigned for its service profiles

sap_agent_request_service_connection - This API is used to create a service connection, to the found peer agent on a remote device, which will help us transfer data. It takes local and remote agent id as parameters.

sap_peer_agent_accept_service_connection - Accepts an incoming service connection request. This is typically called from the registered callback sap_service_connection_cb()

sap_peer_agent_reject_service_connection - This callback function gets to notify the success or failure of service connection request initiated by the remote peer

sap_socket_send_data - This accomplishes the purpose of sending data to a connected remote peer agent. It has service handle, channel id, payload length and payload as parameters.

sap_socket_send_secure_data - Sends secure data over a service connection. If sending failed with BUFFER_FULL, app should wait for sap_on_space_available_cb callback.

sap_peer_agent_terminate_service_connection - This closes the connection with remote peer agent. It uses local peer agent id and remote peer agent id as parameters.

sap_peer_agent_is_feature_enabled - This API checks if the specified feature is enabled by the peer.

Note
In case of emulator, data encryption is disabled. sap_socket_send_secure_data will send data without encrypting it.



Tizen Manifest Declarations

To manage service connections, you must manage the manifest file declarations. The service provider or consumer application needs an org.tizen.hellosap.xml file, similar to the following example:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns="http://tizen.org/ns/packages" package="org.tizen.hellosap"
          version="0.1.0" install-location="internal-only">
    <label>HelloSAP Consumer</label>
    <author email="hellosap@samsung.com" href="www.samsung.com">Hello SAP</author>
    <description>HelloSAP consumer service</description>
    <ui-application component-type="svcapp" auto-restart="false" on-boot="false"
                    appid="org.tizen.hellosap.consumer"
                    exec="/opt/apps/org.tizen.hellosap/bin/hellosap"
                    nodisplay="true"  multiple="false" type="capp" taskmanage="false">
        <metadata key="accessory-services-location" value="/res/xml/accessoryservices.xml"/>
        <metadata key="launch-on-attach" value="true"/>
    </ui-application>
</manifest>

In addition, your application must provide service profile information in an accessory XML file, such as /res/xml/<yourname>.xml, and declare the path of the XML file in the org.tizen.hellosap.xml file:

<metadata key="accessory-services-location" value="/res/xml/accessoryservices.xml"/>



Registering a Service Provider or Consumer

The service provider or consumer must register itself by specifying an accessory service profile description with the Samsung Accessory Service Framework. This registration creates an entry in the local Capability database. The Accessory Capability Exchange module advertises the registered services to all connected Samsung accessory devices.

The registration process needs the accessory service profile description in the accessory XML file, located in the /res/xml folder of your Tizen project. If a single application implements multiple service providers and consumers, multiple accessory service profile descriptions must be declared in the accessory XML file.

<resources>
    <application name="HelloAccessoryConsumer">
        <serviceProfile id="/sample/hello"
                        name="hellosap_consumer"
                        role="consumer"
                        autoLaunchAppId="org.tizen.hellosap.consumer"
                        version="1.0">
            <supportedTransports>
                <transport type="TRANSPORT_BT"/>
                <transport type="TRANSPORT_BLE"/>
            </supportedTransports>
            <serviceChannel id="104"
                            dataRate="low"
                            priority="low"
                            reliability="enable">
            </serviceChannel>
        </serviceProfile>
    </application>
</resources>

In the accessory XMl file:

  • For the <application> name attribute, give the application name that you want the Samsung Accessory Service Framework to advertise in the accessory eco-system. Usually, it is the same as your application's Tizen AppName.
  • To implement multiple service providers and consumers in one application, declare multiple <serviceProfile> elements inside the <application> element.
  • In each <serviceProfile> element:
    • autoLaunchAppId attribute must be your Tizen package name to achieve the automatic launching of the application upon request from the caller app.
    • role attribute must be provider or consumer.
    • name attribute is the friendly name of your service provider or consumer.
    • id attribute is the service profile identifier of the service provider or consumer.
    • version attribute must specify the service profile specification version that your service provider or consumer implements.
  • In the <supportedTransports> element, declare the transports the service provider or consumer is able to operate on. Currently, the Samsung Accessory Service Framework supports the TRANSPORT_WIFI, TRANSPORT_BT, TRANSPORT_BLE, and TRANSPORT_USB transports. If the service provider or consumer supports multiple kinds of transports, add multiple <transport> elements. The above example shows a service consumer that supports only Bluetooth.
  • In the <serviceChannel> element:
    • id attribute must specify the predefined channel number.
    • datarate attribute must be specified as low or high.
    • priority attribute must be specified as low, medium, or high.
    • reliability attribute must be enable or disable.

The Samsung Accessory Service Framework automatically registers accessory peer agents when applications are installed, and deregisters them when applications are uninstalled. An error log is dumped in case the registration process fails to register an accessory service profile implementation. To avoid registration failures, validate your DTD (Document Type Definition) schema during development.

Note
In case of emulator, TRANSPORT_WIFI should be added under supported transports field.



Initializing a Service Agent and Peer Discovery

Before initializing a service agent, Application needs to create an instance of sap_agent by calling sap_agent_create(). Then service provider or consumer application can initialize the service agent by calling the sap_agent_initialize() function to fetch the agent ID for the registered service agent. If an accessory peer agent is found, the calling accessory peer agent is notified through the _on_sap_agent_initialized() callback, which was registered in the sap_agent_initialize() function.

When the initialization is successful, callbacks are registered to notify the application when a service connection creation or termination request arrives from a remote accessory peer agent (sap_service_connection_requested_cb() and sap_service_connection_terminated_cb()).

The find_peers() function initiates a search for matching accessory peer agents available for a service connection.

 void register_sap_agent(){
    sap_agent_h agent;
    int ret;
    ret = sap_agent_create(&agent);
    if(ret != SAP_RESULT_SUCCESS){
      dlog_print(DLOG_DEBUG, TAG, "Failed to create instance of sap Agent");
      return FALSE;
    }
    
    ret = sap_agent_initialize(agent, ASP_PROFILE_ID, SAP_AGENT_ROLE_CONSUMER, _on_sap_agent_initialized, NULL);
    if(ret != SAP_RESULT_SUCCESS){
      dlog_print(DLOG_DEBUG, TAG, "Failed to initialize sap agent.");
      return FALSE;
    }
 }
static void
_on_sap_agent_initialized(sap_agent_h agent_id, sap_agent_initialized_result_e result, void *user_data)
{
    int connected = 0;
    m_local_agent_id = agent_id;
    switch (result) {
    case SAP_AGENT_INITIALIZED_RESULT_SUCCESS:
        priv_data.agent_id = m_local_agent_id;
        dlog_print(DLOG_DEBUG, TAG,"adding sap_set_service_connection_cb, sap_connection status:%d", connected);
        sap_agent_set_service_connection_requested_cb(priv_data.agent_id sap_service_connection_requested_cb,
                                                      NULL);
        sap_peer_agent_set_service_connection_terminated_cb(priv_data.peer_agent,
                                                            sap_service_connection_terminated_cb, NULL);
        dlog_print(DLOG_DEBUG, TAG,"SAP_AGENT_INITIALIZED_RESULT_SUCCESS");
        g_idle_add(_find_peer_agent, &priv_data);
        break;
    case SAP_AGENT_INITIALIZED_RESULT_DUPLICATED:
        dlog_print(DLOG_ERROR, TAG, "duplicate registration");
        break;
    case SAP_AGENT_INITIALIZED_RESULT_INVALID_ARGUMENTS:
        dlog_print(DLOG_ERROR, TAG, "invalid arguments");
        break;
    case SAP_AGENT_INITIALIZED_RESULT_INTERNAL_ERROR:
        dlog_print(DLOG_ERROR, TAG, "internal sap error");
        break;
    default:
        dlog_print(DLOG_ERROR, TAG, "unknown status (%d)", status);
        break;
    }
}



Finding a Matching Peer Agent and Initiating a Service Connection

To create a service connection with a matching peer agent:

  1. The service provider or consumer application can search for matching accessory peer agents available for making a service connection by calling the sap_agent_find_peer_agent() function.

    The accessory peer agents match if they are of the same accessory service profile (such as Notification service or Weather service) and have a complementary provider-consumer relation with the calling accessory peer agent. (Accessory peer agents of different accessory service profiles, 2 service providers, or 2 service consumers, are not "matching" and cannot be connected with each other.) The accessory peer agents implementing a different accessory service profile version can be considered as "matching" (for example, a Notification service consumer implementing the Notification service profile version 2.0 and a Notification service provider implementing the Notification service profile version 1.0 are "matching").

    static gboolean
    _find_peer_agent(gpointer user_data)
    {
        struct priv *priv = NULL;
        sap_result_e result = SAP_RESULT_FAILURE;
    
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        priv = (struct priv *)user_data;
    
        if (priv->agent_id == 0) {
            dlog_print(DLOG_ERROR, TAG, "service agent is not registered");
    
            return FALSE;
        }
        result = sap_agent_find_peer_agent(priv->agent_id, sap_peer_agent_updated_cb, NULL);
    
        if (result == SAP_RESULT_SUCCESS)
            dlog_print(DLOG_ERROR, TAG, "findsap_peer_agent_s (agent_id:%d) succeeded", priv->agent_id);
        else
            dlog_print(DLOG_DEBUG, TAG, "findsap_peer_agent_s is failed (%d)", result);
    
        return FALSE;
    }
    
  2. If a matching accessory peer agent is found, the calling accessory peer agent is notified through the previously registered sap_peer_agent_updated_cb() callback. If multiple matching accessory peer agents are found, the callback occurs multiple times, once for each found match. If your application wants to make a service connection with only 1 accessory peer agent, check whether the first callback is acceptable.
    void
    sap_peer_agent_updated_cb(sap_peer_agent_h peer_agent, sap_peer_agent_status_e peer_status,
                              sap_peer_agent_found_result_e result, void *user_data)
    {
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        switch (peer_status) {
        case SAP_PEER_AGENT_FOUND_RESULT_FOUND:
            _free_peer_agent(&priv_data.peer_agent);
            priv_data.peer_agent = _dup_peer_agent(peer_agent);
            request_service_connection();
            break;
        case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED:
            dlog_print(DLOG_DEBUG, TAG, "device not connected");
            g_timeout_add(1000, _find_peer_agent, &priv_data);
            break;
        case SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND:
            dlog_print(DLOG_DEBUG, TAG, "service not found");
            break;
        case SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT:
            dlog_print(DLOG_DEBUG, TAG, "peer agent find timed out");
            break;
        case SAP_PEER_AGENT_FOUND_RESULT_END:
            dlog_print(DLOG_DEBUG, TAG, "peer agent find end");
            break;
        default:
            dlog_print(DLOG_DEBUG, TAG, "unknown status (%d)", peer_status);
            break;
        }
    }
    
  3. You can check the identity or properties of the found accessory peer agent by using the members of sap_peer_agent_s structure, such as the vendor ID or application name, to decide whether to request a service connection with that particular accessory peer agent. To initiate a service connection with an accessory peer agent, call the sap_agent_request_service_connection() function.
    static gboolean
    _create_service_connection(gpointer user_data)
    {
        struct priv *priv = NULL;
        sap_result_e result = SAP_RESULT_FAILURE;
    
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        priv = (struct priv *)user_data;
    
        if (priv->agent_id == 0) {
            dlog_print(DLOG_ERROR, TAG, "service agent is not registered");
    
            return FALSE;
        }
    
        if(sap_peer_agent_is_feature_enabled(priv->peer_agent, SAP_FEATURE_SOCKET) == FALSE){
            dlog_print(DLOG_DEBUG, TAG, "peer agent does not support Service connection feature");
            return FALSE;
        }
    
    result = sap_agent_request_service_connection(priv->agent_id, priv->peer_agent,
                                                  sap_service_connection_established_cb, NULL);
    
        if (result == SAP_RESULT_SUCCESS)
            dlog_print(DLOG_DEBUG, TAG, "sap_request_service_connection succeeded");
        else
            dlog_print(DLOG_ERROR, TAG, "sap_request_service_connection is failed (%d)", result);
    
        return FALSE;
    }
    
  4. The remote accessory peer agent for which you request a service connection can accept or reject your request. Your application is notified through the sap_service_connection_established_cb() callback, which was registered initially in the sap_agent_request_service_connection() function. The result of your request can be request accepted and service connection established, request rejected, or a failure to establish a service connection for other reasons.

    When the connection is successfully established, the requesting accessory peer agent gets a socket, which can be used to send data to and receive data from the connected accessory peer agent, as well as handle service connection-related events. Once the service connection is established, you can send data to a remote accessory peer agent, or launch a UI to realize use cases related to the specific accessory service.

    To receive data on the socket from the remote accessory peer agent, the sap_socket_data_received_cb() callback must be registered through the sap_socket_set_data_received_cb() function.

    static void
    sap_service_connection_established_cb(sap_peer_agent_h peer_agent, sap_socket_h socket,
                                          sap_service_connection_result_e result, void *user_data);
    {
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        switch (result) {
        case SAP_CONNECTION_SUCCESS:
            dlog_print(DLOG_DEBUG, TAG, "connection success");
            priv_data. socket = socket;
            sap_socket_send_data ("hello world sap");
            break;
        case SAP_CONNECTION_ALREADY_EXIST:
            dlog_print(DLOG_DEBUG, TAG, "connection is already exist");
            priv_data. socket = socket;
            break;
        case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE:
            dlog_print(DLOG_DEBUG, TAG, "device is not unreachable");
            break;
        case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT:
            dlog_print(DLOG_DEBUG, TAG, "invalid peer agent");
            break;
        case SAP_CONNECTION_FAILURE_NETWORK:
            dlog_print(DLOG_DEBUG, TAG, "network failure");
            break;
        case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE:
            dlog_print(DLOG_DEBUG, TAG, "peer agent is no response");
            break;
        case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED:
            dlog_print(DLOG_DEBUG, TAG, "peer agent is rejected");
            break;
        case SAP_CONNECTION_PEER_AGENT_NOT_SUPPORTED:
            dlog_print(DLOG_DEBUG, TAG, "peer agent does not support service connection feature");
            break;
        }
    
        sap_socket_set_data_received_cb(sap_socket_data_received_cb, NULL);
    }
    



Handling Service Connection Requests from Remote Accessory Peer Agents

The service provider or consumer application is notified when a remote accessory peer agent wants to create a service connection with it. The notification comes through the sap_service_connection_requested_cb() callback, which was registered in the sap_peer_agent_updated_cb() function. The accessory peer agent application can choose to accept or reject the service connection request by calling the sap_peer_agent_accept_service_connection() or sap_peer_agent_reject_service_connection() function.

The sap_service_connection_requested_cb() callback can check for accessory peer agent-specific information using the sap_peer_agent_s structure. It can check for, for example, application name or vendor ID, before accepting or rejecting the request.

static void
sap_service_connection_requested_cb(sap_agent_h agent, sap_peer_agent_h peer_agent,
                                    sap_socket_h socket, sap_service_connection_result_e result,
                                    void *user_data)
{
    sap_peer_agent_accept_service_connection(agent_id, service_handle, peer_agent);
}



Exchanging Data with Accessory Peer Agents

The service consumer or provider can send data to its connected accessory peer agent by calling the sap_socket_send_data() function, which is passed by the sap_service_connection_established_cb() callback. The function sends data on a selected service channel inside the established service connection. The Samsung Accessory Service Framework provides a datagram service, in which either all data or nothing is sent. In case of an error, an exception is thrown. The service connection encapsulates all service channels as necessitated by the Accessory Service Profile Protocol specification.

gboolean
send_data(char *message)
{
    int result;
    if (priv_data.service_handle) {
        dlog_print(DLOG_DEBUG, TAG, "sending data");
        result = sap_socket_send_data (priv_data.service_handle, 104, strlen(message), message);
    }
}

If sending fails, it can be due to insufficient buffer space. In such cases, the Samsung Accessory Service Framework returns a failure, and the sap_socket_ready_to_send_cb() callback is triggered once buffer space becomes available. At this point, you can resend the data.

When data is received from a remote accessory peer agent, your application is notified through the sap_socket_data_received_cb() callback. This callback can be set initially after the service connection is created by using the sap_set_on_data_receive_cb() function.

static void
sap_socket_data_received_cb(unsigned int service_handle, unsigned short int channel_id,
                            unsigned int length, void *buffer, void *user_data)
{
    dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
    dlog_print(DLOG_DEBUG, TAG, "received data: %s", buffer);
    sap_socket_send_data ("ACK");
}



Disconnecting and Handling Errors

The service consumer or provider can call the sap_peer_agent_terminate_service_connection() function to terminate the service connection with a remote accessory peer agent. Similarly, if a remote accessory peer agent calls this function to terminate the service connection, your application is notified through the sap_service_connection_terminated_cb() callback, and all established service channels of the service connection are closed by the Samsung Accessory Service Framework.

Other reasons, such as network failure, or 2 devices going out of range while on a wireless connection, can also result in a service connection loss. Your service provider or consumer application is expected to implement handling mechanisms in the callback for such cases.

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)
{
    dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
    switch (status) {
    case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED:
        dlog_print(DLOG_DEBUG, TAG, "disconnected because peer lost");
        break;
    case SAP_CONNECTION_TERMINATED_REASON_DEVICE_DETACHED:
        dlog_print(DLOG_DEBUG, TAG, "disconnected because device is detached");
        break;
    case SAP_CONNECTION_TERMINATED_REASON_UNKNOWN:
        dlog_print(DLOG_DEBUG, TAG, "disconnected because of unknown reason");
        break;
    }
}



Transferring Files

The Samsung Accessory File Transfer service uses a utility file transfer application to transfer user files from one device to another. The file is transferred on a separate service connection and the user's application may or may not have an existing service connection to use the file transfer service.

The sender application needs to know the peer that it wants to send the file to. Generally, the file sender is regarded as a "file provider" and the file receiver is regarded as the "file consumer".

Relevant APIs for File Transfer

The callbacks that you receive for FT are as below. The members are part of sap_ft.h. .

sap_ft_set_recieve_file_request_cb - This callback is hit when you receive a file sending request from the other side

sap_ft_set_on_transfer_done_cb - This callback is hit when sending has been completed.

sap_ft_set_on_transfer_progress_cb - This callback is used to show the amount of file that has already been sent by the app.



The following functions are used for file transfer:

sap_ft_send_file - This is used to send an image or text file.

sap_ft_receive_file - This is used to receive a file. This can be called when pFDefOnSendFile is called.

sap_ft_push_file - The function pushFile is called by app, which has multiple profile implementations in a single app.

sap_ft_cancel_file_operation - The function cancelFile is called by app to cancel the file transfer.



Creating a File Sender

To create an application that sends files:

  1. Register callbacks in the following form after registering a service agent:
    /* Triggered when sending has been completed */
    sap_ft_set_on_transfer_done_cb(_on_send_receive_completed, NULL);
    /* Show the amount of file content that has already been sent by the application */
    sap_ft_set_on_transfer_progress_cb(_on_sending_file_in_progress, NULL);
    /* Triggered when you receive a file sending request from the other side */
    sap_ft_set_recieve_file_request_cb(_on_send_file, NULL);
    
  2. To send a file, you must know the peer agent you want to send the file to. Obtain a peer agent by calling the sap_find_peer_agents() function, and then send the file with the sap_ft_send_file() function.
    priv_data.peer_agent = _dup_peer_agent(peer_agent);
    sap_ft_send_file("/media/file.txt", priv_data.peer_agent);
    

    The provided filename must be fully qualified for the path. You can supply a content or data URI as well. The data must be stored in a publicly visible location, such as /media/file.txt. The Accessory SDK cannot access files residing in an internal application storage. A unique transaction ID is returned to the application, and you must maintain it for future reference.

  3. During the course of the file transfer, progress updates are provided in the _on_sending_file_in_progress() callback. The application can update a progress bar in the UI based on the progress value received in the callback.
    static void
    _on_sending_file_in_progress(int dwTransactionId, unsigned short int uwProgress,
                                 unsigned int ulAgentId, void* user_data)
    {
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        dlog_print(DLOG_DEBUG, TAG, "on_file_progress: Trans:%d, Progress:%d\n", dwTransactionId, uwProgress);
    }
    
  4. When the file transfer is completed, in both successful and unsuccessful cases, the _on_send_receive_completed() callback is called with the appropriate error values. The application can match the error codes with the error fields declared in the sap_type.h header file. The sender can cancel the file transfer at any time by calling the sap_ft_cancel_file_operation() function.
    static void
    _on_send_receive_completed(int ulTransactionId, char *pFilePath, unsigned short int ulResult,
                               unsigned int ulAgentId, void* user_data)
    {
        dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
        dlog_print(DLOG_DEBUG, TAG, "_on_send_receive_completed: Trans:%d, File:%s, result:%d\n", ulTransactionId, pFilePath, ulResult);
    }
    



Creating a File Receiver

The file receiver application is triggered when a file transfer request is received. The receiver application must register itself for the file transfer service use in order to receive any incoming file transfer request notifications. This means that on the receiver side, the application is bound to the file transfer service as long the application wants to receive incoming file transfer notifications.

The receiver application must register the same callbacks as the file sending application, for the file transfer request and receiving files:

  • The incoming file transfer request is provided in the _on_send_file() callback. At this point, the application can inform the user through a notification or pop-up about the incoming file transfer and ask for permission to accept or reject the incoming file transfer request.
  • To receive the file, the application must call the sap_ft_receive_file() function.

    The file destination path where the received file is stored has to be a publicly available location and also a fully qualified path. The application encounters an error, in case it supplies an invalid file path or an invalid transaction ID.

static void
_on_send_file(int ulTransactionId, char *pFilePath, unsigned int ulAgentId, void* user_data)
{
    int ret = 0;
    dlog_print(DLOG_DEBUG, TAG, "%s", __func__);
    ret = sap_ft_receive_file(ulTransactionId,"/media/file.txt", 1);
    if (ret != 0)
        dlog_print(DLOG_DEBUG, TAG, "receiveFile() failed with error:%d\n", ret);
}

The sender starts sending data only after the sap_ft_receive_file() function is called. When the file transfer is complete, either successfully or unsuccessfully, the _on_send_receive_completed() callback is called with the requisite error code. The application can match the error code received with those defined in the sap_type.h header file to know the exact cause of the error. If the file transfer is successful, the error code is 0.

The application can cancel the file transfer at any time by calling the sap_ft_cancel_file_operation() function with a correct transaction ID. In the case of the file transfer cancellation, the _on_receive_completed() callback is called with a proper error code.



Exchanging Messages

The Samsung Accessory Message Exchange Protocol service allows sending data without need of any service connection (it enables sessionless transfers). The application must provide the message feature description in the accessory XML file, and the sender application must know the peer to whom the message needs to be sent. After the message is sent, the sender receives an acknowledgment with the message delivery status.

The Samsung Accessory Message Exchange Protocol service internally uses a reserved channel for data transfers.

Relevant APIs for Message Exchange

The callbacks that you receive for Message are as below. The members are part of sap_message_exchange.h.

sap_agent_data_received_cb - This callback is hit when data is received on Message channel.

sap_agent_set_data_received_cb – Register a callback so as to receive data over Message channel.

sap_peer_agent_message_delivery_status_cb - This callback is hit in the following cases: 1)Peer has received the data 2)Peer app is not available to receive data 3)Delivery timed out due to network problem.



The following function is used to check if the Message feature is enabled on both sides. The API’s are part of sap.h

sap_peer_agent_is_feature_enabled – This api checks whether the remote application has the Message feature enabled.



The following function is used for Sending Message. It is part of sap_message_exchange.h

sap_peer_agent_send_data – This api can be used to send messages using Message protocol service. This api will return a unique transaction id, the same will be reflected back in sap_peer_agent_message_delivery_status_cb callback.

Add the <supportedFeatures> element in the accessory XML file

<resources>
    <application name="HelloMessageConsumer">
        <serviceProfile id="/sample/hellomessage"
                        name="hellomessage_consumer"
                        role="consumer"
                        version="1.0">
            <supportedTransports>
                <transport type="TRANSPORT_BT"/>
            </supportedTransports>
            <supportedFeatures>
                <feature type="message"/>
            </supportedFeatures>
        </serviceProfile>
    </application>
</resources>



Find Peer

To send data, the application must know the peer agent it wants to send data to.

Obtain the agent by calling the sap_agent_find_peer_agent() function defined in the sap.h header file:

If a matching accessory peer agent is found, the calling accessory peer agent is notified through the previously registered sap_peer_agent_updated_cb() callback. If multiple matching accessory peer agents are found, the callback occurs multiple times, once for each found match.

void
on_peer_agent_updated(sap_peer_agent_h peer_agent, sap_peer_agent_status_e status,
                      sap_peer_agent_found_result_e result,
                      void *user_data) /* Find peer result callback (sap_peer_agent_updated_cb) */

{
    if (result == SAP_PEER_AGENT_FOUND_RESULT_FOUND) {
        if (status == SAP_PEER_AGENT_STATUS_AVAILABLE)
            g_peer_agent_h = peer_agent;
    }
}

void
message_app_find_peers()
{
    /*
       SAP API to find peer agents
       sap_agent_h handle must be received from sap_agent_initialized_cb() callback
       by calling the sap_agent_initialize() function
    */
    sap_agent_find_peer_agent(g_agent_handle, on_peer_agent_updated, NULL);
}



Send Messages

To send messages using the message exchange protocol service, use the sap_peer_agent_send_data() function.

Before sending the message, use the following functions to check whether the message exchange feature is enabled on both sides. The functions are part of the sap.h.

  • sap_peer_agent_is_feature_enabled(): Check whether the remote application has message exchange feature enabled.
  • sap_peer_agent_send_data(): This function returns a unique transaction ID, which can be maintained for future reference. The same transaction ID is reflected back in the sap_peer_agent_message_delivery_status_cb() callback along with the status of the message delivery.
  • sap_peer_agent_message_delivery_status_cb: Triggered when the remote peer has received the data. It is also triggered in error cases, if the peer application is not available to receive data, or delivery timed out due to a network problem.
#define ENCRYPT_DATA_ENABLED 1
void
message_app_send_data(char *msg, unsinged int length)
{
    int transaction_id;
    if (sap_peer_agent_is_feature_enabled(gp_agent, SAP_FEATURE_MESSAGE)) {
            transaction _id = sap_peer_agent_send_data(g_peer_agent_h, msg, length, ENCRYPT_DATA_ENABLED,
                                                       on_message_delivery_status_cb, NULL);
            if (transaction_id < 0) {
                switch (transaction_id) {
                case SAP_CONNECTIONLESS_TRANSFER_NOT_SUPPORTED:
                    dlog_print(DLOG_ERROR, TAG, "message exchange feature not supported in current SAP framework");
                    break;
                case SAP_CONNECTIONLESS_TRANSFER_INVALID_PARAMETERS:
                    dlog_print(DLOG_ERROR, TAG, "Invalid parameters provided");
                    break;
                case SAP_CONNECTIONLESS_TRANSFER_MAX_REQUEST_LIMIT_REACHED:
                    dlog_print(DLOG_ERROR, TAG, "Maximum Send message req limit reached. Retry sending data");
                    break;
                case SAP_CONNECTIONLESS_TRANSFER_IO_ERROR:
                    dlog_print(DLOG_ERROR, TAG, "SAP message framework I/O error.");
                    break;
                case SAP_CONNECTIONLESS_TRANSFER_EXCEEDED_MAX_APDU_LEN:
                    dlog_print(DLOG_ERROR, TAG, "Send Message failed because Payload length exceeds 2MB.");
                    break;
                case SAP_CONNECTIONLESS_TRANSFER_INVALID_PEER_AGENT_HANDLE:
                    dlog_print(DLOG_ERROR, TAG, "wrong peer agent handle provided");
                    break;
                }
            }
    } else {
            dlog_print(DLOG_ERROR, TAG, "message exchange is not supported by the Peer framework");
            /* Fallback to socket connection */
    }
}
void
on_message_delivery_status_cb(sap_peer_agent_h peer_agent_h, int transaction_id,
                          sap_connectionless_transfer_status_e status, void *user_data)
{
    if (status == SAP_CONNECTION_LESS_TRANSFER_ERROR_NONE) {
        dlog_print(DLOG_DEBUG, TAG, "message was sent successfully, transaction:%d", transaction_id);
    } else {
        switch(status) {
        case SAP_CONNECTIONLESS_TRANSFER_PEER_APP_ERROR:
            dlog_print(DLOG_ERROR, TAG, "Peer App is not available to receive data. Retry");
            break;
        case SAP_CONNECTIONLESS_TRANSFER_NETWORK_ERROR:
            dlog_print(DLOG_ERROR, TAG, "Network is slow or busy.");
            break;
        case SAP_CONNECTIONLESS_TRANSFER_FRAMEWORK_INTERNAL_ERROR:
            dlog_print(DLOG_ERROR, TAG, "SAP message framework internal error. Retry sending data");
            break;
        case SAP_CONNECTIONLESS_TRANSFER_UNKNOWN_ERROR:
            dlog_print(DLOG_ERROR, TAG, "SAP message framework unknown error. Retry sending data.");
            break;
        }
    }
}
Note
The maximum data that can be sent over a message exchange channel is limited to 2 MB for BT and TCP connectivities and 1 MB for BLE connectivity.
The message exchange feature has been enabled for tizen versions starting from 2.3.2. It is not currently supported for the Tizen mobile platform.



Receive Messages From Remote Peers

Define the following callbacks for message exchange. The members are part of the sap_message_exchange.h.

  • sap_agent_data_received_cb: Triggered when data is received on a message exchange channel.
  • sap_agent_set_data_received_cb: Triggered to receive data over a message exchange channel.
    void
    on_message_received(sap_peer_agent_h peer_agent, unsigned int payload_length, void *buffer,
                    void *user_data) /* message exchange on_receive callback (sap_agent_data_received_cb) */
    {
        char *msg = (char*)g_new0(payload_length + 1);
        char *peer_app;
        sap_peer_agent_get_app_name(peer_agent, &peer_app);
        memcpy(msg, buffer, payload_length);
        dlog_print(DLOG_DEBUG, TAG, "Data received is %s from peer:%s", msg, peer_app);
        g_free(peer_app);
        g_free(msg);
    }
    
    void
    message_app_set_on_data_receive()
    {
        /* message exchange API to set the on receive data callback */
        sap_agent_set_data_received_cb(priv.agent, on_message_received, NULL);
    }
    


  • Message Exchange Sequence Flow

    The following figure illustrates the message exchange function sequence flow.

    Figure: Message exchange function sequence flow

    Message exchange function sequence flow

Go to top