Skip to content

Commit

Permalink
Merge pull request #2407 from fanoush/f-nfc-ndef-record-over-254
Browse files Browse the repository at this point in the history
allow NDEF records with length over 254 bytes
  • Loading branch information
gfwilliams authored Aug 30, 2023
2 parents 01193e5 + c73ab40 commit 032fbc2
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 95 deletions.
44 changes: 28 additions & 16 deletions libs/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,27 +316,39 @@ void jsble_setup_advdata(ble_advdata_t *advdata);

#define TAG_HEADER_LEN 0x0A

#define NDEF_HEADER "\x00\x00\x00\x00" /* | UID/BCC | TT = Tag Type */ \
"\x00\x00\x00\x00" /* | UID/BCC | ML = NDEF Message Length */ \
"\x00\x00\xFF\xFF" /* | UID/BCC | LOCK | TF = TNF and Flags */ \
"\xE1\x11\x7C\x0F" /* | Cap. Container | TL = Type Legnth */ \
"\x03\x00\xC1\x01" /* | TT | ML | TF | TL | RT = Record Type */ \
"\x00\x00\x00\x00" /* | Payload Length | IC = URI Identifier Code */ \
"\x55\x00" /* | RT | IC | Payload | 0x00: No prepending */

#define NDEF_FULL_RAW_HEADER_LEN 0x12 /* full header until ML */
#define NDEF_FULL_URL_HEADER_LEN 0x1A /* full header until IC */

#define NDEF_RECORD_HEADER_LEN 0x08 /* record header (TF, TL, PL, RT, IC ) */
#define NDEF_IC_OFFSET 0x19
/*
TT = Tag Type
ML = NDEF Message Length
RT = Record Type
TF = TNF and Flags
TL = Type Legnth
IC = URI Identifier Code
*/

#define NDEF_HEADER "\x00\x00\x00\x00" /* | UID/BCC | */ \
"\x00\x00\x00\x00" /* | UID/BCC | */ \
"\x00\x00\xFF\xFF" /* | UID/BCC | LOCK | */ \
"\xE1\x11\x7C\x0F" /* | Cap. Container | */ \
"\x03\x00\x00\x00" /* | TT | ML (1 or 3 bytes)| */

#define NDEF_HEADER_LEN_SHORT 0x12 /* with 1 byte length */
#define NDEF_HEADER_LEN_LONG 0x14 /* with 3 byte length */
#define NDEF_HEADER_MSG_LEN_OFFSET 0x11

#define NDEF_URL_RECORD_HEADER \
"\xC1\x01" /* | TF | TL | */ \
"\x00\x00\x00\x00" /* | Payload Length | */ \
"\x55\x00" /* | RT | IC | 0x00: No prepending */

#define NDEF_URL_RECORD_HEADER_LEN 0x08 /* record header (TF, TL, PL, RT, IC ) */
#define NDEF_IC_LEN 0x01

#define NDEF_MSG_LEN_OFFSET 0x11
#define NDEF_PL_LEN_LSB_OFFSET 0x17 /* we support pl < 256 */
#define NDEF_MSG_IC_OFFSET 7
#define NDEF_MSG_PL_LEN_MSB_OFFSET 4

#define NDEF_TERM_TLV 0xfe /* last TLV block / byte */
#define NDEF_TERM_TLV_LEN 0x01

#define NDEF_TAG2_VALUE_MAXLEN (992 - 4 - NDEF_TERM_TLV_LEN) /* max NDEF data size for 0x7C size in cap. container (*8=992)*/
void jsble_nfc_stop();
void jsble_nfc_start(const uint8_t *data, size_t len);
void jsble_nfc_get_internal(uint8_t *data, size_t *max_len);
Expand Down
139 changes: 60 additions & 79 deletions libs/bluetooth/jswrap_bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,51 @@ void jswrap_ble_setLowPowerConnection(bool lowPower) {
}
}

