NFC API for mbed using the MicroNFCBoard as a peripheral

Dependents:   MicroNFCBoardAPI_P2P_Client MicroNFCBoardAPI_Blink MicroNFCBoardAPI_Tag_Emulator MicroNFCBoardAPI_Tag_Reader ... more

Files at this revision

API Documentation at this revision

Comitter:
AppNearMe
Date:
Fri Apr 24 12:57:23 2015 +0000
Child:
1:1d246e0872c6
Commit message:
Initial commit

Changed in this revision

micronfcboard.cpp Show annotated file Show diff for this revision Revisions of this file
micronfcboard.h Show annotated file Show diff for this revision Revisions of this file
transport.cpp Show annotated file Show diff for this revision Revisions of this file
transport.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/micronfcboard.cpp	Fri Apr 24 12:57:23 2015 +0000
@@ -0,0 +1,252 @@
+/**
+ * \file micronfcboard.cpp
+ * \copyright Copyright (c) AppNearMe Ltd 2015
+ * \author Donatien Garnier
+ */
+
+#include "micronfcboard.h"
+
+#define STATUS_POLLING          (1 << 0)
+#define STATUS_CONNECTED        (1 << 1)
+#define STATUS_NDEF_PRESENT     (1 << 2)
+#define STATUS_NDEF_READABLE    (1 << 3)
+#define STATUS_NDEF_WRITEABLE   (1 << 4)
+#define STATUS_NDEF_BUSY        (1 << 5)
+#define STATUS_NDEF_SUCCESS     (1 << 6)
+
+#define STATUS_TYPE_MASK        (0xFF << 8)
+#define STATUS_TYPE2            (2 << 8)
+#define STATUS_P2P              (8 << 8)
+
+#define RECORD_URI  1
+#define RECORD_TEXT 2
+#define RECORD_SP   3
+
+MicroNFCBoard::MicroNFCBoard(PinName mosi, PinName miso, PinName sck, PinName cs, PinName irq) : _transport(mosi, miso, sck, cs, irq)
+{
+
+}
+
+void MicroNFCBoard::init()
+{
+  _transport.init();
+  _status = _transport.status();
+}
+
+void MicroNFCBoard::setLeds(bool led1, bool led2)
+{
+  _transport.leds(led1, led2);
+}
+
+void MicroNFCBoard::updateStatus()
+{
+  if(_transport.statusChanged())
+  {
+    _status = _transport.status();
+  }
+}
+
+bool MicroNFCBoard::connected()
+{
+  updateStatus();
+  return _status & STATUS_CONNECTED;
+}
+
+bool MicroNFCBoard::type2()
+{
+  updateStatus();
+  return (_status & STATUS_TYPE_MASK) == STATUS_TYPE2;
+}
+
+bool MicroNFCBoard::p2p()
+{
+  updateStatus();
+  return (_status & STATUS_TYPE_MASK) == STATUS_P2P;
+}
+
+bool MicroNFCBoard::polling()
+{
+  updateStatus();
+  return _status & STATUS_POLLING;
+}
+
+bool MicroNFCBoard::ndefReadable()
+{
+  updateStatus();
+  return _status & STATUS_NDEF_READABLE;
+}
+
+bool MicroNFCBoard::ndefWriteable()
+{
+  updateStatus();
+  return _status & STATUS_NDEF_WRITEABLE;
+}
+
+bool MicroNFCBoard::ndefPresent()
+{
+  updateStatus();
+  return _status & STATUS_NDEF_PRESENT;
+}
+
+bool MicroNFCBoard::ndefBusy()
+{
+  updateStatus();
+  return _status & STATUS_NDEF_BUSY;
+}
+
+bool MicroNFCBoard::ndefSuccess()
+{
+  updateStatus();
+  return _status & STATUS_NDEF_SUCCESS;
+}
+
+void MicroNFCBoard::startPolling()
+{
+  _transport.nfcPoll(true);
+}
+
+void MicroNFCBoard::stopPolling()
+{
+  _transport.nfcPoll(false);
+}
+
+void MicroNFCBoard::ndefRead()
+{
+  _transport.nfcOperation(true, false);
+}
+
+void MicroNFCBoard::ndefWrite()
+{
+  _transport.nfcOperation(false, true);
+}
+
+bool MicroNFCBoard::readNdefUri(char* uri, size_t maxUriLength)
+{
+  if(!ndefPresent())
+  {
+    return false;
+  }
+
+  size_t recordCount = 0;
+  _transport.nfcGetMessageInfo(&recordCount);
+
+
+  size_t recordNumber = 0;
+  uint16_t info[4];
+  uint16_t type;
+  size_t infoCount = 4;
+
+  for(recordNumber = 0; recordNumber < recordCount; recordNumber++)
+  {
+    _transport.nfcGetRecordInfo(recordNumber, &type, info, infoCount);
+    if(type == RECORD_URI)
+    {
+      break;
+    }
+    if(type == RECORD_SP)
+    {
+      recordCount += info[1];
+    }
+  }
+  if(recordNumber == recordCount)
+  {
+    return false;
+  }
+
+  //Recover prefix
+  size_t length = maxUriLength - 1;
+  _transport.nfcDecodePrefix(info[0], uri, &length);
+
+  maxUriLength -= length;
+  uri += length;
+
+  if(maxUriLength <= 1)
+  {
+    return false;
+  }
+
+  length = info[1];
+  if(length > maxUriLength - 1)
+  {
+    return false;
+  }
+
+  size_t off = 0;
+  while(length > 0)
+  {
+    size_t cpyLength = length;
+    if(cpyLength > 32)
+    {
+      cpyLength = 32;
+    }
+    _transport.nfcGetRecordData(recordNumber, 0, off, (uint8_t*)uri, cpyLength);
+    length -= cpyLength;
+    off += cpyLength;
+    uri += cpyLength;
+  }
+
+  uri[0] = '\0';
+
+  return true;
+}
+
+bool MicroNFCBoard::readNdefText(char* text, size_t maxTextLength)
+{
+  if(!ndefPresent())
+  {
+    return false;
+  }
+
+  size_t recordCount = 0;
+  _transport.nfcGetMessageInfo(&recordCount);
+
+
+  size_t recordNumber = 0;
+  uint16_t info[4];
+  uint16_t type;
+  size_t infoCount = 4;
+
+  for(recordNumber = 0; recordNumber < recordCount; recordNumber++)
+  {
+    _transport.nfcGetRecordInfo(recordNumber, &type, info, infoCount);
+    if(type == RECORD_TEXT)
+    {
+      break;
+    }
+    if(type == RECORD_SP)
+    {
+      recordCount += info[1];
+    }
+  }
+  if(recordNumber == recordCount)
+  {
+    return false;
+  }
+
+  size_t length = info[2];
+  if(length > maxTextLength - 1)
+  {
+    return false;
+  }
+
+  size_t off = 0;
+  while(length > 0)
+  {
+    size_t cpyLength = length;
+    if(cpyLength > 32)
+    {
+      cpyLength = 32;
+    }
+    _transport.nfcGetRecordData(recordNumber, 1, off, (uint8_t*)text, cpyLength);
+    length -= cpyLength;
+    off += cpyLength;
+    text += cpyLength;
+  }
+
+  text[0] = '\0';
+
+  return true;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/micronfcboard.h	Fri Apr 24 12:57:23 2015 +0000
@@ -0,0 +1,66 @@
+/**
+ * \file micronfcboard.h
+ * \copyright Copyright (c) AppNearMe Ltd 2015
+ * \author Donatien Garnier
+ */
+#ifndef SRC_MICRONFCBOARD_H_
+#define SRC_MICRONFCBOARD_H_
+
+#include "mbed.h"
+#include <cstddef>
+
+#include "transport.h"
+
+class MicroNFCBoard
+{
+public:
+  MicroNFCBoard(PinName mosi, PinName miso, PinName sck, PinName cs, PinName irq);
+
+  void init();
+
+  void setLeds(bool led1, bool led2);
+
+  void updateStatus();
+
+  bool connected();
+
+  bool type2();
+
+  bool p2p();
+
+  bool polling();
+
+  bool ndefReadable();
+
+  bool ndefWriteable();
+
+  bool ndefPresent();
+
+  bool ndefBusy();
+
+  bool ndefSuccess();
+
+  void startPolling();
+
+  void stopPolling();
+
+  void ndefRead();
+
+  void ndefWrite();
+
+  bool readNdefUri(char* uri, size_t maxUriLength);
+
+  bool readNdefText(char* text, size_t maxTextLength);
+
+  void writeNdefUri(char* uri);
+
+  void writeNdefText(char* text);
+
+protected:
+  Transport _transport;
+
+private:
+  uint32_t _status;
+};
+
+#endif /* SRC_MICRONFCBOARD_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/transport.cpp	Fri Apr 24 12:57:23 2015 +0000
@@ -0,0 +1,260 @@
+/**
+ * \file transport.cpp
+ * \copyright Copyright (c) AppNearMe Ltd 2015
+ * \author Donatien Garnier
+ */
+
+#include "transport.h"
+
+
+//MSB first
+#define WRITE_UINT32( addr, val ) do{ *(((uint8_t*)(addr)) + 0) = ((val) >> 24 ) & 0xFF; \
+                                           *(((uint8_t*)(addr)) + 1) = ((val) >> 16 ) & 0xFF; \
+                                           *(((uint8_t*)(addr)) + 2) = ((val) >> 8 ) & 0xFF; \
+                                           *(((uint8_t*)(addr)) + 3) = ((val) >> 0 ) & 0xFF; } while(0)
+#define WRITE_UINT16( addr, val ) do{ *(((uint8_t*)(addr)) + 0) = ((val) >> 8 ) & 0xFF; \
+                                           *(((uint8_t*)(addr)) + 1) = ((val) >> 0 ) & 0xFF; } while(0)
+
+//MSB first
+#define READ_UINT32( addr, val ) do{ val = (*(((uint8_t*)(addr)) + 0) << 24 ) \
+                                              | (*(((uint8_t*)(addr)) + 1) << 16 ) \
+                                              | (*(((uint8_t*)(addr)) + 2) << 8 ) \
+                                              | (*(((uint8_t*)(addr)) + 3) << 0 ); } while(0)
+#define READ_UINT16( addr, val ) do{ val = (*(((uint8_t*)(addr)) + 0) << 8 ) \
+                                              | (*(((uint8_t*)(addr)) + 1) << 0 ); } while(0)
+
+
+Transport::Transport(PinName mosi, PinName miso, PinName sck, PinName cs, PinName irq) : \
+_cs(cs), _spi(mosi, miso, sck), _int(irq)
+{
+}
+
+void Transport::init()
+{
+  _spi.format(8, 1);
+  _spi.frequency(100000);
+  _cs = 1;
+
+  for(int i = 0; i < 64; i++)
+  {
+    _cs = 0;
+    _spi.write(0);
+    _cs = 1;
+  }
+}
+
+void Transport::reset()
+{
+  uint8_t out[] = {0};
+  command(Transport::RESET, out, sizeof(out), NULL, 0);
+}
+
+bool Transport::statusChanged()
+{
+  return (_int.read() != 0);
+}
+
+uint32_t Transport::status()
+{
+  uint8_t in[4];
+  command(Transport::GET_STATUS, NULL, 0, in, sizeof(in));
+
+  uint32_t status;
+  READ_UINT32(&in[0], status);
+  return status;
+}
+
+void Transport::nfcPoll(bool enable)
+{
+  uint8_t out[] = {enable?1:0};
+  command(Transport::NFC_POLL, out, sizeof(out), NULL, 0);
+}
+
+void Transport::nfcOperation(bool readOp, bool writeOp)
+{
+  uint8_t out[1];
+  if(readOp)
+  {
+    out[0] = 1;
+  }
+  else if(writeOp)
+  {
+    out[0] = 2;
+  }
+  else
+  {
+    out[0] = 0;
+  }
+  command(Transport::NFC_OPERATION, out, sizeof(out), NULL, 0);
+}
+
+void Transport::nfcGetInfoIsoA(uint8_t* atqa, uint8_t* sak, uint8_t* uid, size_t* pUidLength)
+{
+  uint8_t in[2 + 1 + 1 + 10];
+  command(Transport::NFC_GET_INFO, NULL, 0, in, sizeof(in));
+  memcpy(atqa, &in[0], 2);
+  *sak = in[2];
+  *pUidLength = in[3];
+  memcpy(uid, &in[4], *pUidLength);
+}
+
+void Transport::nfcGetMessageInfo(size_t* pRecordCount)
+{
+  uint8_t in[2];
+  command(Transport::NFC_GET_MESSAGE_INFO, NULL, 0, in, sizeof(in));
+  READ_UINT16(&in[0], *pRecordCount);
+}
+
+void Transport::nfcSetMessageInfo(size_t recordCount)
+{
+  uint8_t out[2];
+  WRITE_UINT16(&out[0], recordCount);
+  command(Transport::NFC_SET_MESSAGE_INFO, out, sizeof(out), NULL, 0);
+}
+
+void Transport::nfcGetRecordInfo(size_t recordNumber, uint16_t* pType, uint16_t* info, size_t infoCount)
+{
+  uint8_t out[2];
+  uint8_t in[2+2*infoCount];
+  WRITE_UINT16(&out[0], recordNumber);
+  command(Transport::NFC_GET_RECORD_INFO, out, sizeof(out), in, sizeof(in));
+  READ_UINT16(&in[0], *pType);
+  for(int i = 0; i < infoCount; i++)
+  {
+    READ_UINT16(&in[2+2*i], info[i]);
+  }
+}
+
+void Transport::nfcSetRecordInfo(size_t recordNumber, uint16_t type, uint16_t* info, size_t infoCount)
+{
+  uint8_t out[2+2+2*infoCount];
+  WRITE_UINT16(&out[0], recordNumber);
+  WRITE_UINT16(&out[2], type);
+  for(int i = 0; i < infoCount; i++)
+  {
+    WRITE_UINT16(&out[2+2+2*i], info[i]);
+  }
+  command(Transport::NFC_SET_RECORD_INFO, out, sizeof(out), NULL, 0);
+}
+
+void Transport::nfcGetRecordData(size_t recordNumber, size_t item, size_t offset, uint8_t* data, size_t length)
+{
+  uint8_t out[7];
+  WRITE_UINT16(&out[0], recordNumber);
+  out[2] = item;
+  WRITE_UINT16(&out[3], offset);
+  WRITE_UINT16(&out[5], length);
+  command(Transport::NFC_GET_RECORD_DATA, out, sizeof(out), data, length);
+}
+
+void Transport::nfcSetRecordData(size_t recordNumber, size_t item, size_t offset, uint8_t* data, size_t length)
+{
+  uint8_t out[7+length];
+  WRITE_UINT16(&out[0], recordNumber);
+  out[2] = item;
+  WRITE_UINT16(&out[3], offset);
+  WRITE_UINT16(&out[5], length);
+  memcpy(&out[7], data, length);
+  command(Transport::NFC_SET_RECORD_DATA, out, sizeof(out), NULL, 0);
+}
+
+void Transport::nfcPrepareMessage(bool lock, bool generate)
+{
+  uint8_t out[1];
+  if(lock)
+  {
+    out[0] = 1;
+  }
+  else if(generate)
+  {
+    out[0] = 2;
+  }
+  else
+  {
+    out[0] = 0;
+  }
+  command(Transport::NFC_POLL, out, sizeof(out), NULL, 0);
+}
+
+void Transport::nfcDecodePrefix(uint8_t prefix, char* data, size_t* pDataLength)
+{
+  uint8_t out[] = { prefix };
+  uint8_t in[2 + 36]; //max prefix length is 36
+  command(Transport::NFC_DECODE_PREFIX, out, sizeof(out), in, sizeof(in));
+  size_t length;
+  READ_UINT16(&in[0], length);
+  if(length < *pDataLength)
+  {
+    *pDataLength = length;
+  }
+  memcpy(data, &in[2], *pDataLength);
+}
+
+void Transport::nfcEncodePrefix(uint8_t* pPrefix, char* data, size_t dataLength)
+{
+  uint8_t out[2 + dataLength];
+  uint8_t in[1];
+
+  WRITE_UINT16(&out[0], dataLength);
+  memcpy(data, &out[2], dataLength);
+
+  command(Transport::NFC_ENCODE_PREFIX, out, sizeof(out), in, sizeof(in));
+
+  *pPrefix = in[0];
+}
+
+void Transport::leds(bool led1, bool led2)
+{
+  uint8_t out[] = {led1?1:0, led2?1:0};
+  command(Transport::LEDS, out, sizeof(out), NULL, 0);
+}
+
+Transport::CommandError Transport::command(Transport::CommandCode command, uint8_t* outBuf, size_t outLength, uint8_t* inBuf, size_t inLength)
+{
+  _cs = 0;
+  _spi.write((uint8_t)((outLength + 1) & 0xFF));
+  _cs = 1;
+  _cs = 0;
+  _spi.write((uint8_t)(command & 0xFF));
+  _cs = 1;
+  for(int i = 0; i < outLength; i++)
+  {
+    _cs = 0;
+    _spi.write(outBuf[i]);
+    _cs = 1;
+  }
+
+  size_t length = 0;
+  while(length == 0)
+  {
+    _cs = 0;
+    length = _spi.write(0);
+    _cs = 1;
+  }
+
+  _cs = 0;
+  Transport::CommandCode retCmd = (Transport::CommandCode)_spi.write(0);
+  length--;
+  _cs = 1;
+
+  _cs = 0;
+  Transport::CommandError ret = (Transport::CommandError)_spi.write(0);
+  length--;
+  _cs = 1;
+
+  for(int i = 0; i < length; i++)
+  {
+    _cs = 0;
+    if(i < inLength)
+    {
+      inBuf[i] = _spi.write(0);
+    }
+    else
+    {
+      _spi.write(0);
+    }
+    _cs = 1;
+  }
+
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/transport.h	Fri Apr 24 12:57:23 2015 +0000
@@ -0,0 +1,93 @@
+/**
+ * \file transport.h
+ * \copyright Copyright (c) AppNearMe Ltd 2015
+ * \author Donatien Garnier
+ */
+#ifndef SRC_TRANSPORT_H_
+#define SRC_TRANSPORT_H_
+
+#include "mbed.h"
+#include <cstddef>
+
+class Transport
+{
+public:
+  Transport(PinName mosi, PinName miso, PinName sck, PinName cs, PinName irq);
+
+  void init();
+
+  void reset();
+
+  bool statusChanged();
+
+  uint32_t status();
+
+  void nfcPoll(bool enable);
+
+  void nfcOperation(bool readOp, bool writeOp);
+
+  void nfcGetInfoIsoA(uint8_t* atqa, uint8_t* sak, uint8_t* uid, size_t* pUidLength);
+
+  void nfcGetMessageInfo(size_t* pRecordCount);
+
+  void nfcSetMessageInfo(size_t recordCount);
+
+  void nfcGetRecordInfo(size_t recordNumber, uint16_t* pType, uint16_t* info, size_t infoCount);
+
+  void nfcSetRecordInfo(size_t recordNumber, uint16_t type, uint16_t* info, size_t infoCount);
+
+  void nfcGetRecordData(size_t recordNumber, size_t item, size_t offset, uint8_t* data, size_t length);
+
+  void nfcSetRecordData(size_t recordNumber, size_t item, size_t offset, uint8_t* data, size_t length);
+
+  void nfcPrepareMessage(bool lock, bool generate);
+
+  void nfcDecodePrefix(uint8_t prefix, char* data, size_t* pDataLength);
+
+  void nfcEncodePrefix(uint8_t* pPrefix, char* data, size_t dataLength);
+
+  void leds(bool led1, bool led2);
+
+protected:
+  enum CommandError
+  {
+    OK                  = 0,
+    ERR_LENGTH          = 1,
+    ERR_EMPTY           = 2,
+    ERR_UNKNOWN_COMMAND = 3,
+    ERR_TIMEOUT         = 4,
+    ERR_PARAMS          = 5,
+    ERR_STATUS          = 6,
+  };
+
+  enum CommandCode
+  {
+    GET_STATUS = 0,
+    INFO = 1,
+    RESET = 2,
+    LEDS = 3,
+    NFC_POLL = 4,
+    NFC_OPERATION = 5,
+    NFC_GET_INFO = 6,
+    NFC_GET_MESSAGE_INFO = 7,
+    NFC_GET_RECORD_INFO = 8,
+    NFC_GET_RECORD_DATA = 9,
+    NFC_SET_MESSAGE_INFO = 10,
+    NFC_SET_RECORD_INFO = 11,
+    NFC_SET_RECORD_DATA = 12,
+    NFC_PREPARE_MESSAGE = 13,
+    NFC_DECODE_PREFIX = 14,
+    NFC_ENCODE_PREFIX = 15
+  };
+
+  CommandError command(CommandCode command, uint8_t* outBuf, size_t outLength, uint8_t* inBuf, size_t inLength);
+
+private:
+  DigitalOut _cs;
+  SPI _spi;
+  DigitalIn _int;
+};
+
+
+
+#endif /* SRC_TRANSPORT_H_ */