ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_nrf5_sdk15_communication_nfc.c
Go to the documentation of this file.
1
10#if RUUVI_NRF5_SDK15_NFC_ENABLED
11
12#include "ruuvi_driver_error.h"
15#include "ruuvi_interface_log.h"
16#include <stdint.h>
17
18#include "nfc_t4t_lib.h"
19#include "nfc_ndef_msg.h"
20#include "nfc_uri_rec.h"
21#include "nfc_text_rec.h"
22#include "nfc_launchapp_rec.h"
23#include "nfc_ndef_msg_parser.h"
24
25#define RUUVI_NRF5_SDK15_COMM_NFC_MAX_RECORDS 4
26#define BIN_PAY_DESC_HEADER_LEN 3U
27
28static struct
29{
30 volatile uint8_t connected; // NFC field is active
31 uint8_t initialized;
32 volatile uint8_t rx_updated; // New data received
33 volatile uint8_t tx_updated; // New data should be written to buffer
34 volatile uint8_t configurable; // Allow NFC to write configuration
35 uint8_t nfc_ndef_msg[ (RUUVI_NRF5_SDK15_COMM_NFC_MAX_RECORDS + 1)
37 volatile size_t nfc_ndef_msg_len;
38 uint8_t desc_buf[NFC_NDEF_PARSER_REQIRED_MEMO_SIZE_CALC (
39 RUUVI_NRF5_SDK15_COMM_NFC_MAX_RECORDS)]; // Buffer to contain incoming data descriptors
40 size_t msg_index; // Store index of our record
41 ri_comm_evt_handler_fp_t * on_nfc_evt;
42} nrf5_sdk15_nfc_state;
43
47static void nfc_callback (void * context,
48 nfc_t4t_event_t event,
49 const uint8_t * data,
50 size_t dataLength,
51 uint32_t flags)
52{
53 (void) context;
54
55 switch (event)
56 {
57 case NFC_T4T_EVENT_FIELD_ON:
58 if (NULL != * (nrf5_sdk15_nfc_state.on_nfc_evt)
59 && false == nrf5_sdk15_nfc_state.connected)
60 {
61 (* (nrf5_sdk15_nfc_state.on_nfc_evt)) (RI_COMM_CONNECTED, NULL, 0);
62 }
63
64 nrf5_sdk15_nfc_state.connected = true;
65 break;
66
67 case NFC_T4T_EVENT_FIELD_OFF:
68 if (NULL != * (nrf5_sdk15_nfc_state.on_nfc_evt) && true == nrf5_sdk15_nfc_state.connected)
69 {
70 (* (nrf5_sdk15_nfc_state.on_nfc_evt)) (RI_COMM_DISCONNECTED, NULL,
71 0);
72 }
73
74 nrf5_sdk15_nfc_state.connected = false;
75 break;
76
77 case NFC_T4T_EVENT_NDEF_READ:
78 if (NULL != * (nrf5_sdk15_nfc_state.on_nfc_evt)) { (* (nrf5_sdk15_nfc_state.on_nfc_evt)) (RI_COMM_SENT, NULL, 0); }
79
80 break;
81
82 // Update process generally sets length of field to 0 and
83 // then updates. Once done, length is updated again.
84 case NFC_T4T_EVENT_NDEF_UPDATED:
85 if (dataLength > 0)
86 {
87 nrf5_sdk15_nfc_state.nfc_ndef_msg_len = dataLength;
88 nrf5_sdk15_nfc_state.rx_updated = true;
89
90 // If tag is not configurable by NFC, set flag to overwrite received data.
91 if (!nrf5_sdk15_nfc_state.configurable) { nrf5_sdk15_nfc_state.tx_updated = true;}
92
93 // Do not process data in interrupt context, you should rather schedule data processing. Note: If incoming data is long, it might exceed max size.
94 if (NULL != * (nrf5_sdk15_nfc_state.on_nfc_evt)) { (* (nrf5_sdk15_nfc_state.on_nfc_evt)) (RI_COMM_RECEIVED, nrf5_sdk15_nfc_state.nfc_ndef_msg, dataLength); }
95 }
96
97 break;
98
99 default:
100 break;
101 }
102}
103
104NFC_NDEF_MSG_DEF (nfc_ndef_msg,
105 RUUVI_NRF5_SDK15_COMM_NFC_MAX_RECORDS); // max NFC_MAX_NUMBER_OF_RECORDS records
106
107// Setup constant records
108static uint8_t nfc_fw_buf[RI_COMM_DIS_STRLEN];
109static size_t nfc_fw_length = 0;
110static uint8_t nfc_addr_buf[RI_COMM_DIS_STRLEN];
111static size_t nfc_addr_length = 0;
112static uint8_t nfc_id_buf[RI_COMM_DIS_STRLEN];
113static size_t nfc_id_length = 0;
114static uint8_t nfc_tx_buf[RI_COMM_DIS_STRLEN];
115static size_t nfc_tx_length = 0;
116
118{
119 if (NULL == channel) { return RD_ERROR_NULL; }
120
121 if (nrf5_sdk15_nfc_state.initialized) { return RD_ERROR_INVALID_STATE; }
122
123 // Set up NFC
124 ret_code_t err_code = NRF_SUCCESS;
125 // Allow invalid state here as setup will return invalid state on reinit.
126 err_code |= nfc_t4t_setup (nfc_callback, NULL);
127
128 if (NRF_ERROR_INVALID_STATE == err_code)
129 {
130 err_code = NRF_SUCCESS;
131 }
132
133 memset (nrf5_sdk15_nfc_state.nfc_ndef_msg, 0, sizeof (nrf5_sdk15_nfc_state.nfc_ndef_msg));
134 // Run Read-Write mode for Type 4 Tag platform
135 err_code |= nfc_t4t_ndef_rwpayload_set (nrf5_sdk15_nfc_state.nfc_ndef_msg,
136 sizeof (nrf5_sdk15_nfc_state.nfc_ndef_msg));
137 // Setup communication abstraction fps
138 channel->init = ri_nfc_init;
139 channel->uninit = ri_nfc_uninit;
140 channel->read = ri_nfc_receive;
141 channel->send = ri_nfc_send;
142 channel->on_evt = NULL;
143 nrf5_sdk15_nfc_state.on_nfc_evt = & (channel->on_evt);
144 // Start sensing NFC field
145 err_code |= nfc_t4t_emulation_start();
146 nrf5_sdk15_nfc_state.initialized = true;
147 nrf5_sdk15_nfc_state.msg_index = 0;
148 return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
149}
150
152{
153 ret_code_t err_code = nfc_t4t_emulation_stop();
154 err_code |= nfc_t4t_done();
155 memset (&nrf5_sdk15_nfc_state, 0, sizeof (nrf5_sdk15_nfc_state));
156 memset (channel, 0, sizeof (ri_comm_channel_t));
157 return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
158}
159
161{
162 // State check
163 if (!nrf5_sdk15_nfc_state.initialized) { return RD_ERROR_INVALID_STATE; }
164
165 if (nrf5_sdk15_nfc_state.connected) { return RD_ERROR_INVALID_STATE; }
166
167 // Return success if there is nothing to do
168 if (! (nrf5_sdk15_nfc_state.tx_updated)) { return RD_SUCCESS; }
169
170 // Create NFC NDEF text record description in English
171 ret_code_t err_code = NRF_SUCCESS;
172 uint8_t fw_code[] = RI_NFC_SW_FIELD_CODE;
173 NFC_NDEF_TEXT_RECORD_DESC_DEF (nfc_fw_rec,
174 UTF_8,
175 fw_code,
176 sizeof (fw_code),
177 nfc_fw_buf,
178 nfc_fw_length);
179 uint8_t addr_code[] = RI_NFC_ADDR_FIELD_CODE;
180 NFC_NDEF_TEXT_RECORD_DESC_DEF (nfc_addr_rec,
181 UTF_8,
182 addr_code,
183 sizeof (addr_code),
184 nfc_addr_buf,
185 nfc_addr_length);
186 uint8_t id_code[] = RI_NFC_ID_FIELD_CODE;
187 NFC_NDEF_TEXT_RECORD_DESC_DEF (nfc_id_rec,
188 UTF_8,
189 id_code,
190 sizeof (id_code),
191 nfc_id_buf,
192 nfc_id_length);
193 uint8_t data_code[] = RI_NFC_DATA_FIELD_CODE;
194 NFC_NDEF_TEXT_RECORD_DESC_DEF (nfc_bin_rec, \
195 UTF_8, \
196 data_code, sizeof (data_code), \
197 nfc_tx_buf, \
198 nfc_tx_length);
199 // Clear our record
200 nfc_ndef_msg_clear (&NFC_NDEF_MSG (nfc_ndef_msg));
201
202 // Add new records if applicable
203 if (nfc_id_length)
204 {
205 err_code |= nfc_ndef_msg_record_add (&NFC_NDEF_MSG (nfc_ndef_msg),
206 &NFC_NDEF_TEXT_RECORD_DESC (nfc_id_rec));
207 }
208
209 if (nfc_addr_length)
210 {
211 err_code |= nfc_ndef_msg_record_add (&NFC_NDEF_MSG (nfc_ndef_msg),
212 &NFC_NDEF_TEXT_RECORD_DESC (nfc_addr_rec));
213 }
214
215 if (nfc_fw_length)
216 {
217 err_code |= nfc_ndef_msg_record_add (&NFC_NDEF_MSG (nfc_ndef_msg),
218 &NFC_NDEF_TEXT_RECORD_DESC (nfc_fw_rec));
219 }
220
221 if (nfc_tx_length)
222 {
223 err_code |= nfc_ndef_msg_record_add (&NFC_NDEF_MSG (nfc_ndef_msg),
224 &NFC_NDEF_TEXT_RECORD_DESC (nfc_bin_rec));
225 }
226
227 // Encode data to NFC buffer. NFC will transmit the buffer, i.e. data is updated immediately.
228 err_code |= nfc_t4t_emulation_stop();
229 uint32_t msg_len = sizeof (nrf5_sdk15_nfc_state.nfc_ndef_msg);
230 err_code |= nfc_ndef_msg_encode (&NFC_NDEF_MSG (nfc_ndef_msg),
231 nrf5_sdk15_nfc_state.nfc_ndef_msg,
232 &msg_len);
233 err_code |= nfc_t4t_ndef_rwpayload_set (nrf5_sdk15_nfc_state.nfc_ndef_msg,
234 sizeof (nrf5_sdk15_nfc_state.nfc_ndef_msg));
235 err_code |= nfc_t4t_emulation_start();
236 // TX Data processed, set update status to false
237 nrf5_sdk15_nfc_state.tx_updated = false;
238 return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
239}
240
242{
243 if (NULL == message) { return RD_ERROR_NULL; }
244
245 if (message->data_length >= RI_COMM_DIS_STRLEN) { return RD_ERROR_INVALID_LENGTH; }
246
247 nfc_tx_length = message->data_length;
248 memcpy (nfc_tx_buf, message->data, nfc_tx_length);
249 nrf5_sdk15_nfc_state.tx_updated = true;
250 return ri_nfc_data_set();
251}
252
253rd_status_t ri_nfc_fw_version_set (const uint8_t * const version, const uint8_t length)
254{
255 if (NULL == version && length) { return RD_ERROR_NULL; }
256
257 if (length >= RI_COMM_DIS_STRLEN) { return RD_ERROR_INVALID_LENGTH; }
258
259 nfc_fw_length = length;
260 memcpy (nfc_fw_buf, version, nfc_fw_length);
261 nrf5_sdk15_nfc_state.tx_updated = true;
262 return RD_SUCCESS;
263}
264
265rd_status_t ri_nfc_address_set (const uint8_t * const address, const uint8_t length)
266{
267 if (NULL == address && length) { return RD_ERROR_NULL; }
268
269 if (length >= RI_COMM_DIS_STRLEN) { return RD_ERROR_INVALID_LENGTH; }
270
271 nfc_addr_length = length;
272 memcpy (nfc_addr_buf, address, nfc_addr_length);
273 nrf5_sdk15_nfc_state.tx_updated = true;
274 return RD_SUCCESS;
275}
276
277rd_status_t ri_nfc_id_set (const uint8_t * const id,
278 const uint8_t length)
279{
280 if (NULL == id && length) { return RD_ERROR_NULL; }
281
282 if (length >= RI_COMM_DIS_STRLEN) { return RD_ERROR_INVALID_LENGTH; }
283
284 nfc_id_length = length;
285 memcpy (nfc_id_buf, id, nfc_id_length);
286 nrf5_sdk15_nfc_state.tx_updated = true;
287 return RD_SUCCESS;
288}
289
290/* Read and parse RX buffer into records. Parse records into Ruuvi Communication messages.
291 * Restore original data after last record has been parsed
292 *
293 * parameter msg: Ruuvi Communication message, received record payload is copied into message payload field.
294 *
295 * Return RD_STATUS_MORE_AVAILABLE if payload was parsed into msg and more data is available
296 * Return RD_SUCCESS if payload was parsed into msg and no more data is available
297 * Return RD_ERROR_NOT_FOUND if no data was buffered and message could not be parsed.
298 * Return RD_ERROR_DATA_SIZE if received message could not fit into message payload
299 */
301{
302 // Input check
303 //ruuvi_platform_log("Getting message, state check");
304 if (NULL == msg) { return RD_ERROR_NULL; }
305
306 // State check. Do not process data while connection is active, i.e. while
307 // data might be received.
308 // if ( nrf5_sdk15_nfc_state.connected) { return RD_ERROR_INVALID_STATE; }
309 // If new data is not received, return not found
310 if (!nrf5_sdk15_nfc_state.rx_updated) { return RD_ERROR_NOT_FOUND; }
311
312 rd_status_t err_code = RD_SUCCESS;
313
314 // If we're at index 0, parse message into records
315 if (0 == nrf5_sdk15_nfc_state.msg_index)
316 {
317 uint32_t desc_buf_len = sizeof (nrf5_sdk15_nfc_state.desc_buf);
318 uint32_t data_lenu32 = sizeof (
319 nrf5_sdk15_nfc_state.nfc_ndef_msg); // Skip NFCT4T length bytes?
320 err_code = ndef_msg_parser (nrf5_sdk15_nfc_state.desc_buf,
321 &desc_buf_len,
322 nrf5_sdk15_nfc_state.nfc_ndef_msg + 2, // Skip NFCT4T length bytes
323 &data_lenu32);
324 // PLATFORM_LOG_INFO("Found %d messages", ((nfc_ndef_msg_desc_t*)desc_buf)->record_count);
325 // ndef_msg_printout((nfc_ndef_msg_desc_t*) nrf5_sdk15_nfc_state.desc_buf);
326 }
327
328 // If there is a new message, parse the payload into Ruuvi Message.
329 if (nrf5_sdk15_nfc_state.msg_index < ( (nfc_ndef_msg_desc_t *)
330 nrf5_sdk15_nfc_state.desc_buf)->record_count)
331 {
332 // PLATFORM_LOG_INFO("Parsing message %d", msg_index);
333 nfc_ndef_record_desc_t * const p_rec_desc = ( (nfc_ndef_msg_desc_t *)
334 nrf5_sdk15_nfc_state.desc_buf)->pp_record[nrf5_sdk15_nfc_state.msg_index];
335 nfc_ndef_bin_payload_desc_t * p_bin_pay_desc = p_rec_desc->p_payload_descriptor;
336 // Data length check, skip header
337 size_t payload_len = (p_bin_pay_desc->payload_length - BIN_PAY_DESC_HEADER_LEN);
338
339 if (payload_len > msg->data_length)
340 {
341 err_code = RD_ERROR_DATA_SIZE;
342 }
343 else
344 {
345 memcpy (msg->data, ( (uint8_t *) p_bin_pay_desc->p_payload + BIN_PAY_DESC_HEADER_LEN),
346 payload_len);
347 msg->data_length = payload_len;
348 }
349
350 nrf5_sdk15_nfc_state.msg_index++;
351
352 if (RD_SUCCESS == err_code) { err_code = RD_STATUS_MORE_AVAILABLE; }
353 }
354
355 // If no more records could/can be parsed, reset buffer and message counter
356 if (RD_STATUS_MORE_AVAILABLE != err_code
357 || nrf5_sdk15_nfc_state.msg_index == ( (nfc_ndef_msg_desc_t *)
358 nrf5_sdk15_nfc_state.desc_buf)->record_count)
359 {
360 nrf5_sdk15_nfc_state.msg_index = 0;
361 nrf5_sdk15_nfc_state.rx_updated = false;
362
363 // If tag is not writeable, restore original data
364 if (nrf5_sdk15_nfc_state.configurable)
365 {
367 }
368 }
369
370 return err_code;
371}
372
373#endif
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
#define RD_ERROR_INVALID_LENGTH
Invalid Length.
#define RD_STATUS_MORE_AVAILABLE
Driver has more data queued.
rd_status_t ruuvi_nrf5_sdk15_to_ruuvi_error(const ret_code_t error)
convert nrf5 sdk15 error code into Ruuvi error code.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_DATA_SIZE
Invalid Data size.
#define RD_ERROR_NOT_FOUND
Not found.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
rd_status_t(* ri_comm_evt_handler_fp_t)(const ri_comm_evt_t evt, void *p_data, size_t data_len)
Application event handler for communication events.
#define RI_COMM_DIS_STRLEN
Maximum length for device information strings.
@ RI_COMM_CONNECTED
Connection established, OK to send, may receive data.
@ RI_COMM_RECEIVED
New data received, available to read with read function.
@ RI_COMM_SENT
One queued message was sent with all repetitions.
@ RI_COMM_DISCONNECTED
Connection lost, cannot send, may not receive data.
rd_status_t ri_nfc_address_set(const uint8_t *const address, const uint8_t length)
#define RI_NFC_DATA_FIELD_CODE
#define RI_NFC_ID_FIELD_CODE
#define RI_NFC_ADDR_FIELD_CODE
rd_status_t ri_nfc_init(ri_comm_channel_t *const channel)
rd_status_t ri_nfc_data_set(void)
rd_status_t ri_nfc_send(ri_comm_message_t *messge)
rd_status_t ri_nfc_fw_version_set(const uint8_t *const version, const uint8_t length)
rd_status_t ri_nfc_receive(ri_comm_message_t *messge)
rd_status_t ri_nfc_uninit(ri_comm_channel_t *const channel)
#define RI_NFC_SW_FIELD_CODE
rd_status_t ri_nfc_id_set(const uint8_t *const id, const uint8_t length)
control API for communication via outside world
ri_comm_evt_handler_fp_t on_evt
Callback to application-level event handler, must be set in application.
ri_comm_xfer_fp_t send
Asynchronous send function.
ri_comm_init_fp_t init
Initialize and populate channel api control.
ri_comm_init_fp_t uninit
Uninitialize and depopulate channel api control.
ri_comm_xfer_fp_t read
Asynchronous read function.
Application message structure used for communication.
uint8_t data[RI_COMM_MESSAGE_MAX_LENGTH]
Data payload.
uint8_t data_length
Length of data.