#ifdef USE_NFC
static void nfc_raw_data_start(uint8_t *dataPtr, size_t dataLen){
/* Create a flat string - we need this to store the NFC data so it hangs around.
* Avoid having a static var so we have RAM available if not using NFC.
* NFC data is read by nfc_callback in bluetooth.c */
bool isLongMsg = dataLen > 254;
size_t nfcDataLen = dataLen + NDEF_TERM_TLV_LEN + (isLongMsg ? NDEF_HEADER_LEN_LONG : NDEF_HEADER_LEN_SHORT);


JsVar *flatStr = jsvNewFlatStringOfLength(nfcDataLen);
if (!flatStr)
return jsExceptionHere(JSET_ERROR, "Unable to create string with NFC data in");
jsvObjectSetChild(execInfo.hiddenRoot, "NfcData", flatStr);
uint8_t *flatStrPtr = (uint8_t*)jsvGetFlatStringPointer(flatStr);
jsvUnLock(flatStr);

/* assemble NDEF Message */
memcpy(flatStrPtr, NDEF_HEADER, NDEF_HEADER_LEN_LONG); /* fill header */
/* inject tag2 message length into header */
if (isLongMsg){
flatStrPtr[NDEF_HEADER_MSG_LEN_OFFSET] = 255;
flatStrPtr[NDEF_HEADER_MSG_LEN_OFFSET+1] = dataLen >> 8;
flatStrPtr[NDEF_HEADER_MSG_LEN_OFFSET+2] = dataLen & 255;
} else {
flatStrPtr[NDEF_HEADER_MSG_LEN_OFFSET] = dataLen;
}

/* add NDEF message record header after NDEF header */
uint8_t *ndefMsgPtr = flatStrPtr + (isLongMsg ? NDEF_HEADER_LEN_LONG : NDEF_HEADER_LEN_SHORT);
memcpy(ndefMsgPtr, dataPtr, dataLen); /* add payload */


/* write terminator TLV block */
flatStrPtr[nfcDataLen - NDEF_TERM_TLV_LEN] = NDEF_TERM_TLV;

/* start nfc peripheral */
JsVar* uid = jswrap_nfc_start(NULL);

/* inject UID/BCC */
size_t len;
char *uidPtr = jsvGetDataPointer(uid, &len);
if(uidPtr) memcpy(flatStrPtr, uidPtr, TAG_HEADER_LEN);
jsvUnLock(uid);
}
#endif

/*JSON{
"type" : "staticmethod",
Expand Down Expand Up @@ -2437,36 +2482,21 @@ void jswrap_nfc_URL(JsVar *url) {
uriType = NFC_URI_HTTPS;
}

/* Encode NDEF message into a flat string - we need this to store the
* data so it hangs around. Avoid having a static var so we have RAM
* available if not using NFC. NFC data is read by nfc_callback */
JsVar *flatStr = jsvNewFlatStringOfLength(NDEF_FULL_URL_HEADER_LEN + urlLen + NDEF_TERM_TLV_LEN);
if (!flatStr)
return jsExceptionHere(JSET_ERROR, "Unable to create string with URI data in");
jsvObjectSetChild(execInfo.hiddenRoot, "NfcData", flatStr);
uint8_t *flatStrPtr = (uint8_t*)jsvGetFlatStringPointer(flatStr);
jsvUnLock(flatStr);
uint16_t msgLen = NDEF_URL_RECORD_HEADER_LEN + urlLen;
if (msgLen>NDEF_TAG2_VALUE_MAXLEN)
return jsExceptionHere(JSET_ERROR, "URL too long");

/* assemble NDEF Message */
memcpy(flatStrPtr, NDEF_HEADER, NDEF_FULL_URL_HEADER_LEN); /* fill header */
flatStrPtr[NDEF_IC_OFFSET] = uriType; /* set URI Identifier Code */
memcpy(flatStrPtr+NDEF_FULL_URL_HEADER_LEN, urlPtr, urlLen); /* add payload */
uint8_t *ndefMsgPtr = alloca(urlLen+NDEF_URL_RECORD_HEADER_LEN);
memcpy(ndefMsgPtr, NDEF_URL_RECORD_HEADER, NDEF_URL_RECORD_HEADER_LEN); /* fill header */

/* inject length fields into header */
flatStrPtr[NDEF_MSG_LEN_OFFSET] = NDEF_RECORD_HEADER_LEN + urlLen;
flatStrPtr[NDEF_PL_LEN_LSB_OFFSET] = NDEF_IC_LEN + urlLen;
ndefMsgPtr[NDEF_MSG_IC_OFFSET] = uriType; /* set URI Identifier Code */
memcpy(ndefMsgPtr+NDEF_URL_RECORD_HEADER_LEN, urlPtr, urlLen); /* add payload */

/* write terminator TLV block */
flatStrPtr[NDEF_FULL_URL_HEADER_LEN + urlLen] = NDEF_TERM_TLV;

/* start nfc peripheral */
JsVar* uid = jswrap_nfc_start(NULL);
/* put 16 bit (big endian) payload length into record header */
ndefMsgPtr[NDEF_MSG_PL_LEN_MSB_OFFSET] = (NDEF_IC_LEN + urlLen)>>8;
ndefMsgPtr[NDEF_MSG_PL_LEN_MSB_OFFSET+1] = (NDEF_IC_LEN + urlLen)&255;

