NFC API for mbed using the MicroNFCBoard as a peripheral
Dependents: MicroNFCBoardAPI_P2P_Client MicroNFCBoardAPI_Blink MicroNFCBoardAPI_Tag_Emulator MicroNFCBoardAPI_Tag_Reader ... more
Revision 0:07fa9c0dd549, committed 2015-04-24
- Comitter:
- AppNearMe
- Date:
- Fri Apr 24 12:57:23 2015 +0000
- Child:
- 1:1d246e0872c6
- Commit message:
- Initial commit
Changed in this revision
--- /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_ */