NFC TNEP Connection Handover
The NFC TNEP Connection Handover service handles the exchange of Connection Handover Messages between an NFC Forum Tag and an NFC Forum Poller device. It uses the TNEP protocol in the Single Response Communication mode to exchange the handover messages between:
NFC Tag Device (see TNEP for tag device)
NFC Poller Device (see TNEP for polling device)
The Connection Handover Service name URI for the service announced in the Service Parameter record is urn:nfc:sn:handover
.
Handover protocol
The Connection Handover Protocol enables two NFC Forum devices to negotiate a shared set of alternative (non-NFC) communication carriers. The Handover Requester Device is the NFC Forum Device that initiates the handover negotiation. The Handover Selector Device is the NFC Forum Device that is initially passive and responds to the Handover Requester.
Static handover
In the static handover, the Handover Requester only reads a Handover Select Message from the NFC Tag Device. TNEP is not used in this communication form.
Negotiated handover
In the negotiated handover, the Handover Requester provides a Handover Request Message that contains its set of supported carriers to the Handover Selector. The Handover Selector replies with a Handover Select Message that contains the list of carriers that they both support. Connection Handover NDEF messages are exchanged as defined by TNEP.
Device Role
The role of the NFC Poller Device depends on the NFC Tag Device. If the NFC Tag Device takes the role of the Handover Requester, it responds to the Service Select with a Handover Request Message. This message includes a TNEP status record. The NFC Poller Device responds with the Handover Select Message after having received the Handover Request Message.
If the NFC Tag Device takes the role of the Handover Selector, then the NFC Tag Device does not add any NDEF records defined in this specification into the TNEP status message. The TNEP status message follows the Service Select message and the NFC Tag Device waits for a Handover Request Message from the NFC Poller Device.
The NFC Tag Device role is defined by callback sets in structure nfc_tnep_ch_cb
passed to nfc_tnep_ch_service_init()
.
Handover Selector role. Set
request_msg_recv
.Handover Requester role. Set
request_msg_prepare
andselect_msg_recv
.
NFC Tag Device
The following code sample demonstrates how to use this module with an NFC Tag Device:
static int carrier_prepare(void)
{
static struct nfc_ndef_le_oob_rec_payload_desc rec_payload;
NFC_NDEF_LE_OOB_RECORD_DESC_DEF(oob_rec, '0', &rec_payload);
NFC_NDEF_CH_AC_RECORD_DESC_DEF(oob_ac, NFC_AC_CPS_ACTIVE, 1, "0", 0);
memset(&rec_payload, 0, sizeof(rec_payload));
rec_payload.addr = &oob_local.addr;
rec_payload.le_sc_data = &oob_local.le_sc_data;
rec_payload.tk_value = tk_value;
rec_payload.local_name = bt_get_name();
rec_payload.le_role = NFC_NDEF_LE_OOB_REC_LE_ROLE(
NFC_NDEF_LE_OOB_REC_LE_ROLE_PERIPH_ONLY);
rec_payload.appearance = NFC_NDEF_LE_OOB_REC_APPEARANCE(
CONFIG_BT_DEVICE_APPEARANCE);
rec_payload.flags = NFC_NDEF_LE_OOB_REC_FLAGS(BT_LE_AD_NO_BREDR);
return nfc_tnep_ch_carrier_set(&NFC_NDEF_CH_AC_RECORD_DESC(oob_ac),
&NFC_NDEF_LE_OOB_RECORD_DESC(oob_rec),
1);
}
#if defined(CONFIG_NFC_TAG_CH_REQUESTER)
static int tnep_ch_request_prepare(void)
{
bt_le_adv_stop();
return carrier_prepare();
}
static int tnep_ch_select_received(const struct nfc_tnep_ch_record *ch_select,
bool inactive)
{
int err;
const struct nfc_ndef_record_desc *oob_data = NULL;
if (!ch_select->count) {
return -EINVAL;
}
/* All alternative carrier are inactive */
if (inactive) {
/* Try send request again. */
return carrier_prepare();
}
err = check_oob_carrier(ch_select, &oob_data);
if (err) {
return err;
}
err = oob_le_data_handle(oob_data, false);
if (err) {
return err;
}
return 0;
}
#endif /* defined(CONFIG_NFC_TAG_CH_REQUESTER) */
static int tnep_ch_request_received(const struct nfc_tnep_ch_request *ch_req)
{
int err;
const struct nfc_ndef_record_desc *oob_data = NULL;
if (!ch_req->ch_record.count) {
return -EINVAL;
}
err = check_oob_carrier(&ch_req->ch_record, &oob_data);
if (err) {
return err;
}
bt_le_adv_stop();
err = oob_le_data_handle(oob_data, true);
if (err) {
return err;
}
return carrier_prepare();
}
static struct nfc_tnep_ch_cb ch_cb = {
#if defined(CONFIG_NFC_TAG_CH_REQUESTER)
.request_msg_prepare = tnep_ch_request_prepare,
.select_msg_recv = tnep_ch_select_received,
#endif
.request_msg_recv = tnep_ch_request_received
};
This library is used in the Bluetooth: NFC pairing sample.
NFC Poller Device
The following code sample demonstrates how to use this module with an NFC Poller Device:
static int carrier_prepare(void)
{
static struct nfc_ndef_le_oob_rec_payload_desc rec_payload;
NFC_NDEF_LE_OOB_RECORD_DESC_DEF(oob_rec, '0', &rec_payload);
NFC_NDEF_CH_AC_RECORD_DESC_DEF(oob_ac, NFC_AC_CPS_ACTIVE, 1, "0", 0);
memset(&rec_payload, 0, sizeof(rec_payload));
rec_payload.addr = &oob_local.addr;
rec_payload.le_sc_data = &oob_local.le_sc_data;
rec_payload.tk_value = tk_value;
rec_payload.local_name = bt_get_name();
rec_payload.le_role = NFC_NDEF_LE_OOB_REC_LE_ROLE(
NFC_NDEF_LE_OOB_REC_LE_ROLE_CENTRAL_ONLY);
rec_payload.appearance = NFC_NDEF_LE_OOB_REC_APPEARANCE(
CONFIG_BT_DEVICE_APPEARANCE);
rec_payload.flags = NFC_NDEF_LE_OOB_REC_FLAGS(BT_LE_AD_NO_BREDR);
return nfc_tnep_ch_carrier_set(&NFC_NDEF_CH_AC_RECORD_DESC(oob_ac),
&NFC_NDEF_LE_OOB_RECORD_DESC(oob_rec),
1);
}
static int tnep_ch_request_prepare(void)
{
return carrier_prepare();
}
static int tnep_ch_select_received(const struct nfc_tnep_ch_record *ch_select,
bool inactive)
{
int err;
const struct nfc_ndef_record_desc *oob_data = NULL;
if (!ch_select->count) {
return -EINVAL;
}
/* All alternative carrier are inactive */
if (inactive) {
/* Try send request again. */
return carrier_prepare();
}
err = check_oob_carrier(ch_select, &oob_data);
if (err) {
return err;
}
err = oob_le_data_handle(oob_data, false);
if (err) {
return err;
}
return 0;
}
static int tnep_ch_request_received(const struct nfc_tnep_ch_request *ch_req)
{
int err;
const struct nfc_ndef_record_desc *oob_data = NULL;
if (!ch_req->ch_record.count) {
return -EINVAL;
}
err = check_oob_carrier(&ch_req->ch_record, &oob_data);
if (err) {
return err;
}
err = oob_le_data_handle(oob_data, true);
if (err) {
return err;
}
return carrier_prepare();
}
static struct nfc_tnep_ch_cb ch_cb = {
.request_msg_prepare = tnep_ch_request_prepare,
.select_msg_recv = tnep_ch_select_received,
.request_msg_recv = tnep_ch_request_received
};
This library is used in the Bluetooth: Central NFC pairing sample.
API documentation
include/nfc/tnep/ch.h
subsys/nfc/tnep/ch/
- group nfc_tnep_ch
NFC Connection Handover TNEP service API.
Defines
-
NFC_TNEP_CH_URI_LENGTH
NFC Connection Handover service URI name length.
Functions
-
int nfc_tnep_ch_service_init(struct nfc_tnep_ch_cb *cb)
Initialize the TNEP Connection Handover service.
- Parameters
cb – [in] Callback structure.
- Return values
0 – If the operation was successful. Otherwise, a (negative) error code is returned.
-
int nfc_tnep_ch_carrier_set(struct nfc_ndef_record_desc *ac_rec, struct nfc_ndef_record_desc *carrier_rec, size_t count)
Set Connection Handover carriers.
Function for setting the Connection Handover carriers. It should be used in the callback from nfc_tnep_ch_cb when the Application should reply to the Connection Handover Message. The type of message is determined automatically based on the received message and the role of the device in the data exchange.
- Parameters
ac_rec – [in] Array of the Alternative Carrier Records.
carrier_rec – [in] Array of the Carrier Records.
count – [in] Count of the Alternative Carrier Records and the Carrier Records.
- Return values
0 – If the operation was successful. Otherwise, a (negative) error code is returned.
-
const struct nfc_ndef_tnep_rec_svc_param *nfc_tnep_ch_svc_search(const struct nfc_ndef_tnep_rec_svc_param *services, size_t cnt)
Helper function for searching the Connection Handover service in the Initial NDEF Message.
- Parameters
services – [in] Array of the TNEP services.
cnt – [in] Services count.
- Returns
Pointer to the Connection Handover service. NULL if service is not found.
Variables
-
const uint8_t nfc_tnep_ch_svc_uri[19]
NFC Connection Handover service URI.
-
struct nfc_tnep_ch_record
- #include <ch.h>
Connection Handover Record structure.
Public Members
-
const struct nfc_ndef_ch_ac_rec *ac
Pointer to the first Alternative Carrier Record.
-
const struct nfc_ndef_record_desc **carrier
Pointer to the first Carrier Record.
-
size_t count
Count of the Alternative Carriers Records and Carrier Records.
-
uint8_t major_ver
Connection Handover major version.
-
uint8_t minor_ver
Connection Handover minor version.
-
const struct nfc_ndef_ch_ac_rec *ac
-
struct nfc_tnep_ch_request
- #include <ch.h>
Connection Handover Request Record strucure.
Public Members
-
const struct nfc_ndef_ch_cr_rec *cr
Pointer to the Collision Resolution Record data.
-
struct nfc_tnep_ch_record ch_record
Connection Handover Record data.
-
const struct nfc_ndef_ch_cr_rec *cr
-
struct nfc_tnep_ch_cb
- #include <ch.h>
Connection Handover service callback structure.
Public Members
-
int (*request_msg_prepare)(void)
The Connection Handover Request Message prepare callback.
This callback is called every time when the NFC Forum Device takes the Connection Handover Requester role and the Connection Handover Message must be sent to the other NFC Forum Device.
- Retval 0
If the operation was successful. Otherwise, a (negative) error code is returned.
-
int (*request_msg_recv)(const struct nfc_tnep_ch_request *ch_req)
The Connection Handover Request Message received callback.
This callback is called always when NFC Forum Device which supports TNEP received the Connection Handover Request Message. After receiving this message, application shall respond with the Handover Select Message by calling nfc_tnep_ch_carrier_set.
- Param ch_req
[in] Pointer to the Connection Handover Request structure which contains the parsed Connection Handover Request Message.
- Retval 0
If the operation was successful. Otherwise, a (negative) error code is returned.
-
int (*select_msg_recv)(const struct nfc_tnep_ch_record *ch_select, bool inactive)
The Connection Handover Select Message received callback.
This callback is called always when the NFC Device receive the Connection Select Message in response to the Connection Handover Request message.
- Param ch_select
[in] Pointer to Connection Handover structure which contains the parsed Connection Handover Select Message.
- Param inactive
[in] Indicates that all Alternative Carriers are inactive. The Handover Request Message should be sent again with only one Alternative Carrier using nfc_tnep_ch_carrier_set.
- Retval 0
If the operation was successful. Otherwise, a (negative) error code is returned.
-
int (*mediation_req_recv)(void)
The Connection Handover Mediation Request Message received callback.
This callback is called when an NFC Forum Tag Device that supports TNEP receives a Connection Handover Request Message that contains, in a Handover Carrier Record, the information for a single alternative carrier of NFC Forum Well Known type “Hm”. After receiving this message, the application shall respond with the Handover Mediation Message by calling nfc_tnep_ch_carrier_set.
- Retval 0
If the operation was successful. Otherwise, a (negative) error code is returned.
-
int (*initial_msg_recv)(const struct nfc_tnep_ch_record *ch_initial)
The Connection Handover Initial Message received callback.
This callback is called always when NFC Forum Tag Device which supports TNEP receives the Connection Handover Initial Message. After receiving this message, application shall respond also with the Handover Initial Message by calling nfc_tnep_ch_carrier_set.
- Param ch_initial
[in] Pointer to Connection Handover structure which contains the parsed Connection Handover Initial Message.
- Retval 0
If the operation was successful. Otherwise, a (negative) error code is returned.
-
void (*error)(int err)
Error callback.
Called always when internal error was detected.
- Param err
[in] Detected error code.
-
int (*request_msg_prepare)(void)
-
NFC_TNEP_CH_URI_LENGTH