/* inject UID/BCC */
size_t len;
char *uidPtr = jsvGetDataPointer(uid, &len);
if(uidPtr) memcpy(flatStrPtr, uidPtr, TAG_HEADER_LEN);
jsvUnLock(uid);
nfc_raw_data_start(ndefMsgPtr, urlLen+NDEF_URL_RECORD_HEADER_LEN);
#endif
}

Expand Down Expand Up @@ -2516,18 +2546,8 @@ void jswrap_nfc_pair(JsVar *key) {
&ndef_msg_len);
if (jsble_check_error(err_code)) return;

/* Encode NDEF message into a flat string - we need this to store the
* data so it hangs around. Avoid having a static var so we have RAM
* available if not using NFC. NFC data is read by nfc_callback */
nfc_raw_data_start(buf, ndef_msg_len);

JsVar *flatStr = jsvNewFlatStringOfLength(ndef_msg_len);
if (!flatStr)
return jsExceptionHere(JSET_ERROR, "Unable to create string with pairing data in");
uint8_t *flatStrPtr = (uint8_t*)jsvGetFlatStringPointer(flatStr);
memcpy(flatStrPtr, buf, ndef_msg_len);

jswrap_nfc_raw(flatStr);
jsvUnLock(flatStr);
#endif
}

Expand Down Expand Up @@ -2575,18 +2595,7 @@ void jswrap_nfc_androidApp(JsVar *appName) {
&ndef_msg_len);
if (jsble_check_error(err_code)) return;

/* Encode NDEF message into a flat string - we need this to store the
* data so it hangs around. Avoid having a static var so we have RAM
* available if not using NFC. NFC data is read by nfc_callback */

JsVar *flatStr = jsvNewFlatStringOfLength(ndef_msg_len);
if (!flatStr)
return jsExceptionHere(JSET_ERROR, "Unable to create string with pairing data in");
uint8_t *flatStrPtr = (uint8_t*)jsvGetFlatStringPointer(flatStr);
memcpy(flatStrPtr, buf, ndef_msg_len);

jswrap_nfc_raw(flatStr);
jsvUnLock(flatStr);
nfc_raw_data_start(buf, ndef_msg_len);
#endif
}

Expand Down Expand Up @@ -2617,41 +2626,13 @@ void jswrap_nfc_raw(JsVar *payload) {
}

JSV_GET_AS_CHAR_ARRAY(dataPtr, dataLen, payload);
if (!dataPtr || !dataLen)
if (!dataPtr || !dataLen || dataLen>NDEF_TAG2_VALUE_MAXLEN)
return jsExceptionHere(JSET_ERROR, "Unable to get NFC data");

/* Create a flat string - we need this to store the NFC data so it hangs around.
* Avoid having a static var so we have RAM available if not using NFC.
* NFC data is read by nfc_callback in bluetooth.c */
JsVar *flatStr = jsvNewFlatStringOfLength(NDEF_FULL_RAW_HEADER_LEN + dataLen + NDEF_TERM_TLV_LEN);
if (!flatStr)
return jsExceptionHere(JSET_ERROR, "Unable to create string with NFC data in");
jsvObjectSetChild(execInfo.hiddenRoot, "NfcData", flatStr);
uint8_t *flatStrPtr = (uint8_t*)jsvGetFlatStringPointer(flatStr);
jsvUnLock(flatStr);

/* assemble NDEF Message */
memcpy(flatStrPtr, NDEF_HEADER, NDEF_FULL_RAW_HEADER_LEN); /* fill header */
memcpy(flatStrPtr+NDEF_FULL_RAW_HEADER_LEN, dataPtr, dataLen); /* add payload */

/* inject length fields into header */
flatStrPtr[NDEF_MSG_LEN_OFFSET] = dataLen;

/* write terminator TLV block */
flatStrPtr[NDEF_FULL_RAW_HEADER_LEN + dataLen] = NDEF_TERM_TLV;

/* start nfc peripheral */
JsVar* uid = jswrap_nfc_start(NULL);

/* inject UID/BCC */
size_t len;
char *uidPtr = jsvGetDataPointer(uid, &len);
if(uidPtr) memcpy(flatStrPtr, uidPtr, TAG_HEADER_LEN);
jsvUnLock(uid);
nfc_raw_data_start((uint8_t*)dataPtr, dataLen);
#endif
}


/*JSON{
"type" : "staticmethod",
"class" : "NRF",
Expand Down

0 comments on commit 032fbc2

Please sign in to comment.