Merge pull request #7822 from donatieng/nfc-impl

Add initial NFC support to Mbed OS
pull/7951/head
Cruz Monrreal 2018-08-31 19:01:25 -05:00 committed by GitHub
commit f82feecc51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 14350 additions and 3 deletions

499
TESTS/nfc/eeprom/main.cpp Normal file
View File

@ -0,0 +1,499 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include <events/mbed_events.h>
#include "NFCEEPROMDriver.h"
#if !MBED_CONF_NFCEEPROM
#error [NOT_SUPPORTED] NFC EEPROM not supported for this target
#endif
using namespace utest::v1;
using namespace mbed::nfc;
/* individual steps that map to specific operations that include parameters */
typedef enum {
START_SESSION = 0x0000,
END_SESSION = 0x0100,
READ_BYTES = 0x0200,
READ_2_BYTES = 0x0201,
READ_2_BYTES_OFFSET_FAIL = 0x0202,
READ_4_BYTES = 0x0203,
READ_4_BYTES_MIXED = 0x0204,
READ_4_BYTES_OFFSET = 0x0205,
READ_4_BYTES_ERASED = 0x0206,
READ_4_BYTES_FAIL = 0x0207,
WRITE_BYTES = 0x0300,
WRITE_2_BYTES = 0x0301,
WRITE_2_BYTES_OFFSET = 0x0302,
WRITE_2_BYTES_OFFSET_FAIL = 0x0303,
WRITE_4_BYTES = 0x0304,
WRITE_4_BYTES_FAIL = 0x0305,
ERASE_BYTES = 0x0400,
ERASE_4_BYTES = 0x0401,
READ_SIZE = 0x0500,
READ_SIZE_2 = 0x0501,
READ_SIZE_4 = 0x0502,
WRITE_SIZE = 0x0600,
WRITE_SIZE_2 = 0x0601,
WRITE_SIZE_4 = 0x0602,
TERMINATE = 0xFF00
} TestCommand_t;
/* We group the command based on their fist byte to simplify step checking.
* Individual conditions of a step are checked in the event so this doesn't
* sacrifice any correctness checking */
const size_t TEST_COMMAND_GROUP_MASK = 0xFF00;
/* test case sequences that index into the array of commands which comprise them */
typedef enum {
SESSION_TEST,
WRITE_READ_TEST,
ERASE_TEST,
WRITE_READ_SIZE_TEST,
TRUNCATE_TEST,
WRITE_TRUNCATE_TEST,
WRITE_WITH_OFFSET_TEST,
WRITE_BEYOND_SIZE_TEST,
SEQUENCE_MAX
} TestSequence_t;
static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE);
static const size_t MAX_STEP = 10;
static const size_t BUFFER_MAX = 10;
/* defines the "script" the test follows, each step is checked and all
* have to execute to completion for a successful run */
static const TestCommand_t SEQUENCES[SEQUENCE_MAX][MAX_STEP] = {
/* SESSION_TEST */
{ START_SESSION, END_SESSION, TERMINATE },
/* WRITE_READ_TEST */
{
START_SESSION, WRITE_SIZE_4, READ_SIZE_4, WRITE_4_BYTES, READ_4_BYTES,
WRITE_2_BYTES, READ_4_BYTES_MIXED, END_SESSION, TERMINATE
},
/* ERASE_TEST */
{
START_SESSION, WRITE_SIZE_4, READ_SIZE_4, WRITE_4_BYTES, READ_4_BYTES,
ERASE_4_BYTES, READ_4_BYTES_ERASED, END_SESSION, TERMINATE
},
/* WRITE_READ_SIZE_TEST */
{
START_SESSION, WRITE_SIZE_2, READ_SIZE_2, WRITE_SIZE_4, READ_SIZE_4,
END_SESSION, TERMINATE
},
/* TRUNCATE_TEST */
{
START_SESSION, WRITE_SIZE_4, READ_SIZE_4, WRITE_4_BYTES, READ_4_BYTES,
WRITE_SIZE_2, READ_SIZE_2, READ_4_BYTES_FAIL, END_SESSION, TERMINATE
},
/* WRITE_TRUNCATE_TEST */
{
START_SESSION, WRITE_SIZE_2, READ_SIZE_2, WRITE_4_BYTES_FAIL, READ_4_BYTES_FAIL,
END_SESSION, TERMINATE
},
/* WRITE_WITH_OFFSET_TEST */
{
START_SESSION, WRITE_SIZE_4, READ_SIZE_4, WRITE_4_BYTES, READ_4_BYTES,
WRITE_2_BYTES_OFFSET, READ_4_BYTES_OFFSET, END_SESSION, TERMINATE
},
/* WRITE_BEYOND_SIZE_TEST */
{
START_SESSION, WRITE_SIZE_2, READ_SIZE_2, WRITE_2_BYTES_OFFSET_FAIL, READ_2_BYTES_OFFSET_FAIL,
WRITE_2_BYTES, READ_2_BYTES, END_SESSION, TERMINATE
}
};
static const uint8_t DATA_4_BYTES[] = { 0x01, 0x02, 0x03, 0x04 };
static const uint8_t DATA_2_BYTES[] = { 0x05, 0x06 };
static const uint8_t DATA_4_BYTES_MIXED[] = { 0x05, 0x06, 0x03, 0x04 };
static const uint8_t DATA_4_BYTES_OFFSET[] = { 0x01, 0x02, 0x05, 0x06 };
static const uint8_t DATA_4_BYTES_ERASED[] = { 0x00, 0x00, 0x00, 0x00 };
class DriverTest : public NFCEEPROMDriver::Delegate {
public:
DriverTest(NFCEEPROMDriver *_driver)
: _operation_data(NULL),
_driver(_driver),
_sequence(SEQUENCE_MAX),
_step(0),
_result_size(0),
_address(0),
_success(true) { };
virtual ~DriverTest() { };
/* Delegate events */
virtual void on_session_started(bool success)
{
if (success != _success) {
TEST_FAIL_MESSAGE("failed to start session");
}
evaluate_step(START_SESSION);
};
virtual void on_session_ended(bool success)
{
if (success != _success) {
TEST_FAIL_MESSAGE("failed to end session");
}
evaluate_step(END_SESSION);
};
virtual void on_bytes_read(size_t count)
{
if (count != _result_size) {
TEST_FAIL_MESSAGE("failed to read bytes");
}
if (memcmp(_buffer, _operation_data, count) != 0) {
TEST_FAIL_MESSAGE("read bytes are different than expected");
}
evaluate_step(READ_BYTES);
};
virtual void on_bytes_written(size_t count)
{
if (count != _result_size) {
TEST_FAIL_MESSAGE("failed to write bytes");
}
evaluate_step(WRITE_BYTES);
};
virtual void on_size_written(bool success)
{
if (success != _success) {
TEST_FAIL_MESSAGE("failed to write size");
}
evaluate_step(WRITE_SIZE);
};
virtual void on_size_read(bool success, size_t size)
{
if (success != _success || size != _result_size) {
TEST_FAIL_MESSAGE("failed to read size");
}
evaluate_step(READ_SIZE);
};
virtual void on_bytes_erased(size_t count)
{
if (count != _result_size) {
TEST_FAIL_MESSAGE("failed to erase bytes");
}
evaluate_step(ERASE_BYTES);
}
/* Sequence running code */
void run_sequence(TestSequence_t sequence)
{
_sequence = sequence;
if (_sequence >= SEQUENCE_MAX) {
TEST_FAIL_MESSAGE("internal test failure - invalid command");
}
execute_next_step();
event_queue.dispatch_forever();
TEST_ASSERT_EQUAL(TERMINATE, SEQUENCES[_sequence][_step]);
}
void execute_next_step()
{
TestCommand_t command = SEQUENCES[_sequence][_step];
/* setup data buffer */
switch (command) {
case READ_2_BYTES:
case READ_2_BYTES_OFFSET_FAIL:
case WRITE_2_BYTES:
case WRITE_2_BYTES_OFFSET:
case WRITE_2_BYTES_OFFSET_FAIL:
_operation_data = DATA_2_BYTES;
break;
case READ_4_BYTES:
case READ_4_BYTES_FAIL:
case WRITE_4_BYTES:
case WRITE_4_BYTES_FAIL:
_operation_data = DATA_4_BYTES;
break;
case READ_4_BYTES_ERASED:
_operation_data = DATA_4_BYTES_ERASED;
break;
case READ_4_BYTES_MIXED:
_operation_data = DATA_4_BYTES_MIXED;
break;
case READ_4_BYTES_OFFSET:
_operation_data = DATA_4_BYTES_OFFSET;
break;
default:
_operation_data = NULL;
}
/* setup result size */
switch (command) {
case READ_2_BYTES:
case READ_4_BYTES_FAIL:
case WRITE_2_BYTES:
case WRITE_4_BYTES_FAIL:
case WRITE_2_BYTES_OFFSET:
case READ_SIZE_2:
_result_size = 2;
break;
case READ_4_BYTES:
case READ_4_BYTES_ERASED:
case READ_4_BYTES_MIXED:
case READ_4_BYTES_OFFSET:
case WRITE_4_BYTES:
case ERASE_4_BYTES:
case READ_SIZE_4:
_result_size = 4;
break;
default:
_result_size = 0;
}
/* setup operation size */
switch (command) {
case READ_2_BYTES:
case READ_2_BYTES_OFFSET_FAIL:
case WRITE_2_BYTES:
case WRITE_2_BYTES_OFFSET:
case WRITE_2_BYTES_OFFSET_FAIL:
case WRITE_SIZE_2:
_operation_size = 2;
break;
case READ_4_BYTES:
case READ_4_BYTES_ERASED:
case READ_4_BYTES_MIXED:
case READ_4_BYTES_OFFSET:
case READ_4_BYTES_FAIL:
case WRITE_4_BYTES:
case WRITE_4_BYTES_FAIL:
case ERASE_4_BYTES:
case READ_SIZE_4:
case WRITE_SIZE_4:
_operation_size = 4;
break;
default:
_operation_size = 0;
}
/* setup offset */
switch (command) {
case READ_2_BYTES_OFFSET_FAIL:
case WRITE_2_BYTES_OFFSET:
case WRITE_2_BYTES_OFFSET_FAIL:
_address = 2;
break;
default:
_address = 0;
}
/* setup command success */
switch (command) {
case READ_2_BYTES_OFFSET_FAIL:
case WRITE_2_BYTES_OFFSET_FAIL:
_success = false;
break;
default:
_success = true;
}
/* call next command */
switch (command & TEST_COMMAND_GROUP_MASK) {
case START_SESSION:
_driver->start_session(true);
break;
case END_SESSION:
_driver->end_session();
break;
case READ_BYTES:
_driver->read_bytes(_address, _buffer, _operation_size);
break;
case WRITE_BYTES:
_driver->write_bytes(_address, _operation_data, _operation_size);
break;
case ERASE_BYTES:
_driver->erase_bytes(_address, 4);
break;
case READ_SIZE:
_driver->read_size();
break;
case WRITE_SIZE:
_driver->write_size(_operation_size);
break;
case TERMINATE:
event_queue.break_dispatch();
break;
default:
TEST_FAIL_MESSAGE("internal test failure - invalid command");
}
}
void evaluate_step(TestCommand_t command_completed)
{
/* check last command succeeded */
TEST_ASSERT_EQUAL(command_completed, SEQUENCES[_sequence][_step]&TEST_COMMAND_GROUP_MASK);
_step++;
if (_step == MAX_STEP) {
TEST_FAIL_MESSAGE("internal test failure - too many steps");
}
execute_next_step();
}
private:
uint8_t _buffer[BUFFER_MAX];
const uint8_t *_operation_data;
NFCEEPROMDriver *_driver;
TestSequence_t _sequence;
size_t _step;
size_t _result_size;
size_t _operation_size;
size_t _address;
bool _success;
};
/* test case running code */
static DriverTest *driver_test;
extern NFCEEPROMDriver *greentea_nfc_EEPROM_driver_get_instance();
utest::v1::status_t test_setup(const Case *const source, const size_t index_of_case)
{
NFCEEPROMDriver *driver = greentea_nfc_EEPROM_driver_get_instance();
driver_test = new DriverTest(driver);
driver->set_event_queue(&event_queue);
driver->set_delegate(driver_test);
driver->reset();
TEST_ASSERT_NOT_EQUAL(0, driver->read_max_size());
return greentea_case_setup_handler(source, index_of_case);
}
void session()
{
driver_test->run_sequence(SESSION_TEST);
}
void write_read()
{
driver_test->run_sequence(WRITE_READ_TEST);
}
void erase_bytes()
{
driver_test->run_sequence(ERASE_TEST);
}
void write_read_size()
{
driver_test->run_sequence(WRITE_READ_SIZE_TEST);
}
void truncate_size()
{
driver_test->run_sequence(TRUNCATE_TEST);
}
void write_bytes_truncated()
{
driver_test->run_sequence(WRITE_TRUNCATE_TEST);
}
void write_with_offset()
{
driver_test->run_sequence(WRITE_WITH_OFFSET_TEST);
}
void write_beyond_size()
{
driver_test->run_sequence(WRITE_BEYOND_SIZE_TEST);
}
utest::v1::status_t test_tear_down(const Case *const source, const size_t passed,
const size_t failed, const failure_t reason)
{
delete driver_test;
return greentea_case_teardown_handler(source, passed, failed, reason);
}
/* test setup */
utest::v1::status_t test_init(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
// Test cases
Case cases[] = {
Case("NFCEEPROM-SESSION", test_setup, session, test_tear_down),
Case("NFCEEPROM-WRITE-READ", test_setup, write_read, test_tear_down),
Case("NFCEEPROM-ERASE-BYTES", test_setup, erase_bytes, test_tear_down),
Case("NFCEEPROM-WRITE-READ-SIZE", test_setup, write_read_size, test_tear_down),
Case("NFCEEPROM-TRUNCATE-SIZE", test_setup, truncate_size, test_tear_down),
Case("NFCEEPROM-WRITE-BYTES-TRUNCATED", test_setup, write_bytes_truncated, test_tear_down),
Case("NFCEEPROM-WRITE-WITH-OFFSET", test_setup, write_with_offset, test_tear_down),
Case("NFCEEPROM-WRITE-BEYOND-SIZE", test_setup, write_beyond_size, test_tear_down)
};
Specification specification(test_init, cases);
// Entry point into the tests
int main()
{
return !Harness::run(specification);
}

View File

@ -10,5 +10,5 @@
"EXPAND_AS_DEFINED": "",
"SKIP_FUNCTION_MACROS": "NO",
"STRIP_CODE_COMMENTS": "NO",
"EXCLUDE_PATTERNS": "*/tools/* */targets/* */features/mbedtls/* */features/storage/* */features/unsupported/* */BUILD/* */rtos/TARGET_CORTEX/rtx*/* */cmsis/* */features/lwipstack/* */nanostack/sal-stack-nanostack/* */nanostack/coap-service/* */ble/generic/* */ble/pal/* */mbed-trace/* */mbed-coap/* */nanostack-libservice/* */mbed-client-randlib/* */nanostack/sal-stack-nanostack-eventloop/*"
"EXCLUDE_PATTERNS": "*/tools/* */targets/* */features/mbedtls/* */features/storage/* */features/unsupported/* */BUILD/* */rtos/TARGET_CORTEX/rtx*/* */cmsis/* */features/lwipstack/* */nanostack/sal-stack-nanostack/* */nanostack/coap-service/* */ble/generic/* */ble/pal/* */mbed-trace/* */mbed-coap/* */nanostack-libservice/* */mbed-client-randlib/* */nanostack/sal-stack-nanostack-eventloop/* */features/nfc/stack/*"
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ac_buffer.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
/** \addtogroup ACore
* @{
* \name Buffer
* @{
*/
#ifndef ACORE_BUFFER_H_
#define ACORE_BUFFER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stddef.h"
#include "stdbool.h"
typedef struct __ac_buffer {
const uint8_t *data;
size_t size;
struct __ac_buffer *pNext;
} ac_buffer_t;
/** Initialize ac_buffer using underlying byte array, set ac_buffer's length to 0 (empty)
* \param pBuf pointer to ac_buffer_t structure to initialize
* \param data byte array to use
* \param size size of byte array
*/
void ac_buffer_init(ac_buffer_t *pBuf, const uint8_t *data, size_t size);
/** Copy pBufIn to pBuf
* \param pBuf pointer to ac_buffer_t structure to initialize
* \param pBufIn the source buffer
*/
void ac_buffer_dup(ac_buffer_t *pBuf, const ac_buffer_t *pBufIn);
/** Get buffer's underlying byte array
* \param pBuf pointer to ac_buffer_t structure
* \return underlying array
*/
static inline const uint8_t *ac_buffer_data(const ac_buffer_t *pBuf)
{
return pBuf->data;
}
/** Get buffer's size
* \param pBuf pointer to ac_buffer_t structure
* \return buffer's size
*/
static inline size_t ac_buffer_size(const ac_buffer_t *pBuf)
{
return pBuf->size;
}
/** Get next buffer in chain
* \param pBuf pointer to ac_buffer_t structure
* \return pointer to next buffer
*/
static inline ac_buffer_t *ac_buffer_next(const ac_buffer_t *pBuf)
{
return pBuf->pNext;
}
/** Set next buffer in chain
* \param pBuf pointer to ac_buffer_t structure
* \param pNextBuf pointer to next buffer (or NULL to break chain)
*/
static inline void ac_buffer_set_next(ac_buffer_t *pBuf, ac_buffer_t *pNextBuf)
{
pBuf->pNext = (ac_buffer_t *) pNextBuf;
}
/** Append buffer to end of chain
* \param pBuf pointer to ac_buffer_t structure
* \param pAppBuf pointer to buffer to append to chain
*/
void ac_buffer_append(ac_buffer_t *pBuf, ac_buffer_t *pAppBuf);
/** Truncate pBuf to length bytes and save the remaining bytes in pEndBuf
* \param pBuf The buffer to split (will be set to invalid state)
* \param pStartBuf A new buffer at the head of the split
* \param pEndBuf A new buffer at the tail of the split
* \param length How long pStartBuf should be (if longer than pBuf, then pStartBuf will be pBuf)
*/
void ac_buffer_split(ac_buffer_t *pStartBuf, ac_buffer_t *pEndBuf, ac_buffer_t *pBuf, size_t length);
//Debug
void ac_buffer_dump(ac_buffer_t *pBuf);
#ifdef __cplusplus
}
#endif
#endif /* ACORE_BUFFER_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,370 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ac_buffer_builder.h
* \copyright Copyright (c) ARM Ltd 2017
* \author Donatien Garnier
*/
/** \addtogroup ACore
* @{
* \name Buffer Builder
* @{
*/
#ifndef ACORE_BUFFER_BUILDER_H_
#define ACORE_BUFFER_BUILDER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stddef.h"
#include "stdbool.h"
#include "acore/ac_buffer.h"
typedef struct __ac_buffer_builder {
ac_buffer_t ac_buffer;
uint8_t *data;
size_t size;
} ac_buffer_builder_t;
/** Write data to big endian ac_buffer (on a LE architecture, byte order will be swapped)
* \param pBuilder ac_buffer builder to use
* \param buf pointer to data
* \param size the data size
*/
void ac_buffer_builder_write_be(ac_buffer_builder_t *pBuilder, const uint8_t *buf, size_t size);
/** Write data to little endian ac_buffer (on a LE architecture, byte order will be preserved)
* \param pBuilder ac_buffer builder to use
* \param buf pointer to data
* \param size the data size
*/
void ac_buffer_builder_write_le(ac_buffer_builder_t *pBuilder, const uint8_t *buf, size_t size);
/** Write data to big endian ac_buffer at specific position (on a LE architecture, byte order will be swapped)
* \param pBuilder ac_buffer builder to use
* \param pos position in ac_buffer to write from
* \param buf pointer to data
* \param size the data size
*/
void ac_buffer_builder_write_be_at(ac_buffer_builder_t *pBuilder, size_t pos, const uint8_t *buf, size_t size);
/** Write data to little endian ac_buffer at specific position (on a LE architecture, byte order will be preserved)
* \param pBuilder ac_buffer builder to use
* \param pos position in ac_buffer to write from
* \param buf pointer to data
* \param size the data size
*/
void ac_buffer_builder_write_le_at(ac_buffer_builder_t *pBuilder, size_t pos, const uint8_t *buf, size_t size);
/** Initialize ac_buffer builder
* \param pBuilder ac_buffer builder to init
* \param data pointer to byte array to use
* \param size of byte array
*/
void ac_buffer_builder_init(ac_buffer_builder_t *pBuilder, uint8_t *data, size_t size);
/** Initialize ac_buffer builder from underlying ac_buffer
* \param pBuilder ac_buffer builder to init
*/
void ac_buffer_builder_from_buffer(ac_buffer_builder_t *pBuilder);
/** Reset ac_buffer builder
* \param pBuilder ac_buffer builder to reset
*/
void ac_buffer_builder_reset(ac_buffer_builder_t *pBuilder);
/** Set ac_buffer builder's ac_buffer to full size
* \param pBuilder ac_buffer builder to set to full size
*/
void ac_buffer_builder_set_full(ac_buffer_builder_t *pBuilder);
/** Get ac_buffer builder's length
* \param pBuilder ac_buffer builder to get length of
* \return number of valid bytes in ac_buffer
*/
static inline size_t ac_buffer_builder_length(ac_buffer_builder_t *pBuilder)
{
return ac_buffer_size(&pBuilder->ac_buffer);
}
/** Set ac_buffer builder's length
* \param pBuilder ac_buffer builder to set length of
* \param length number of valid bytes in ac_buffer
*/
static inline void ac_buffer_builder_set_length(ac_buffer_builder_t *pBuilder, size_t length)
{
if (ac_buffer_data(&pBuilder->ac_buffer) + length > pBuilder->data + pBuilder->size) {
return;
}
pBuilder->ac_buffer.size = length;
}
/** Get ac_buffer builder's pointer to write position
* \param pBuilder ac_buffer builder
* \return pointer to write position
*/
static inline uint8_t *ac_buffer_builder_write_position(ac_buffer_builder_t *pBuilder)
{
return (uint8_t *)ac_buffer_data(&pBuilder->ac_buffer) + ac_buffer_size(&pBuilder->ac_buffer);
}
/** Get ac_buffer builder's write offset
* \param pBuilder ac_buffer builder
* \return write offset
*/
static inline size_t ac_buffer_builder_write_offset(ac_buffer_builder_t *pBuilder)
{
return ac_buffer_data(&pBuilder->ac_buffer) + ac_buffer_size(&pBuilder->ac_buffer) - pBuilder->data;
}
/** Set ac_buffer builder's write offset
* \param pBuilder ac_buffer builder
* \param off new write offset
*/
static inline void ac_buffer_builder_set_write_offset(ac_buffer_builder_t *pBuilder, size_t off)
{
if (off > pBuilder->size) {
return;
}
if (pBuilder->data + off > pBuilder->ac_buffer.data) {
pBuilder->ac_buffer.size = off - (pBuilder->ac_buffer.data - pBuilder->data);
} else {
pBuilder->ac_buffer.size = 0;
}
}
/** Get ac_buffer builder's read offset
* \param pBuilder ac_buffer builder
* \return read offset
*/
static inline size_t ac_buffer_builder_read_offset(ac_buffer_builder_t *pBuilder)
{
return ac_buffer_data(&pBuilder->ac_buffer) - pBuilder->data;
}
/** Set ac_buffer builder's read offset
* \param pBuilder ac_buffer builder
* \param off new read offset
*/
static inline void ac_buffer_builder_set_read_offset(ac_buffer_builder_t *pBuilder, size_t off)
{
if (off > pBuilder->size) {
return;
}
if (pBuilder->data + off < pBuilder->ac_buffer.data + pBuilder->ac_buffer.size) {
pBuilder->ac_buffer.size = pBuilder->ac_buffer.data - (pBuilder->data + off);
} else {
pBuilder->ac_buffer.size = 0;
}
pBuilder->ac_buffer.data = pBuilder->data + off;
}
/** Get ac_buffer builder's underlying ac_buffer
* \param pBuilder ac_buffer builder
* \return ac_buffer
*/
static inline ac_buffer_t *ac_buffer_builder_buffer(ac_buffer_builder_t *pBuilder)
{
return &pBuilder->ac_buffer;
}
/** Get space in ac_buffer builder
* \param pBuilder ac_buffer builder
* \return number of free bytes in ac_buffer builder
*/
static inline size_t ac_buffer_builder_space(ac_buffer_builder_t *pBuilder)
{
return pBuilder->size - (ac_buffer_data(&pBuilder->ac_buffer) - pBuilder->data + ac_buffer_size(&pBuilder->ac_buffer));
}
/** Is ac_buffer builder empty
* \param pBuilder ac_buffer builder
* \return true if ac_buffer builder is empty
*/
static inline bool ac_buffer_builder_empty(ac_buffer_builder_t *pBuilder)
{
return (ac_buffer_builder_length(pBuilder) == 0);
}
/** Is ac_buffer builder full
* \param pBuilder ac_buffer builder
* \return true if ac_buffer builder is full
*/
static inline bool ac_buffer_full(ac_buffer_builder_t *pBuilder)
{
return (ac_buffer_builder_space(pBuilder) == 0);
}
/** Write 8-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu8 8-bit value to write
*/
static inline void ac_buffer_builder_write_nu8(ac_buffer_builder_t *pBuilder, uint8_t hu8)
{
ac_buffer_builder_write_be(pBuilder, &hu8, 1);
}
/** Write 16-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu16 16-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu16(ac_buffer_builder_t *pBuilder, uint16_t hu16)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t *)&hu16, 2);
}
/** Write 24-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu24 24-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu24(ac_buffer_builder_t *pBuilder, uint32_t hu24)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t *)&hu24, 3);
}
/** Write 32-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu32 32-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu32(ac_buffer_builder_t *pBuilder, uint32_t hu32)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t *)&hu32, 4);
}
/** Write 64-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu64 64-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu64(ac_buffer_builder_t *pBuilder, uint64_t hu64)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t *)&hu64, 8);
}
/** Write n-bytes value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param data data to write
* \param size data length
*/
static inline void ac_buffer_builder_write_n_bytes(ac_buffer_builder_t *pBuilder, const uint8_t *data, size_t size)
{
ac_buffer_builder_write_le(pBuilder, data, size);
}
/** Write 8-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu8 8-bit value to write
*/
static inline void ac_buffer_builder_write_nu8_at(ac_buffer_builder_t *pBuilder, size_t off, uint8_t hu8)
{
ac_buffer_builder_write_be_at(pBuilder, off, &hu8, 1);
}
/** Write 16-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu16 16-bit value to write
*/
static inline void ac_buffer_builder_write_nu16_at(ac_buffer_builder_t *pBuilder, size_t off, uint16_t hu16)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t *)&hu16, 2);
}
/** Write 24-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu24 24-bit value to write
*/
static inline void ac_buffer_builder_write_nu24_at(ac_buffer_builder_t *pBuilder, size_t off, uint32_t hu24)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t *)&hu24, 3);
}
/** Write 32-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu32 32-bit value to write
*/
static inline void ac_buffer_builder_write_nu32_at(ac_buffer_builder_t *pBuilder, size_t off, uint32_t hu32)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t *)&hu32, 4);
}
/** Write 64-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu64 64-bit value to write
*/
static inline void ac_buffer_builder_write_nu64_at(ac_buffer_builder_t *pBuilder, size_t off, uint64_t hu64)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t *)&hu64, 8);
}
/** Write n-bytes value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param data data to write
* \param size data length
*/
static inline void ac_buffer_builder_write_n_bytes_at(ac_buffer_builder_t *pBuilder, size_t off, const uint8_t *data, size_t size)
{
ac_buffer_builder_write_be_at(pBuilder, off, data, size);
}
/** Skip n-bytes in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param size number of bytes to skip
*/
void ac_buffer_builder_write_n_skip(ac_buffer_builder_t *pBuilder, size_t size);
/** Copy n bytes from buffer to builder
* \param pBuilderOut ac_buffer builder
* \param pBufIn the input buffer
* \param size number of bytes to copy
*/
void ac_buffer_builder_copy_n_bytes(ac_buffer_builder_t *pBuilderOut, ac_buffer_t *pBufIn, size_t size);
/** Compact builder
* Will move underlying buffer's byte to start of allocated buffer
* \param pBuilder ac_buffer builder
*/
void ac_buffer_builder_compact(ac_buffer_builder_t *pBuilder);
/** Get number of writable bytes in ac_buffer builder
* \param pBuilder ac_buffer builder
* \return number of free bytes in ac_buffer builder
*/
static inline size_t ac_buffer_builder_writable(ac_buffer_builder_t *pBuilder)
{
return ac_buffer_builder_space(pBuilder);
}
#ifdef __cplusplus
}
#endif
#endif /* ACORE_BUFFER_BUILDER_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,169 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ac_buffer_reader.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
/** \addtogroup ACore
* @{
* \name Buffer Reader
* @{
*/
#ifndef ACORE_BUFFER_READER_H_
#define ACORE_BUFFER_READER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stddef.h"
#include "stdbool.h"
#include "acore/ac_buffer.h"
/** Read n-bytes in big-endian format from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \param buf the array to write to
* \param size the number of bytes to read
*/
void ac_buffer_read_be(ac_buffer_t *pBuf, uint8_t *buf, size_t size);
/** Read n-bytes in little-endian format from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \param buf the array to write to
* \param size the number of bytes to read
*/
void ac_buffer_read_le(ac_buffer_t *pBuf, uint8_t *buf, size_t size);
/** Read 8-bit value from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \return 8-bit value read
*/
static inline uint8_t ac_buffer_read_nu8(ac_buffer_t *pBuf)
{
uint8_t hu8;
ac_buffer_read_be(pBuf, &hu8, 1);
return hu8;
}
/** Read BE 16-bit value from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \return 16-bit value read
*/
static inline uint16_t ac_buffer_read_nu16(ac_buffer_t *pBuf)
{
uint16_t hu16;
ac_buffer_read_be(pBuf, (uint8_t *)&hu16, 2);
return hu16;
}
/** Read BE 24-bit value from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \return 24-bit value read
*/
static inline uint32_t ac_buffer_read_nu24(ac_buffer_t *pBuf)
{
uint32_t hu24;
ac_buffer_read_be(pBuf, (uint8_t *)&hu24, 3);
return hu24;
}
/** Read BE 32-bit value from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \return 32-bit value read
*/
static inline uint32_t ac_buffer_read_nu32(ac_buffer_t *pBuf)
{
uint32_t hu32;
ac_buffer_read_be(pBuf, (uint8_t *)&hu32, 4);
return hu32;
}
/** Read BE 64-bit value from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \return 64-bit value read
*/
static inline uint64_t ac_buffer_read_nu64(ac_buffer_t *pBuf)
{
uint64_t hu64;
ac_buffer_read_be(pBuf, (uint8_t *)&hu64, 8);
return hu64;
}
/** Read n bytes from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \param data the array to write bytes to
* \param size the number of bytes to read
*/
static inline void ac_buffer_read_n_bytes(ac_buffer_t *pBuf, uint8_t *data, size_t size)
{
ac_buffer_read_le(pBuf, data, size);
}
/** Skip n bytes from buffer reader and advance read posiion
* \param pBuf the buffer to read from
* \param size the number of bytes to skip
*/
void ac_buffer_read_n_skip(ac_buffer_t *pBuf, size_t size);
/** Get number of bytes readable from buffer
* \param pBuf the buffer to read from
* \return The number of bytes which can be read
*/
size_t ac_buffer_reader_readable(const ac_buffer_t *pBuf);
/** Get a pointer to the current position within this buffer's current backing array
* \param pBuf the buffer to read from
* \return A pointer to the current position within the current backing array
*/
const uint8_t *ac_buffer_reader_current_buffer_pointer(ac_buffer_t *pBuf);
/** Get the number of bytes readable within the current backing array
* \param pBuf the buffer to read from
* \return The number of bytes readable within the current backing array
*/
size_t ac_buffer_reader_current_buffer_length(ac_buffer_t *pBuf);
/** Compare buffer with array (does not advance read position)
* \param pBuf the buffer to compare from
* \param bytes the array to compare with
* \param length the array length
* \return Whether the buffer is AT LEAST as long as the array AND the buffer and array have the same content
*/
bool ac_buffer_reader_cmp_bytes(const ac_buffer_t *pBuf, const uint8_t *bytes, size_t length);
/** Compare buffer with array (does not advance read position)
* \param pBuf1 the buffer to compare from
* \param pBuf2 the buffer to compare with
* \return Whether the buffers have the same length and content
*/
bool ac_buffer_reader_cmp(const ac_buffer_t *pBuf1, const ac_buffer_t *pBuf2);
#ifdef __cplusplus
}
#endif
#endif /* CORE_ac_buffer_READER_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,41 @@
/**
* \file ac_debug.h
* \copyright Copyright (c) ARM Ltd 2018
* \author Donatien Garnier
*/
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ACORE_DEBUG_H_
#define ACORE_DEBUG_H_
// Macro that can be defined to lock stdio in multithreaded environments
#if !defined(ACORE_STDIO_LOCK)
#define ACORE_STDIO_LOCK()
#endif
#if !defined(ACORE_STDIO_UNLOCK)
#define ACORE_STDIO_UNLOCK()
#endif
// Macro that can be defined to define an alternative printf impl for debugging
#if !defined(ACORE_STDIO_PRINT)
#include "stdio.h"
#define ACORE_STDIO_PRINT(...) printf(__VA_ARGS__)
#endif
#endif

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ACORE_MACROS_H_
#define ACORE_MACROS_H_
//Macros
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#endif

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ac_stream.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef ACORE_STREAM_H_
#define ACORE_STREAM_H_
#ifdef __cplusplus
extern "C" {
#endif
struct __ac_istream;
struct __ac_ostream;
typedef struct __ac_istream ac_istream_t;
typedef struct __ac_ostream ac_ostream_t;
#include "stddef.h"
#include "stdbool.h"
#include "stdint.h"
#include "acore/ac_buffer.h"
typedef void (*ac_istream_fn)(ac_buffer_t *pDataIn, bool *pClose, size_t maxLength, void *pUserParam);
typedef void (*ac_ostream_fn)(ac_buffer_t *pDataOut, bool closed, void *pUserParam);
//Input stream -- pulled by consumer
struct __ac_istream {
ac_istream_fn fn;
void *pUserParam;
};
//Output stream -- pushed by supplier
struct __ac_ostream {
ac_ostream_fn fn;
void *pUserParam;
};
//Called by supplier
void ac_istream_init(ac_istream_t *pac_istream, ac_istream_fn fn, void *pUserParam);
//Called by consumer
void ac_istream_pull(ac_istream_t *pac_istream, ac_buffer_t *pDataIn, bool *pClose, size_t maxLength);
//Called by consumer
void ac_ostream_init(ac_ostream_t *pac_ostream, ac_ostream_fn fn, void *pUserParam);
//Called by supplier
void ac_ostream_push(ac_ostream_t *pac_ostream, ac_buffer_t *pDataOut, bool closed);
#ifdef __cplusplus
}
#endif
#endif /* ACORE_STREAM_H_ */

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file buffer.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \desc Module to ease ac_buffers' management
*/
#include "string.h"
#include "acore/ac_buffer.h"
#include "acore/ac_buffer_reader.h"
#include "acore/ac_macros.h"
#include "acore/ac_debug.h"
void ac_buffer_init(ac_buffer_t *pBuf, const uint8_t *data, size_t size)
{
pBuf->data = data;
pBuf->size = size;
pBuf->pNext = NULL;
}
void ac_buffer_dup(ac_buffer_t *pBuf, const ac_buffer_t *pBufIn)
{
if (pBuf != pBufIn) {
memcpy(pBuf, pBufIn, sizeof(ac_buffer_t));
}
}
void ac_buffer_append(ac_buffer_t *pBuf, ac_buffer_t *pAppBuf)
{
while (pBuf->pNext != NULL) {
pBuf = pBuf->pNext;
}
pBuf->pNext = pAppBuf;
}
void ac_buffer_split(ac_buffer_t *pStartBuf, ac_buffer_t *pEndBuf, ac_buffer_t *pBuf, size_t length)
{
ac_buffer_dup(pStartBuf, pBuf);
ac_buffer_dup(pEndBuf, pBuf);
ac_buffer_read_n_skip(pEndBuf, length);
while (length > ac_buffer_size(pStartBuf)) {
length -= pStartBuf->size;
pStartBuf = pStartBuf->pNext;
}
pStartBuf->size = length;
pStartBuf->pNext = NULL;
}
/** Dump a ac_buffer's content to stdout (useful for debugging)
* \param pBuf pointer to ac_buffer_t structure
*/
void ac_buffer_dump(ac_buffer_t *pBuf)
{
#if !defined(NDEBUG)
ACORE_STDIO_LOCK();
while (pBuf != NULL) {
size_t r = ac_buffer_size(pBuf);
size_t i = 0;
size_t j = 0;
while (i < r) {
for (j = i; j < MIN(i + 16, r); j++) {
ACORE_STDIO_PRINT("%02x ", ac_buffer_data(pBuf)[j]);
}
ACORE_STDIO_PRINT("\r\n");
i = j;
}
pBuf = ac_buffer_next(pBuf);
if (pBuf != NULL) {
ACORE_STDIO_PRINT("->\r\n");
}
}
ACORE_STDIO_UNLOCK();
#else
(void)pBuf;
#endif
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file buffer_builder.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#include "acore/ac_buffer_builder.h"
#include "acore/ac_buffer_reader.h"
#include "acore/ac_macros.h"
#include "string.h"
#define VOID
#define ENSURE_WRITE_LENGTH(pBuilder, n) do{ if( ac_buffer_builder_space(pBuilder) < n ) { return; } }while(0);
void ac_buffer_builder_init(ac_buffer_builder_t *pBuilder, uint8_t *data, size_t size)
{
pBuilder->data = data;
pBuilder->size = size;
ac_buffer_init(&pBuilder->ac_buffer, data, 0);
}
void ac_buffer_builder_from_buffer(ac_buffer_builder_t *pBuilder)
{
pBuilder->data = (uint8_t *)pBuilder->ac_buffer.data;
pBuilder->size = pBuilder->ac_buffer.size;
pBuilder->ac_buffer.size = 0;
}
void ac_buffer_builder_reset(ac_buffer_builder_t *pBuilder)
{
ac_buffer_init(&pBuilder->ac_buffer, pBuilder->data, 0);
}
void ac_buffer_builder_set_full(ac_buffer_builder_t *pBuilder)
{
ac_buffer_init(&pBuilder->ac_buffer, pBuilder->data, pBuilder->size);
}
void ac_buffer_builder_write_be(ac_buffer_builder_t *pBuilder, const uint8_t *buf, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilder, size);
buf += size;
while (size > 0) {
buf--;
*ac_buffer_builder_write_position(pBuilder) = *buf;
pBuilder->ac_buffer.size++;
size--;
}
}
void ac_buffer_builder_write_le(ac_buffer_builder_t *pBuilder, const uint8_t *buf, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilder, size);
memcpy(ac_buffer_builder_write_position(pBuilder), buf, size);
pBuilder->ac_buffer.size += size;
}
void ac_buffer_builder_write_be_at(ac_buffer_builder_t *pBuilder, size_t pos, const uint8_t *buf, size_t size)
{
size_t currentPos = pBuilder->ac_buffer.size;
pBuilder->ac_buffer.size = pos;
ac_buffer_builder_write_be(pBuilder, buf, size);
pBuilder->ac_buffer.size = currentPos;
}
void ac_buffer_builder_write_le_at(ac_buffer_builder_t *pBuilder, size_t pos, const uint8_t *buf, size_t size)
{
size_t currentPos = pBuilder->ac_buffer.size;
pBuilder->ac_buffer.size = pos;
ac_buffer_builder_write_le(pBuilder, buf, size);
pBuilder->ac_buffer.size = currentPos;
}
void ac_buffer_builder_write_n_skip(ac_buffer_builder_t *pBuilder, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilder, size);
pBuilder->ac_buffer.size += size;
}
void ac_buffer_builder_copy_n_bytes(ac_buffer_builder_t *pBuilderOut, ac_buffer_t *pBufIn, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilderOut, size);
if (ac_buffer_reader_readable(pBufIn) < size) {
return;
}
while (size > 0) {
size_t cpy = ac_buffer_reader_current_buffer_length(pBufIn);
cpy = MIN(cpy, size);
ac_buffer_builder_write_n_bytes(pBuilderOut, ac_buffer_reader_current_buffer_pointer(pBufIn), cpy);
ac_buffer_read_n_skip(pBufIn, cpy);
size -= cpy;
}
}
void ac_buffer_builder_compact(ac_buffer_builder_t *pBuilder)
{
memmove(pBuilder->data, ac_buffer_data(&pBuilder->ac_buffer), ac_buffer_size(&pBuilder->ac_buffer));
pBuilder->ac_buffer.data = pBuilder->data;
}

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file buffer_reader.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#include "acore/ac_buffer_reader.h"
#include "acore/ac_macros.h"
#include "string.h"
#define VOID
#define ENSURE_READ_LENGTH(pBuf, n) do{ if( ac_buffer_reader_readable(pBuf) < n ) { return; } }while(0);
static inline void update_buf(ac_buffer_t *pBuf)
{
while (ac_buffer_size(pBuf) == 0) {
if (ac_buffer_next(pBuf) != NULL) {
ac_buffer_t *pNext = ac_buffer_next(pBuf);
ac_buffer_init(pBuf, ac_buffer_data(pNext), ac_buffer_size(pNext));
pBuf->pNext = ac_buffer_next(pNext);
} else if (pBuf->data != NULL) {
ac_buffer_init(pBuf, NULL, 0);
} else {
return;
}
}
}
void ac_buffer_read_be(ac_buffer_t *pBuf, uint8_t *buf, size_t size)
{
ENSURE_READ_LENGTH(pBuf, size);
buf += size;
while (size > 0) {
buf--;
*buf = *ac_buffer_data(pBuf);
pBuf->data++;
pBuf->size--;
update_buf(pBuf);
size--;
}
}
void ac_buffer_read_le(ac_buffer_t *pBuf, uint8_t *buf, size_t size)
{
ENSURE_READ_LENGTH(pBuf, size);
while (size > 0) {
size_t cpy = ac_buffer_size(pBuf);
cpy = MIN(cpy, size);
memcpy(buf, ac_buffer_data(pBuf), cpy);
pBuf->data += cpy;
pBuf->size -= cpy;
update_buf(pBuf);
size -= cpy;
buf += cpy;
}
}
void ac_buffer_read_n_skip(ac_buffer_t *pBuf, size_t size)
{
ENSURE_READ_LENGTH(pBuf, size);
while (size > 0) {
size_t cpy = ac_buffer_size(pBuf);
cpy = MIN(cpy, size);
pBuf->data += cpy;
pBuf->size -= cpy;
update_buf(pBuf);
size -= cpy;
}
}
size_t ac_buffer_reader_readable(const ac_buffer_t *pBuf)
{
size_t r = 0;
while (pBuf != NULL) {
r += ac_buffer_size(pBuf);
pBuf = ac_buffer_next(pBuf);
}
return r;
}
const uint8_t *ac_buffer_reader_current_buffer_pointer(ac_buffer_t *pBuf)
{
update_buf(pBuf);
return ac_buffer_data(pBuf);
}
size_t ac_buffer_reader_current_buffer_length(ac_buffer_t *pBuf)
{
update_buf(pBuf);
return ac_buffer_size(pBuf);
}
bool ac_buffer_reader_cmp_bytes(const ac_buffer_t *pBuf, const uint8_t *bytes, size_t length)
{
ac_buffer_t reader;
if (length > ac_buffer_reader_readable(pBuf)) {
return false;
}
ac_buffer_dup(&reader, pBuf);
while (length > 0) {
size_t sz = ac_buffer_reader_current_buffer_length(&reader);
if (sz > length) {
sz = length;
}
int c = memcmp(ac_buffer_reader_current_buffer_pointer(&reader), bytes, sz);
if (c) {
return false;
}
length -= sz;
bytes += sz;
ac_buffer_read_n_skip(&reader, sz);
}
return true;
}
bool ac_buffer_reader_cmp(const ac_buffer_t *pBuf1, const ac_buffer_t *pBuf2)
{
ac_buffer_t reader1;
ac_buffer_t reader2;
if (ac_buffer_reader_readable(pBuf1) != ac_buffer_reader_readable(pBuf2)) {
return false;
}
ac_buffer_dup(&reader1, pBuf1);
ac_buffer_dup(&reader2, pBuf2);
size_t length = ac_buffer_reader_readable(pBuf1);
while (length > 0) {
size_t sz1 = ac_buffer_reader_current_buffer_length(&reader1);
size_t sz2 = ac_buffer_reader_current_buffer_length(&reader2);
size_t sz = MIN(sz1, sz2);
int c = memcmp(ac_buffer_reader_current_buffer_pointer(&reader1), ac_buffer_reader_current_buffer_pointer(&reader2), sz);
if (c) {
return false;
}
length -= sz;
ac_buffer_read_n_skip(&reader1, sz);
ac_buffer_read_n_skip(&reader2, sz);
}
return true;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file stream.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#include "acore/ac_stream.h"
#include "acore/ac_macros.h"
//Called by supplier
void ac_istream_init(ac_istream_t *pac_istream, ac_istream_fn fn, void *pUserParam)
{
pac_istream->fn = fn;
pac_istream->pUserParam = pUserParam;
}
//Called by consumer
void ac_istream_pull(ac_istream_t *pac_istream, ac_buffer_t *pDataIn, bool *pClose, size_t maxLength)
{
pac_istream->fn(pDataIn, pClose, maxLength, pac_istream->pUserParam);
}
//Called by consumer
void ac_ostream_init(ac_ostream_t *pac_ostream, ac_ostream_fn fn, void *pUserParam)
{
pac_ostream->fn = fn;
pac_ostream->pUserParam = pUserParam;
}
//Called by supplier
void ac_ostream_push(ac_ostream_t *pac_ostream, ac_buffer_t *pDataOut, bool closed)
{
pac_ostream->fn(pDataOut, closed, pac_ostream->pUserParam);
}

View File

@ -0,0 +1,51 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PN512_DRIVER_H
#define MBED_PN512_DRIVER_H
#include <stdint.h>
#include "nfc/NFCControllerDriver.h"
#include "PN512TransportDriver.h"
#include "nfc/acore/acore/ac_buffer.h"
#include "nfc/acore/acore/ac_buffer_reader.h"
#include "nfc/acore/acore/ac_buffer_builder.h"
#include "nfc/stack/transceiver/pn512/pn512.h"
namespace mbed {
namespace nfc {
class PN512Driver : public NFCControllerDriver, private PN512TransportDriver::Delegate {
public:
PN512Driver(PN512TransportDriver *transport_driver);
virtual nfc_transceiver_t *initialize(nfc_scheduler_timer_t *scheduler_timer);
virtual void get_supported_nfc_techs(nfc_tech_t *initiator, nfc_tech_t *target) const;
private:
// PN512TransportDriver::Delegate implementation
virtual void on_hw_interrupt();
PN512TransportDriver *_transport_driver;
pn512_t _pn512;
};
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,58 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PN512_SPI_TRANSPORT_DRIVER_H
#define MBED_PN512_SPI_TRANSPORT_DRIVER_H
#include <stdint.h>
#include "platform/platform.h"
#include "platform/nfc_transport.h"
#include "PN512TransportDriver.h"
#include "drivers/SPI.h"
#include "drivers/DigitalOut.h"
#include "drivers/InterruptIn.h"
namespace mbed {
namespace nfc {
class PN512SPITransportDriver : public PN512TransportDriver {
public:
PN512SPITransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName irq, PinName rst);
private:
virtual void initialize();
virtual nfc_transport_t *get_transport();
void transport_write(uint8_t address, const uint8_t *outBuf, size_t outLen);
void transport_read(uint8_t address, uint8_t *inBuf, size_t inLen);
// Callbacks from munfc
static void s_transport_write(uint8_t address, const uint8_t *outBuf, size_t outLen, void *pUser);
static void s_transport_read(uint8_t address, uint8_t *inBuf, size_t inLen, void *pUser);
nfc_transport_t _nfc_transport;
mbed::SPI _spi;
mbed::DigitalOut _ssel;
mbed::InterruptIn _irq;
mbed::DigitalOut _rst;
};
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,86 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PN512_TRANSPORT_DRIVER_H
#define MBED_PN512_TRANSPORT_DRIVER_H
#include <stdint.h>
#include "stack/platform/nfc_transport.h"
namespace mbed {
namespace nfc {
/**
* The PN512 supports multiple transport mechanisms (SPI, I2C, UART): this class provides a unified API across these transports
*/
class PN512TransportDriver {
public:
/**
* The PN512TransportDriver delegate
*/
struct Delegate {
/**
* Called when the PN512 asserts the interrupt line
*/
virtual void on_hw_interrupt() {}
protected:
~Delegate() {}
};
/**
* Create a PN512TransportDriver instance
*/
PN512TransportDriver();
/**
* PN512TransportDriver destructor.
*/
virtual ~PN512TransportDriver();
/**
* Initialize transport driver and perform a chip reset
*/
virtual void initialize() = 0;
/**
* Retrieve the nfc_transport_t struct for the stack to use
*
* @return a pointer to a nfc_transport_t struct
*/
virtual nfc_transport_t *get_transport() = 0;
/**
* Set this instance's delegate
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate *delegate);
protected:
/**
* An implementation must call this function (can be called from interrupt context)
* when the PN512 asserts its interrupt line
*/
void hw_interrupt();
private:
Delegate *_delegate;
};
} // namespace nfc
} // namespace mbed
#endif

31
features/nfc/nfc/NFC.h Normal file
View File

@ -0,0 +1,31 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_H
#define MBED_NFC_H
// Convenience header
// NFC Controller
#include "NFCController.h"
// NFC EEPROM
#include "NFCEEPROM.h"
// Type 4 Remote Initiator
#include "Type4RemoteInitiator.h"
#endif

View File

@ -0,0 +1,189 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_CONTROLLER_H
#define MBED_NFC_CONTROLLER_H
#include <stdint.h>
#include "events/EventQueue.h"
#include "platform/SharedPtr.h"
#include "drivers/Timer.h"
#include "drivers/Timeout.h"
#include "NFCDefinitions.h"
#include "NFCControllerDriver.h"
#include "platform/Span.h"
namespace mbed {
namespace nfc {
class NFCRemoteInitiator;
class NFCRemoteTarget;
class NFCControllerDriver;
/**
* @addtogroup nfc
* @{
*/
/**
* This class represents a NFC Controller.
*
* A controller can be in one of three different states:
* * Idle/sleep state
* * Discovery state: The controller tries to discover a remote endpoint (initiator or target)
* * Connected state: The controller exchanges data with an endpoint (initiator or target)
*
* A NFCController instance needs to be initialized with a NFCControllerDriver instance which abstracts the specific controller being used.
* A delegate needs to be set by the user to receive discovery events.
*/
class NFCController : private NFCControllerDriver::Delegate {
public:
/**
* The NFCController delegate. Users of the NFCController class need to implement this delegate's methods to receive events.
*/
struct Delegate {
/**
* A enumeration of causes for the discovery process terminating.
*/
enum nfc_discovery_terminated_reason_t {
nfc_discovery_terminated_completed = 0, ///< Process completed, at least one endpoint was discovered
nfc_discovery_terminated_canceled, ///< Process was canceled by the user
nfc_discovery_terminated_rf_error ///< An unexpected error was encountered during an exchange on the air interface
};
/**
* The discovery process terminated.
* @param[in] reason the cause for the termination
*/
virtual void on_discovery_terminated(nfc_discovery_terminated_reason_t reason) {}
/**
* A remote initiator was discovered (the local controller is in target mode).
* @param[in] nfc_initiator the NFCRemoteInitiator instance
*/
virtual void on_nfc_initiator_discovered(const SharedPtr<NFCRemoteInitiator> &nfc_initiator) {}
/**
* A remote target was discovered (the local controller is in initiator mode).
* @param[in] nfc_target the NFCRemoteTarget instance
*/
virtual void on_nfc_target_discovered(const SharedPtr<NFCRemoteTarget> &nfc_target) {}
protected:
~Delegate() { }
};
/**
* Construct a NFCController instance.
*
* @param[in] driver a pointer to a NFCControllerDriver instance
* @param[in] queue a pointer to the events queue to use
* @param[in] ndef_buffer a bytes array used to store NDEF messages
*/
NFCController(NFCControllerDriver *driver, events::EventQueue *queue, const Span<uint8_t> &ndef_buffer);
/**
* Initialize the NFC controller
*
* This method must be called before any other method call.
*
* @return NFC_OK, or an error.
*/
nfc_err_t initialize();
/**
* Set the delegate that will receive events generated by this controller.
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate *delegate);
/**
* Get the list of RF protocols supported by this controller.
*
* @return a bitmask of RF protocols supported by the controller
*/
nfc_rf_protocols_bitmask_t get_supported_rf_protocols() const;
/**
* Set the list of RF protocols to look for during discovery.
*
* @param[in] rf_protocols the relevant bitmask
* @return NFC_OK on success, or
* NFC_ERR_UNSUPPORTED if a protocol is not supported by the controller,
* NFC_ERR_BUSY if the discovery process is already running
*/
nfc_err_t configure_rf_protocols(nfc_rf_protocols_bitmask_t rf_protocols);
/**
* Start the discovery process using the protocols configured previously.
*
* If remote endpoints are connected when this is called, they will be disconnected.
*
* @return NFC_OK on success, or
* NFC_ERR_BUSY if the discovery process is already running
*/
nfc_err_t start_discovery();
/**
* Cancel/stop a running discovery process.
*
* @return NFC_OK
*/
nfc_err_t cancel_discovery();
private:
// These two classes need to be friends to access the following transceiver() method
friend class NFCRemoteEndpoint;
friend class Type4RemoteInitiator;
nfc_transceiver_t *transceiver() const;
void polling_callback(nfc_err_t ret);
// NFC Stack scheduler
void scheduler_process(bool hw_interrupt);
// Callbacks from NFC stack
static void s_polling_callback(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData);
// Implementation of NFCControllerDriver::Delegate
virtual void on_hw_interrupt();
// Triggers when scheduler must be run again
void on_timeout();
NFCControllerDriver *_driver;
events::EventQueue *_queue;
nfc_transceiver_t *_transceiver;
nfc_scheduler_t *_scheduler;
Timer _timer;
Timeout _timeout;
Delegate *_delegate;
bool _discovery_running;
Span<uint8_t> _ndef_buffer;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,104 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_CONTROLLER_DRIVER_H
#define MBED_NFC_CONTROLLER_DRIVER_H
#include <stdint.h>
#include "events/EventQueue.h"
#include "stack/nfc_errors.h"
#include "stack/transceiver/transceiver.h"
#include "stack/platform/nfc_scheduler.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
/**
* The abstraction for a NFC controller driver.
* Implementers need to derive from this class and implement its methods.
*/
class NFCControllerDriver {
public:
/**
* Instantiate a NFCControllerDriver
*/
NFCControllerDriver();
/**
* NFCControllerDriver destructor
*/
virtual ~NFCControllerDriver();
/**
* The NFCControllerDriver delegate
*/
struct Delegate {
/**
* Called when the controller asserts the interrupt line
*/
virtual void on_hw_interrupt() {}
protected:
~Delegate() {}
};
/**
* Initialize the driver and retrieve the interface to the controller.
*
* @param[in] scheduler_timer a timer to initialize the controller's scheduler instance with
* @return an initialized MicroNFC nfc_transceiver_t instance
*/
virtual nfc_transceiver_t *initialize(nfc_scheduler_timer_t *scheduler_timer) = 0;
/**
* Retrieve list of technologies supported by the controller
* @param[out] initiator bitmask of technologies supported when the controller is in initiator mode
* @param[out] target bitmask of technologies supported when the controller is in target mode
*/
virtual void get_supported_nfc_techs(nfc_tech_t *initiator, nfc_tech_t *target) const = 0;
/**
* Set this instance's delegate
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate *delegate);
protected:
/**
* An implementation must call this function (can be called from interrupt context)
* when the controller asserts its interrupt line
*/
void hw_interrupt();
private:
Delegate *_delegate;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,57 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_DEFINITIONS_H
#define MBED_NFC_DEFINITIONS_H
#include <stdint.h>
#include <stdbool.h>
#include "stack/nfc_errors.h"
#include "acore/ac_buffer.h"
namespace mbed {
namespace nfc {
struct nfc_rf_protocols_bitmask_t {
bool initiator_t1t : 1;
bool initiator_t2t : 1;
bool initiator_t3t : 1;
bool initiator_iso_dep : 1;
bool initiator_nfc_dep : 1;
bool initiator_t5t : 1;
bool target_t1t : 1;
bool target_t2t : 1;
bool target_t3t : 1;
bool target_iso_dep : 1;
bool target_nfc_dep : 1;
bool target_t5t : 1;
};
enum nfc_tag_type_t {
nfc_tag_type_1,
nfc_tag_type_2,
nfc_tag_type_3,
nfc_tag_type_4a,
nfc_tag_type_4b,
nfc_tag_type_5
};
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,164 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_EEPROM_H
#define MBED_NFC_EEPROM_H
#include <stdint.h>
#include "events/EventQueue.h"
#include "NFCDefinitions.h"
#include "NFCTarget.h"
#include "NFCEEPROMDriver.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
/**
* The NFC EEPROM class represents a NFC target device connected using a wired
* link (I2C, SPI, etc).
*
* These EEPROMs essentially provide addressable memory that can be accessed
* using either a wired or NFC interface.
*
* In NFC mode these most often conform to one of the NFC tag types defined
* by the NFC Forum, therefore encoding NDEF data in these EEPROMs will
* ensure that it is understandable by a NFC reader.
*/
class NFCEEPROM : public NFCTarget, public NFCEEPROMDriver::Delegate {
public:
/**
* Construct a NFCEEPROM instance.
*
* @param[in] driver a pointer to a NFCEEPROMDriver instance
* @param[in] queue a pointer to the events queue to use
* @param[in] ndef_buffer a bytes array used to store NDEF messages
*/
NFCEEPROM(NFCEEPROMDriver *driver, events::EventQueue *queue, const Span<uint8_t> &ndef_buffer);
/**
* The NFCEEPROM delegate. Users of the NFCEEPROM class need to implement this delegate's methods to receive events.
*/
struct Delegate : NFCTarget::Delegate {
/**
* The NDEF message erasing request completed.
*
* @param[in] result NFC_OK or an error code on failure
*/
virtual void on_ndef_message_erased(nfc_err_t result) {}
/**
* The NDEF message writing request completed.
*
* @param[in] result NFC_OK or an error code on failure
*/
virtual void on_ndef_message_written(nfc_err_t result) {}
/**
* The NDEF message reading request completed.
*
* @param[in] result NFC_OK or an error code on failure
*/
virtual void on_ndef_message_read(nfc_err_t result) {}
protected:
~Delegate() {}
};
/**
* Initialize the NFC EEPROM
*
* This method must be called before any other method call.
*
* @return NFC_OK, or an error.
*/
nfc_err_t initialize();
/**
* Set the delegate that will receive events generated by this EEPROM.
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate *delegate);
// Implementation of NFCTarget
virtual void write_ndef_message();
virtual void read_ndef_message();
virtual void erase_ndef_message();
private:
// Implementation of NFCEEPROMDriver::Delegate
virtual void on_session_started(bool success);
virtual void on_session_ended(bool success);
virtual void on_bytes_read(size_t count);
virtual void on_bytes_written(size_t count);
virtual void on_size_written(bool success);
virtual void on_size_read(bool success, size_t size);
virtual void on_bytes_erased(size_t count);
void handle_error(nfc_err_t ret);
void continue_write();
void continue_read();
void continue_erase();
// NFCNDEFCapable implementation
virtual NFCNDEFCapable::Delegate *ndef_capable_delegate();
enum nfc_eeprom_operation_t {
nfc_eeprom_idle,
nfc_eeprom_write_start_session,
nfc_eeprom_write_write_bytes,
nfc_eeprom_write_write_size,
nfc_eeprom_write_end_session,
nfc_eeprom_read_start_session,
nfc_eeprom_read_read_size,
nfc_eeprom_read_read_bytes,
nfc_eeprom_read_end_session,
nfc_eeprom_erase_start_session,
nfc_eeprom_erase_write_max_size,
nfc_eeprom_erase_erase_bytes,
nfc_eeprom_erase_write_0_size,
nfc_eeprom_erase_end_session
};
Delegate *_delegate;
NFCEEPROMDriver *_driver;
bool _initialized;
nfc_eeprom_operation_t _current_op;
ac_buffer_t _ndef_buffer_reader;
size_t _ndef_buffer_read_sz;
uint32_t _eeprom_address;
nfc_err_t _operation_result;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,203 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_EEPROM_DRIVER_H
#define MBED_NFC_EEPROM_DRIVER_H
#include <stdint.h>
#include "events/EventQueue.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
/**
* The abstraction for a NFC EEPROM driver.
* Implementers need to derive from this class and implement its methods.
*/
class NFCEEPROMDriver {
public:
/**
* Construct a NFCEEPROM driver instance.
*/
NFCEEPROMDriver();
/**
* NFCEEPROM driver destructor.
*/
virtual ~NFCEEPROMDriver();
/**
* The NFCEEPROMDriver delegate.
* Methods in this class are called by the driver on completion of long-running operations.
*/
struct Delegate {
/**
* Completion of session start operation.
*
* @param[in] success whether this operation succeeded
*/
virtual void on_session_started(bool success) = 0;
/**
* Completion of session end operation.
*
* @param[in] success whether this operation succeeded
*/
virtual void on_session_ended(bool success) = 0;
/**
* Completion of read operation.
*
* @param[in] count number of bytes actually read
*/
virtual void on_bytes_read(size_t count) = 0;
/**
* Completion of write operation.
*
* @param[in] count number of bytes actually written
*/
virtual void on_bytes_written(size_t count) = 0;
/**
* Completion of size retrieval operation.
*
* @param[in] success whether this operation succeeded
* @param[out] size the current addressable memory size
*/
virtual void on_size_read(bool success, size_t size) = 0;
/**
* Completion of size setting operation.
*
* @param[in] success whether this operation succeeded
*/
virtual void on_size_written(bool success) = 0;
/**
* Completion of erasing operation.
*
* @param[in] count number of bytes actually erased
*/
virtual void on_bytes_erased(size_t count) = 0;
protected:
~Delegate() {}
};
/**
* Set the delegate that will receive events generated by this EEPROM.
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate *delegate);
/**
* Set the event queue that will be used to schedule event handling
*
* @param[in] queue the queue instance to use
*/
void set_event_queue(events::EventQueue *queue);
/**
* Reset and initialize the EEPROM.
* This method should complete synchronously.
*/
virtual void reset() = 0;
/**
* Get the maximum memory size addressable by the EEPROM.
*/
virtual size_t read_max_size() = 0;
/**
* Start a session of operations (reads, writes, erases, size gets/sets).
* This method is called prior to any memory access to allow the underlying implementation
* to disable the RF interface or abort the transaction if it's being used.
* This method should complete asynchronously by calling has_started_session().
*/
virtual void start_session(bool force = true) = 0; // This could lock the chip's RF interface
/**
* End a session.
* This method should complete asynchronously by calling has_ended_session().
*/
virtual void end_session() = 0;
/**
* Read bytes from memory.
* @param[in] address the virtual address (starting from 0) from which to start the read.
* @param[out] bytes a buffer in which the read bytes will be stored.
* This buffer should remain valid till the callback is called.
* @param[in] count the number of bytes to read.
* This method should complete asynchronously by calling has_read_bytes().
*/
virtual void read_bytes(uint32_t address, uint8_t *bytes, size_t count) = 0;
/**
* Write bytes to memory.
* @param[in] address the virtual address (starting from 0) from which to start the write.
* @param[in] bytes a buffer from to copy.
* This buffer should remain valid till the callback is called.
* @param[in] count the number of bytes to write.
* This method should complete asynchronously by calling has_written_bytes().
*/
virtual void write_bytes(uint32_t address, const uint8_t *bytes, size_t count) = 0;
/**
* Retrieve the size of the addressable memory.
* This method should complete asynchronously by calling has_gotten_size().
*/
virtual void read_size() = 0;
/**
* Set the size of the addressable memory.
* @param[in] count the number of addressable bytes.
* This method should complete asynchronously by calling has_set_size().
*/
virtual void write_size(size_t count) = 0;
/**
* Erase bytes from memory.
* @param[in] address the virtual address (starting from 0) from which to start erasing.
* @param[in] size the number of bytes to erase.
* This method should complete asynchronously by calling has_erased_bytes().
*/
virtual void erase_bytes(uint32_t address, size_t size) = 0;
protected:
Delegate *delegate();
events::EventQueue *event_queue();
private:
Delegate *_delegate;
events::EventQueue *_event_queue;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,130 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_NDEF_CAPABLE_H
#define MBED_NFC_NDEF_CAPABLE_H
#include <stdint.h>
#include "platform/Span.h"
#include "NFCDefinitions.h"
#include "nfc/stack/ndef/ndef.h"
#include "nfc/acore/acore/ac_buffer.h"
#include "nfc/acore/acore/ac_buffer_reader.h"
#include "nfc/acore/acore/ac_buffer_builder.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
/**
* The base class for all endpoints that can support NDEF content.
*/
class NFCNDEFCapable {
public:
/**
* Construct a NFCNDEFCapable instance.
* @param[in] buffer a bytes array used to store NDEF messages
*/
NFCNDEFCapable(const Span<uint8_t> &buffer);
/**
* Check if this instance actually supports NDEF content.
*
* @return whether NDEF content is supported
*/
virtual bool is_ndef_supported() const
{
return false;
}
struct Delegate {
/**
* Parse a NDEF message.
*
* @param[in] buffer a buffer containing the message to parse
*/
virtual void parse_ndef_message(const Span<const uint8_t> &buffer) { }
/**
* Build a NDEF message.
*
* @param[in] buffer a mutable buffer in which the message should be stored
*
* @return the number of bytes actually used
*/
virtual size_t build_ndef_message(const Span<uint8_t> &buffer)
{
return 0;
}
protected:
~Delegate() {}
};
protected:
/**
* Parse a NDEF message.
*
* @param[in] buffer a buffer containing a NDEF message
*/
void parse_ndef_message(const ac_buffer_t &buffer);
/**
* Build NDEF message.
*
* @param[in,out] buffer_builder a buffer builder in which to create the NDEF message.
* The backing buffer is guaranteed to be continuous.
*/
void build_ndef_message(ac_buffer_builder_t &buffer_builder);
/**
* Retrieve underlying NDEF message instance
* @return pointer to NDEF message instance
*/
ndef_msg_t *ndef_message();
private:
/**
* Get the delegate that will receive events generated by this class.
*
* @return the delegate instance to use
*/
virtual Delegate *ndef_capable_delegate();
// Callbacks from NDEF stack
static nfc_err_t s_ndef_encode(ndef_msg_t *pTag, ac_buffer_builder_t *pBufferBldr, void *pUserData);
static nfc_err_t s_ndef_decode(ndef_msg_t *pTag, ac_buffer_t *pBuffer, void *pUserData);
nfc_err_t ndef_encode(ac_buffer_builder_t *pBufferBldr);
nfc_err_t ndef_decode(ac_buffer_t *pBuffer);
ndef_msg_t _ndef_message;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,135 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_REMOTE_ENDPOINT_H
#define MBED_NFC_REMOTE_ENDPOINT_H
#include <stdint.h>
#include "NFCDefinitions.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
class NFCController;
/**
* This is the base class for all remote endpoints (initiators and targets)
* addressable over the air interface.
*/
class NFCRemoteEndpoint {
public:
/**
* Create a NFCRemoteEndpointinstance
* @param[in] controller the NFCController instance that detected this endpoint
*/
NFCRemoteEndpoint(NFCController *controller);
/**
* Destructor
*/
virtual ~NFCRemoteEndpoint();
/**
* The NFCRemoteEndpoint base delegate.
*/
struct Delegate {
/**
* This method is called when the endpoint is connected
*/
virtual void on_connected() {}
/**
* This method is called when the endpoint is lost (air interface link disconnnected)
*/
virtual void on_disconnected() {}
protected:
~Delegate() {}
};
/**
* Connect the remote endpoint
*
* @return NFC_OK or an error code
*/
virtual nfc_err_t connect() = 0;
/**
* Disconnect the remote endpoint
*
* @return NFC_OK or an error code
*/
virtual nfc_err_t disconnect() = 0;
/**
* Check if the endpoint is connected.
* @return whether the endpoint is connected
*/
virtual bool is_connected() const = 0;
/**
* Check if the endpoint is disconnected/lost.
* @return whether the endpoint has been disconnected
*/
virtual bool is_disconnected() const = 0;
/**
* Get the list of RF protocols supported and activated over the air interface.
* @return a bitmask of activated protocols
*/
virtual nfc_rf_protocols_bitmask_t rf_protocols() = 0;
protected:
/**
* Mark endpoint as connected
*/
virtual void connected() = 0;
/**
* Mark endpoint as disconnected
*/
virtual void disconnected() = 0;
/**
* Retrieve NFCController instance
* @return a pointer to the NFController instance that created this endpoint.
*/
NFCController *nfc_controller();
/**
* Retrieve NFCController instance
* @return a pointer to the NFController instance that created this endpoint.
*/
const NFCController *nfc_controller() const;
private:
NFCController *_controller;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,108 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_REMOTE_INITIATOR_H
#define MBED_NFC_REMOTE_INITIATOR_H
#include <stdint.h>
#include "NFCDefinitions.h"
#include "NFCRemoteEndpoint.h"
#include "NFCNDEFCapable.h"
#include "stack/tech/iso7816/iso7816_app.h"
#include "platform/Span.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
class NFCController;
/**
* This class represents a remote NFC initiator (the local controller being in target mode).
*
* An initiator can be a NFC reader, a NFC-enabled phone or other NFC device capable of generating a RF field.
*/
class NFCRemoteInitiator : public NFCRemoteEndpoint, public NFCNDEFCapable {
public:
/**
* Create a NFCRemoteInitiator.
* @param[in] controller the NFCController instance that detected this endpoint
* @param[in] buffer a bytes array used to store NDEF messages
*/
NFCRemoteInitiator(NFCController *controller, const Span<uint8_t> &buffer);
virtual ~NFCRemoteInitiator();
/**
* The NFCRemoteInitiator delegate. Users of the NFCRemoteInitiator class need to implement this delegate's methods to receive events.
*/
struct Delegate : NFCRemoteEndpoint::Delegate, NFCNDEFCapable::Delegate {
protected:
~Delegate() {}
};
/**
* Set the delegate that will receive events generated by the initiator.
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate *delegate);
/**
* Retrieve the NFC tag type exposed by the controller to communicate with the initiator.
*
* @return the relevant NFC tag type
*/
virtual nfc_tag_type_t nfc_tag_type() const = 0;
/**
* Retrieve whether ISO7816 applications are supported by the underlying technology.
*
* @return whether ISO7816 applications are supported
*/
virtual bool is_iso7816_supported() const = 0;
/**
* Register an ISO7816 application to be used by the initiator.
*
* @param[in] application a pointer to an nfc_tech_iso7816_app_t instance as defined by the MuNFC stack
*/
virtual void add_iso7816_application(nfc_tech_iso7816_app_t *application) = 0;
protected:
virtual void connected();
virtual void disconnected();
private:
// NFCNDEFCapable implementation
virtual NFCNDEFCapable::Delegate *ndef_capable_delegate();
Delegate *_delegate;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,109 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_TARGET_H
#define MBED_NFC_TARGET_H
#include <stdint.h>
#include "NFCDefinitions.h"
#include "NFCNDEFCapable.h"
#include "platform/Span.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
/**
* This class represents a NFC target (either a remote target when the local controller in in initiator mode, or a target connected through a wired connection).
*
* A target can be a NFC tag/card, a NFC-enabled phone or other NFC device capable of modulating a RF field.
*/
class NFCTarget : public NFCNDEFCapable {
public:
/**
* Create a NFCTarget.
*
* @param[in] buffer a bytes array used to store NDEF messages
*/
NFCTarget(const Span<uint8_t> &buffer);
/**
* NFCTarget destructor
*/
virtual ~NFCTarget();
struct Delegate : NFCNDEFCapable::Delegate {
/**
* The NDEF message erasing request completed.
*
* @param[in] result NFC_OK or an error code on failure
*/
virtual void on_ndef_message_erased(nfc_err_t result) {}
/**
* The NDEF message writing request completed.
*
* @param[in] result NFC_OK or an error code on failure
*/
virtual void on_ndef_message_written(nfc_err_t result) {}
/**
* The NDEF message reading request completed.
*
* @param[in] result NFC_OK or an error code on failure
*/
virtual void on_ndef_message_read(nfc_err_t result) {}
protected:
~Delegate() {}
};
/**
* Write a NDEF message to the target.
*
* on_ndef_message_written() will be called on completion.
*/
virtual void write_ndef_message() = 0;
/**
* Read a NDEF message from the target.
*
* on_ndef_message_read() will be called on completion.
*/
virtual void read_ndef_message() = 0;
/**
* Erase the NDEF message in the target.
*
* on_ndef_message_erased() will be called on completion.
*/
virtual void erase_ndef_message() = 0;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,91 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_TYPE4_REMOTE_INITIATOR_H
#define MBED_TYPE4_REMOTE_INITIATOR_H
#include <stdint.h>
#include <stddef.h>
#include "NFCNDEFCapable.h"
#include "NFCRemoteInitiator.h"
#include "nfc/acore/acore/ac_buffer.h"
#include "nfc/acore/acore/ac_buffer_reader.h"
#include "nfc/acore/acore/ac_buffer_builder.h"
#include "nfc/stack/tech/type4/type4_target.h"
#include "platform/Span.h"
namespace mbed {
namespace nfc {
/**
* @addtogroup nfc
* @{
*/
/**
* This class is an implementation of the Type 4 tag application.
*/
class Type4RemoteInitiator : public NFCRemoteInitiator {
public:
/**
* Create a Type4RemoteInitiator.
*
* @param[in] controller pointer to the NFCController instance that created this object
* @param[in] buffer a bytes array used to store NDEF messages
*/
Type4RemoteInitiator(NFCController *controller, const Span<uint8_t> &buffer);
/**
* Type4RemoteInitiator destructor.
*/
virtual ~Type4RemoteInitiator();
// NFCRemoteEndpoint implementation
virtual nfc_err_t connect();
virtual nfc_err_t disconnect();
virtual bool is_connected() const;
virtual bool is_disconnected() const;
virtual nfc_rf_protocols_bitmask_t rf_protocols();
// NFCRemoteInitiator implementation
virtual nfc_tag_type_t nfc_tag_type() const;
virtual bool is_iso7816_supported() const;
virtual void add_iso7816_application(nfc_tech_iso7816_app_t *application);
// NFCNDEFCapable implementation
virtual bool is_ndef_supported() const;
// Callbacks from NFC stack
void disconnected_callback();
static void s_disconnected_callback(nfc_tech_iso7816_t *pIso7816, void *pUserData);
bool _is_connected;
bool _is_disconnected;
nfc_tech_iso7816_t _iso7816;
nfc_tech_type4_target_t _type4;
};
/**
* @}
*/
} // namespace nfc
} // namespace mbed
#endif

View File

@ -0,0 +1,201 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_NDEF_MESSAGEBUILDER_H_
#define NFC_NDEF_MESSAGEBUILDER_H_
#include <stdint.h>
#include "platform/Span.h"
#include "nfc/ndef/Record.h"
namespace mbed {
namespace nfc {
namespace ndef {
/**
* @addtogroup nfc
* @{
*/
/**
* Construct a NDEF Message.
*/
class MessageBuilder {
public:
/**
* Build a record payload.
*/
struct PayloadBuilder {
/**
* Return the size of the payload built by this object.
*
* @return The size of the payload.
*/
virtual size_t size() const = 0;
/**
* Build the payload in a buffer that has the required size.
*
* @param buffer The buffer used to construct the payload.
*/
virtual void build(const Span<uint8_t> &buffer) const = 0;
protected:
/**
* Non virtual destructor.
*/
~PayloadBuilder() { }
};
/**
* Create a new MessageBuilder that can be used to construct valid NDEF
* messages.
*
* @param buffer The data buffer that will contain the NDEF message.
*/
MessageBuilder(const Span<uint8_t> &buffer);
/**
* Append a new record to the message being built.
*
* @param type The type of the record to insert.
* @param payload The payload of the record (optional).
* @param is_last_record true if the record to insert is the last record of
* the payload or false otherwise.
*
* @return true if the record has been successfully inserted or false
* otherwise.
*
* @note insertion can fail if the message is already complete or if the
* size remaining in the message buffer is not large enough to makes the
* record inserted fit.
*/
bool append_record(
const RecordType &type,
const RecordPayload &payload = RecordPayload(),
bool is_last_record = false
);
/**
* Append a new record to the message being built.
*
* @param type The type of the record to insert.
* @param builder The builder of the payload.
* @param is_last_record true if the record to insert is the last record of
* the payload or false otherwise.
*
* @return true if the record has been successfully inserted or false
* otherwise.
*
* @note insertion can fail if the message is already complete or if the
* size remaining in the message buffer is not large enough to makes the
* record inserted fit.
*/
bool append_record(
const RecordType &type,
const PayloadBuilder &builder,
bool is_last_record = false
);
/**
* Append a new record to the message being built.
*
* @param record The record to insert.
* @param builder The builder that will construct the payload.
*
* @return true if the record has been successfully inserted or false otherwise.
*
* @note insertion can fail if the message is already complete or if the
* size remaining in the message buffer is not large enough to makes the
* record inserted fit.
*/
bool append_record(
const Record &record,
const PayloadBuilder *builder = NULL
);
/**
* Compute the size of a record.
*
* @param record The record used to compute the size.
* @param builder The payload builder if any.
*
* @return The size of the payload for the record in input.
*/
static size_t compute_record_size(
const Record &record,
const PayloadBuilder *builder = NULL
);
/**
* Reset the builder state.
*/
void reset();
/**
* Reset the builder state and assign a new buffer to it.
*/
void reset(const Span<uint8_t> &buffer);
/**
* Return true if the message stored is complete and false otherwise.
*
* @return true if the message is complete or false.
*/
bool is_message_complete() const;
/**
* Return the buffer storing the data if the message is complete or an empty
* buffer if the message is not complete.
*
* @return The message built.
*/
Span<const uint8_t> get_message() const;
private:
// append fields
void append_header(const Record &record, const PayloadBuilder *);
void append_type_length(const Record &record);
void append_payload_length(const Record &, const PayloadBuilder *);
void append_id_length(const Record &);
void append_type(const Record &);
void append_id(const Record &);
void append_payload(const Record &, const PayloadBuilder *);
// helpers
static bool is_short_payload(const Record &record, const PayloadBuilder *);
static size_t get_payload_size(const Record &, const PayloadBuilder *);
// builder state.
Span<uint8_t> _message_buffer;
size_t _position;
bool _message_started;
bool _message_ended;
bool _in_chunk;
};
/**
* @}
*/
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_NDEF_MESSAGEBUILDER_H_ */

View File

@ -0,0 +1,178 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_NDEF_MESSAGEPARSER_H_
#define NFC_NDEF_MESSAGEPARSER_H_
#include <stdlib.h>
#include "platform/Span.h"
namespace mbed {
namespace nfc {
namespace ndef {
/**
* @addtogroup nfc
* @{
*/
// Forward declaration
class Record;
/**
* Event driven NDEF Message parser
*/
class MessageParser {
public:
/**
* Error that can be reported by the parsing operation.
*/
enum error_t {
/**
* The message doesn't start with a message start tag.
*/
INVALID_MESSAGE_START,
/**
* There is not enough data left to pursue parsing of the message.
*/
INSUFICIENT_DATA,
/**
* The type name of a record is invalid.
*/
INVALID_TYPE_NAME_FORMAT,
/**
* An empty record is malformed.
*/
INVALID_EMPTY_RECORD,
/**
* Record of unknown type embed a type length different than 0.
*/
INVALID_UNKNOWN_TYPE_LENGTH,
/**
* Record of unchanged type contains a type.
*/
INVALID_UNCHANGED_TYPE,
/**
* Chunk record encountered.
*/
CHUNK_RECORD_NOT_SUPPORTED,
/**
* Message is not properly closed.
*/
MISSING_MESSAGE_END,
/**
* Type is missing in a record expecting a type (well known type, media
* type, absolute uri or external type).
*/
MISSING_TYPE_VALUE
};
/**
* Report parsing event to the application.
*/
struct Delegate {
/**
* Invoked when parsing as started.
*/
virtual void on_parsing_started() { }
/**
* Invoked when a record has been parsed.
*
* @param record The record obtained from parsing.
*/
virtual void on_record_parsed(const Record &record) { }
/**
* Invoked when parsing is over.
*/
virtual void on_parsing_terminated() { }
/**
* Invoked when an error is present in the message.
* @param error The error present in the message.
*/
virtual void on_parsing_error(error_t error) { }
protected:
/**
* Protected non virtual destructor.
* Delegate is not meant to be destroyed in a polymorphic manner.
*/
~Delegate() { }
};
/**
* Construct a message parser.
*/
MessageParser();
/**
* Set the handler that processes parsing events.
* @param delegate The parsing event handler.
*/
void set_delegate(Delegate *delegate);
/**
* Parse an NDEF Message.
*
* Records and errors are reported to the handler registered with
* set_event_handler.
*
* @param data_buffer The data buffer that contains the NDEF message.
*/
void parse(const Span<const uint8_t> &data_buffer);
private:
struct parsing_state_t;
// parser
bool parse_record(parsing_state_t &it);
static uint8_t compute_lengths_size(uint8_t header);
static uint8_t extract_type_length(parsing_state_t &s);
static uint32_t extract_payload_length(parsing_state_t &s, uint8_t header);
static uint8_t extract_id_length(parsing_state_t &s, uint8_t header);
// reporting
void report_parsing_started();
void report_record_parsed(const Record &record);
void report_parsing_terminated();
void report_parsing_error(error_t error, parsing_state_t &parsing_state);
Delegate *_delegate;
};
/**
* @}
*/
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_NDEF_MESSAGEPARSER_H_ */

View File

@ -0,0 +1,216 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_NDEF_RECORD_H_
#define NFC_NDEF_RECORD_H_
#include <stdint.h>
#include "platform/Span.h"
namespace mbed {
namespace nfc {
namespace ndef {
/**
* @addtogroup nfc
* @{
*/
/**
* Set of constants of a record header
*/
struct Header {
static const uint8_t message_begin_bit = (1 << 7);
static const uint8_t message_end_bit = (1 << 6);
static const uint8_t chunk_flag_bit = (1 << 5);
static const uint8_t short_record_bit = (1 << 4);
static const uint8_t id_length_bit = (1 << 3);
static const uint8_t tnf_bits = (1 << 0) | (1 << 1) | (1 << 2);
};
/**
* Encode a record type.
*
* A RecordType is composed of a type name format flag and an optional type
* value.
*/
struct RecordType {
/**
* Type name format of a record.
*/
enum tnf_t {
/**
* empty type; value must be empty.
*/
empty = 0x00, //!< empty
/**
* Type defined by the NFC forum; value must be defined.
*/
well_known_type = 0x01,//!< well_known_type
/**
* Mime type; value must be defined.
*/
media_type = 0x02, //!< media_type
/**
* Absolute URI; value must be defined.
*/
absolute_uri = 0x03, //!< absolute_uri
/**
* Type defined by vendors; value must be defined.
*/
external_type = 0x04, //!< external_type
/**
* Unknown type; value must be empty.
*/
unknown = 0x05, //!< unknown
/**
* Use for middle and terminating chunk record.
* value must be empty.
*/
unchanged = 0x06 //!< unchanged
};
/**
* Construct an unknown type.
*/
RecordType() : tnf(unknown), value() { }
/**
* Construct a type with no value.
*
* @note Valid tnf are: empty, unknown and unchanged.
*
* @param tnf The type name format of the type.
*/
RecordType(tnf_t tnf) :
tnf(tnf), value()
{ }
/**
* Construct a RecordType from a type name format and its associated value.
*
* @param tnf The type name format of the record type.
* @param value The value associated with the tnf.
*/
RecordType(tnf_t tnf, const Span<const uint8_t> &value) :
tnf(tnf), value(value)
{ }
/**
* Type name format of the record type.
*/
tnf_t tnf;
/**
* Value associated with the record type. It can be empty.
*/
Span<const uint8_t> value;
};
/**
* Definition of a Record payload.
*
* @note A payload can be empty.
*/
typedef Span<const uint8_t> RecordPayload;
/**
* Definition of a Record IR.
*
* @note ID's are optional and therefore it can be empty.
*/
typedef Span<const uint8_t> RecordID;
/**
* Represent a record.
*/
struct Record {
/**
* Construct an empty record.
*/
Record() : type(), payload(), id(), chunk(false), last_record(false) { }
/**
* Construct a record from its type, payload and id.
*
* The flags chunk and last_record can be added to indicate if the record
* is aprt of a chunk or the last one in a message.
*
* @param type The type of the record.
* @param payload The payload of the record.
* @param id The id associated with the record.
* @param chunk If true then this record is a chunk of a bigger record.
* @param last_record If true then this record is the last of the message
* containing it.
*/
Record(
RecordType type,
const RecordPayload &payload,
const RecordID &id,
bool chunk,
bool last_record
) :
type(type),
payload(payload),
id(id),
chunk(chunk),
last_record(last_record)
{ }
/**
* Type of the record.
*/
RecordType type;
/**
* Value of the payload.
*/
RecordPayload payload;
/**
* ID of the record.
*/
RecordID id;
/**
* If true, this record is a chunked record.
*/
bool chunk: 1;
/**
* If true, this record is the last one of the payload containing it.
*/
bool last_record: 1;
};
/**
* @}
*/
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_NDEF_RECORD_H_ */

View File

@ -0,0 +1,172 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_NDEF_RECORDPARSER_H_
#define NFC_NDEF_RECORDPARSER_H_
#include <stddef.h>
#include "nfc/ndef/Record.h"
namespace mbed {
namespace nfc {
namespace ndef {
/**
* @addtogroup nfc
* @{
*/
/**
* Parse a record.
*/
struct RecordParser {
/**
* Construct a record parser.
*/
RecordParser() : _next_parser(NULL) { }
/**
* Parse the record in input.
* @param record The NDEF record to parse.
* @return true if decoding has succeeded and false otherwise.
*/
virtual bool parse(const Record &record) = 0;
protected:
/**
* Protected non virtual destructor.
* RecordParser subclasses are not meant to be destroyed as RecordParser's.
*/
~RecordParser() { }
private:
friend class RecordParserChain;
RecordParser *_next_parser;
};
/**
* GenericRecordParser.
*
* @tparam ParserImplementation the implementation type of the parser.
* It must provides A decoding function named do_parse that accept a const
* reference to a record and a reference to the type parsed and return a boolean
* status that indicates the result of the parsing operation.
*
* @tparam ParsingResult Type produced by the parsing operation when successful.
*/
template<typename ParserImplementation, typename ParsingResult>
struct GenericRecordParser : public RecordParser {
/**
* Handle that receives parsed values.
*/
struct Delegate {
/**
* Called when a record has been parsed and converted into a value_type.
*
* @param object_parsed The record in its parsed form.
* @param id The RecordId associated with the object parsed.
*/
virtual void on_record_parsed(const ParsingResult &object_parsed, const RecordID &id) = 0;
protected:
~Delegate() { }
};
/**
* Construct a record parser.
*/
GenericRecordParser() : _delegate(NULL) { }
/**
* @see RecordParser::parse
*/
virtual bool parse(const Record &record)
{
ParsingResult parsed_value;
if (static_cast<ParserImplementation *>(this)->do_parse(record, parsed_value)) {
if (_delegate) {
_delegate->on_record_parsed(parsed_value, record.id);
}
return true;
}
return false;
}
/**
* Set the delegate that processes record parser.
*
* @param delegate The delegate to set.
*/
void set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
protected:
/**
* Protected non virtual destructor.
*/
~GenericRecordParser() { }
private:
Delegate *_delegate;
};
/**
* Record parser chain.
*/
struct RecordParserChain {
/**
* Construct a parser chain.
*/
RecordParserChain() : _parsers(NULL) { }
/**
* Destroy a parser chain.
*/
~RecordParserChain() { }
/**
* Parse a record.
* @param record The record to parse.
* @return true if the record has been parsed and false otherwise.
*/
bool parse(const Record &record);
/**
* Add a parser at the end of the parser list.
* @param parser The parser to add.
*/
void set_next_parser(RecordParser *parser);
private:
RecordParser *_parsers;
};
/**
* @}
*/
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_NDEF_RECORDPARSER_H_ */

View File

@ -0,0 +1,155 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_COMMON_MIME_H_
#define NFC_COMMON_MIME_H_
#include <stdint.h>
#include "platform/Span.h"
#include "nfc/ndef/RecordParser.h"
#include "nfc/ndef/MessageBuilder.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
/**
* @addtogroup nfc
* @{
*/
/**
* Represent a mime object.
*/
class Mime {
public:
/**
* Construct an empty Mime object.
*/
Mime();
/**
* Construct a mime object from its type and content
*
* @param mime_type The mime type of the object.
* @param content The content of the object.
*
* @note To remove the NULL terminator of the C-string of the mime_type
* parameter, you can use the utility function span_from_cstr.
*/
Mime(
const Span<const uint8_t> &mime_type,
const Span<const uint8_t> &content
);
/**
* Copy construct a Mime object.
* @param other The Mime object copied.
*/
Mime(const Mime &other);
/**
* Destroy a Mime object.
*/
~Mime();
/**
* Copy assign a Mime object.
*
* @param other The Mime object to copy.
*
* @return a reference to this object
*/
Mime &operator=(const Mime &other);
/**
* Set all attributes of a mime object.
*
* @param mime_type Type of the mime object.
* @param content Content of the mime object.
*
* @note To remove the NULL terminator of the C-string of the mime_type
* parameter, you can use the utility function span_from_cstr.
*/
void set_mime(
const Span<const uint8_t> &mime_type,
const Span<const uint8_t> &content
);
/**
* Return the mime type.
* @return The mime type.
*/
Span<const uint8_t> get_mime_type() const;
/**
* Return the content of the mime object.
* @return the content of the mime object.
*/
Span<const uint8_t> get_mime_content() const;
/**
* Append into a message builder
*/
bool append_as_record(
MessageBuilder &message_builder,
bool is_last_record = false
) const;
/**
* Compute the size of this Mime object in a ndef record.
*
* @return The size of the ndef record required to store this object.
*/
size_t get_record_size() const;
private:
friend class MimeParser;
void move_data(
uint8_t *mime_record,
size_t mime_type_size,
size_t mime_content_size
);
size_t mime_size() const;
uint8_t *_mime;
size_t _type_size;
size_t _content_size;
};
/**
* Parse a Mime payload.
*/
class MimeParser : public GenericRecordParser<MimeParser, Mime> {
public:
bool do_parse(const Record &record, Mime &mime);
};
/**
* @}
*/
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_COMMON_MIME_H_ */

View File

@ -0,0 +1,174 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_COMMON_SIMPLEMESSAGEPARSER_H_
#define NFC_COMMON_SIMPLEMESSAGEPARSER_H_
#include "platform/Span.h"
#include "nfc/ndef/MessageParser.h"
#include "nfc/ndef/RecordParser.h"
#include "nfc/ndef/common/URI.h"
#include "nfc/ndef/common/Text.h"
#include "nfc/ndef/common/Mime.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
/**
* @addtogroup nfc
* @{
*/
/**
* Basic message parser that aggregates URIParser, TextParser and MimeParser.
*
* Custom parsers can be added at runtime as well.
*/
class SimpleMessageParser :
MessageParser::Delegate,
URIParser::Delegate,
TextParser::Delegate,
MimeParser::Delegate {
public:
/**
* Delegate invoked when the parser raise an event.
*/
struct Delegate {
/**
* Invoked when an error is present in the message.
* @param error The error present in the message.
*/
virtual void on_parsing_error(MessageParser::error_t error) { }
/**
* Invoked when parsing as started.
*/
virtual void on_parsing_started() { }
/**
* Invoked when a text element has been parsed.
*
* @param text The text parsed.
* @param id The RecordId of the text object.
*/
virtual void on_text_parsed(const Text &text, const RecordID &id) { }
/**
* Invoked when a text element has been parsed.
*
* @param uri The uri parsed.
* @param id The RecordId of the uri object.
*/
virtual void on_uri_parsed(const URI &uri, const RecordID &id) { }
/**
* Invoked when a mime element has been parsed.
*
* @param mime The mime object parsed.
* @param id The RecordId of the mime object.
*/
virtual void on_mime_parsed(const Mime &mime, const RecordID &id) { }
/**
* Invoked when an unknown record has been parsed.
* @param record The record freshly parsed.
*/
virtual void on_unknown_record_parsed(const Record &record) { }
/**
* Invoked when parsing is over.
*/
virtual void on_parsing_terminated() { }
protected:
~Delegate() { }
};
/**
* Construct a new CommonMessageParser.
*/
SimpleMessageParser();
/**
* Set the handler that processes parsing events.
* @param delegate The parsing event handler.
*/
void set_delegate(Delegate *delegate);
/**
* Parse an NDEF Message.
*
* Records and errors are reported to the handler registered with
* set_event_handler.
*
* @param data_buffer The data buffer that contains the NDEF message.
*/
void parse(const Span<const uint8_t> &data_buffer);
/**
* Insert a new parser in the parser chain.
* @param parser The parser to add in the parsing chain.
*/
void add_record_parser(RecordParser *parser);
private:
////////////////////////////////////////////////////////////////////////////
/// Implementation of MessageParser::EventHandler
virtual void on_parsing_error(MessageParser::error_t error);
virtual void on_parsing_started();
virtual void on_record_parsed(const Record &record);
virtual void on_parsing_terminated();
////////////////////////////////////////////////////////////////////////////
/// Implementation of URIParser::EventHandler
virtual void on_record_parsed(const URI &uri, const RecordID &id);
////////////////////////////////////////////////////////////////////////////
/// Implementation of TextParser::EventHandler
virtual void on_record_parsed(const Text &text, const RecordID &id);
////////////////////////////////////////////////////////////////////////////
/// Implementation of MimeParser::EventHandler
virtual void on_record_parsed(const Mime &mime, const RecordID &id);
MessageParser _message_parser;
RecordParserChain _record_parser_chain;
URIParser _uri_parser;
TextParser _text_parser;
MimeParser _mime_parser;
Delegate *_delegate;
};
/**
* @}
*/
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_COMMON_SIMPLEMESSAGEPARSER_H_ */

View File

@ -0,0 +1,165 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_COMMON_TEXT_H_
#define NFC_COMMON_TEXT_H_
#include <stdint.h>
#include "platform/Span.h"
#include "nfc/ndef/RecordParser.h"
#include "nfc/ndef/MessageBuilder.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
/**
* @addtogroup nfc
* @{
*/
/**
* Represent the well known type text.
*/
class Text {
public:
/**
* Encoding of the text.
*/
enum encoding_t {
UTF8 = 0,//!< UTF8
UTF16 = 1//!< UTF16
};
/**
* Construct an empty text element.
*/
Text();
/**
* Construct a text element from a data buffer and an encoding.
*
* @param text_encoding The encoding of the text.
* @param language_code The string of the language code.
* @param text The text buffer.
*
* @note To remove the NULL terminator of the C-string of the language_code
* and text parameters, you can use the utility function span_from_cstr.
*/
Text(
encoding_t text_encoding,
const Span<const uint8_t> &language_code,
const Span<const uint8_t> &text
);
/**
* Copy construct a text element.
* @param to_copy
*/
Text(const Text &to_copy);
/**
* Destroy a text element.
*/
~Text();
/**
* Copy assignment of another text element.
* @param to_copy The Text instance to copy
* @return a reference to this object.
*/
Text &operator=(const Text &to_copy);
/**
* Copy a text from an external buffer.
*
* @param text_encoding The encoding of the text.
* @param language_code The language code of the text.
* @param text The text to copy.
*
* @note To remove the NULL terminator of the C-string of the language_code
* and text parameters, you can use the utility function span_from_cstr.
*/
void set_text(
encoding_t text_encoding,
const Span<const uint8_t> &language_code,
const Span<const uint8_t> &text
);
/**
* Get the encoding of the text.
* @return The encoding of the text.
*/
encoding_t get_encoding() const;
/**
* Return the language code.
* @return The language code.
*/
Span<const uint8_t> get_language_code() const;
/**
* Return the text contained in this object.
* @return The text contained in this object.
*/
Span<const uint8_t> get_text() const;
/**
* Append into a message builder
*/
bool append_as_record(
MessageBuilder &message_builder,
bool is_last_record = false
) const;
/**
* Compute the size of this object in a ndef record.
*
* @return The size of the ndef record required to store this object.
*/
size_t get_record_size() const;
private:
friend class TextParser;
void move_data(uint8_t *text, size_t size);
uint8_t *_text_record;
size_t _text_record_size;
};
/**
* Parse a Text.
*/
class TextParser : public GenericRecordParser<TextParser, Text> {
public:
virtual bool do_parse(const Record &record, Text &text);
};
/**
* @}
*/
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_COMMON_TEXT_H_ */

View File

@ -0,0 +1,206 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NFC_COMMON_URI_H_
#define NFC_COMMON_URI_H_
#include <stdint.h>
#include <string.h>
#include "platform/Span.h"
#include "nfc/ndef/RecordParser.h"
#include "nfc/ndef/MessageBuilder.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
/**
* @addtogroup nfc
* @{
*/
/**
* Model the well known type URI.
*/
class URI {
public:
/**
* Identifier codes
*/
enum uri_identifier_code_t {
NA = 0x00, /// Not applicable
HTTP_WWW = 0x01, /// http://www.
HTTPS_WWW = 0x02, /// https://www.
HTTP = 0x03, /// http://
HTTPS = 0x04, /// https://
TEL = 0x05, /// tel:
MAILTO = 0x06, /// mailto:
FTP_ANONYMOUS = 0x07, /// ftp://anonymous:anonymous@
FTP_FTP = 0x08, /// ftp://ftp.
FTPS = 0x09, /// ftps://
SFTP = 0x0A, /// sftp://
SMB = 0x0B, /// smb://
NFS = 0x0C, /// nfs://
FTP = 0x0D, /// ftp://
DAV = 0x0E, /// dav://
NEWS = 0x0F, /// news:
TELNET = 0x10, /// telnet://
IMAP = 0x11, /// imap:
RSTP = 0x12, /// rstp://
URN = 0x13, /// urn:
POP = 0x14, /// pop:
SIP = 0x15, /// sip:
SIPS = 0x16, /// sips:
TFTP = 0x17, /// tftp:
BTSPP = 0x18, /// btspp://
BTL2CAP = 0x19, /// btl2cap://
BTGOEP = 0x1A, /// btgoep://
TCPOBEX = 0x1B, /// tcpobex://
IRDAOBEX = 0x1C, /// irdaobex://
FILE = 0x1D, /// file://
URN_EPC_ID = 0x1E, /// urn:epc:id:
URN_EPC_TAG = 0x1F, /// urn:epc:tag:
URN_EPC_PAT = 0x20, /// urn:epc:pat:
URN_EPC_RAW = 0x21, /// urn:epc:raw:
URN_EPC = 0x22, /// urn:epc:
URN_NFC = 0x23, /// urn:nfc:
};
/**
* Construct an empty URI object.
*/
URI();
/**
* Construct a URI from an id and a uri field.
*
* @param id The code of the URI prefix.
* @param uri_field The URI itself.
*
* @note To remove the NULL terminator of the C-string of the uri_field
* parameter, you can use the utility function span_from_cstr.
*/
URI(uri_identifier_code_t id, const Span<const uint8_t> &uri_field);
/**
* Construct a URI from another URI.
* @param to_copy The uri copied.
*/
URI(const URI &to_copy);
/**
* Destroy a URI object.
*/
~URI();
/**
* Replace the content by the one of an existing URI.
* @param to_copy The URI to copy.
* @return a reference to this object
*/
URI &operator=(const URI &to_copy);
/**
* Replace the value of the URI.
*
* @param id The ID of the URI
* @param uri_field A buffer containing the value of the URI field.
*
* @note To remove the NULL terminator of the C-string of the uri_field
* parameter, you can use the utility function span_from_cstr.
*/
void set_uri(
uri_identifier_code_t id,
const Span<const uint8_t> &uri_field
);
/**
* Return the id of the uri.
* @return The id of the uri.
*/
uri_identifier_code_t get_id() const;
/**
* Return the current value of the uri field.
* @return The value of the uri field.
*/
Span<const uint8_t> get_uri_field() const;
/**
* Append into a message builder
*/
bool append_as_record(
MessageBuilder &message_builder,
bool is_last_record = false
) const;
/**
* Compute the size of this object in a ndef record.
*
* @return The size of the ndef record required to store this object.
*/
size_t get_record_size() const;
/**
* Equal operator between two URIs
* @param lhs The URI on the left hand side
* @param rhs The URI on the right hand side
* @return true if lhs equals rhs or false.
*/
friend bool operator==(const URI &lhs, const URI &rhs)
{
if (lhs._uri_size != rhs._uri_size) {
return false;
}
return memcmp(lhs._uri, rhs._uri, lhs._uri_size) == 0;
}
friend bool operator!=(const URI &lhs, const URI &rhs)
{
return !(lhs == rhs);
}
private:
friend class URIParser;
void move_data(uint8_t *text, size_t size);
uint8_t *_uri;
size_t _uri_size;
};
/**
* Parser of a URI.
*/
class URIParser : public GenericRecordParser<URIParser, URI> {
public:
bool do_parse(const Record &record, URI &uri);
};
/**
* @}
*/
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* NFC_COMMON_URI_H_ */

View File

@ -0,0 +1,69 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FEATURES_NFC_SOURCE_NFC_COMMON_UTIL_H_
#define FEATURES_NFC_SOURCE_NFC_COMMON_UTIL_H_
#include "platform/Span.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
/**
* @addtogroup nfc
* @{
*/
/**
* Convert a C-string into a Span<const uint8_t>.
*
* @note The NULL charactere is not present in the resulting object.
*
* @param cstr The cstr to convert into a Span.
*
* @return A Span that views cstr but doesn't include the NULL terminator
* character.
*/
template<size_t N>
Span < const uint8_t, N - 1 > span_from_cstr(const char (&cstr)[N])
{
return Span < const uint8_t, N - 1 > ((const uint8_t *)cstr, N - 1);
}
/**
* Convert a C-string into a Span<const uint8_t>.
*
* @note The NULL charactere is not present in the resulting object.
*
* @param cstr The cstr to convert into a Span.
*
* @return A Span that views cstr but doesn't include the NULL terminator
* character.
*/
Span<const uint8_t> span_from_cstr(const char *cstr);
/**
* @}
*/
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed
#endif /* FEATURES_NFC_SOURCE_NFC_COMMON_UTIL_H_ */

View File

@ -0,0 +1,68 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PN512Driver.h"
#include "nfc/stack/platform/nfc_debug.h"
using namespace mbed;
using namespace mbed::nfc;
PN512Driver::PN512Driver(PN512TransportDriver *transport_driver) : NFCControllerDriver(), _transport_driver(transport_driver)
{
_transport_driver->set_delegate(this);
}
nfc_transceiver_t *PN512Driver::initialize(nfc_scheduler_timer_t *scheduler_timer)
{
// Initialize transport
_transport_driver->initialize();
nfc_err_t ret = pn512_init(&_pn512, _transport_driver->get_transport(), scheduler_timer);
if (ret != NFC_OK) {
NFC_ERR("PN512 init error (%d)", ret);
return NULL;
}
NFC_DBG("PN512 Initialized");
return pn512_get_transceiver(&_pn512);
}
void PN512Driver::get_supported_nfc_techs(nfc_tech_t *initiator, nfc_tech_t *target) const
{
initiator->nfc_type1 = 0;
initiator->nfc_type2 = 1;
initiator->nfc_type3 = 1;
initiator->nfc_iso_dep_a = 1;
initiator->nfc_iso_dep_b = 0;
initiator->nfc_nfc_dep_a = 1;
initiator->nfc_nfc_dep_f_212 = 1;
initiator->nfc_nfc_dep_f_424 = 1;
target->nfc_type1 = 0;
target->nfc_type2 = 0;
target->nfc_type3 = 0;
target->nfc_iso_dep_a = 1;
target->nfc_iso_dep_b = 0;
target->nfc_nfc_dep_a = 1;
target->nfc_nfc_dep_f_212 = 1;
target->nfc_nfc_dep_f_424 = 1;
}
void PN512Driver::on_hw_interrupt()
{
hw_interrupt(); // Propagate interrupt signal
}

View File

@ -0,0 +1,117 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform/platform.h"
#if (defined (DEVICE_SPI) && defined (DEVICE_INTERRUPTIN)) || defined(DOXYGEN_ONLY)
#include "PN512SPITransportDriver.h"
#include "stack/transceiver/transceiver.h"
#include "platform/mbed_wait_api.h"
using namespace mbed;
using namespace mbed::nfc;
PN512SPITransportDriver::PN512SPITransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName irq, PinName rst) :
_spi(mosi, miso, sclk),
_ssel(ssel, 1),
_irq(irq, PullNone),
_rst(rst, 1)
{
// Use SPI mode 0
_spi.format(8, 0);
// The PN512 supports SPI clock frequencies up to 10MHz, so use this if we can
_spi.frequency(10000000UL);
// Initialize NFC transport
nfc_transport_init(&_nfc_transport, &PN512SPITransportDriver::s_transport_write, &PN512SPITransportDriver::s_transport_read, this);
}
void PN512SPITransportDriver::initialize()
{
// Deactivate IRQ
_irq.rise(callback<void>());
// Assert reset pin
// According to the datasheet, it needs to be asserted for at least 100ns
// Wait for 1us as that's the shortest time we can wait for
_rst = 0;
wait_us(1);
_rst = 1;
// Setup IRQ pin
_irq.rise(callback(this, &PN512SPITransportDriver::hw_interrupt));
}
nfc_transport_t *PN512SPITransportDriver::get_transport()
{
return &_nfc_transport;
}
void PN512SPITransportDriver::transport_write(uint8_t address, const uint8_t *outBuf, size_t outLen)
{
if (outLen == 0) {
return;
}
// First byte is (address << 1) | 0x00 for a write
address = (address << 1) | 0x00;
_ssel = 0;
_spi.write(address); // First write address byte
_spi.write((const char *) outBuf, outLen, (char *) NULL, 0); // Ignore read bytes
_ssel = 1;
}
void PN512SPITransportDriver::transport_read(uint8_t address, uint8_t *inBuf, size_t inLen)
{
if (inLen == 0) {
return;
}
// Address byte is (address << 1) | 0x80 for a read
// This should be repeated accross the transfer, except for the last byte which should be 0
address = (address << 1) | 0x80;
// Set this byte across inBuf so that it's repeated accross the transfer
// Bit cheeky, but will work
memset(inBuf, address, inLen - 1);
// Also terminate with 0 so that it's a no-op
inBuf[inLen - 1] = 0;
_ssel = 0;
_spi.write(address); // First write address byte
_spi.write((const char *) inBuf, inLen, (char *) inBuf, inLen);
_ssel = 1;
}
// Callbacks from munfc
void PN512SPITransportDriver::s_transport_write(uint8_t address, const uint8_t *outBuf, size_t outLen, void *pUser)
{
PN512SPITransportDriver *self = (PN512SPITransportDriver *)pUser;
self->transport_write(address, outBuf, outLen);
}
void PN512SPITransportDriver::s_transport_read(uint8_t address, uint8_t *inBuf, size_t inLen, void *pUser)
{
PN512SPITransportDriver *self = (PN512SPITransportDriver *)pUser;
self->transport_read(address, inBuf, inLen);
}
#endif

View File

@ -0,0 +1,42 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PN512TransportDriver.h"
using namespace mbed;
using namespace mbed::nfc;
PN512TransportDriver::PN512TransportDriver() : _delegate(NULL)
{
}
PN512TransportDriver::~PN512TransportDriver()
{
}
void PN512TransportDriver::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
void PN512TransportDriver::hw_interrupt()
{
if (_delegate != NULL) {
_delegate->on_hw_interrupt();
}
}

View File

@ -0,0 +1,236 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCController.h"
#include "NFCControllerDriver.h"
#include "Type4RemoteInitiator.h"
#include "stack/transceiver/transceiver.h"
using namespace mbed;
using namespace mbed::nfc;
NFCController::NFCController(NFCControllerDriver *driver, events::EventQueue *queue, const Span<uint8_t> &ndef_buffer) :
_driver(driver), _queue(queue), _transceiver(NULL), _scheduler(NULL), _delegate(NULL), _discovery_running(false), _ndef_buffer(ndef_buffer)
{
_driver->set_delegate(this);
}
nfc_err_t NFCController::initialize()
{
MBED_ASSERT(_transceiver == NULL); // Initialize should only be called once
_transceiver = _driver->initialize((nfc_scheduler_timer_t *)&_timer); // See implementation below
if (_transceiver == NULL) {
// Initialization error
return NFC_ERR_CONTROLLER; // Controller error
}
// Recover scheduler
_scheduler = transceiver_get_scheduler(_transceiver);
// Run scheduler for the first time
_queue->call(this, &NFCController::scheduler_process, false);
return NFC_OK;
}
void NFCController::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
nfc_rf_protocols_bitmask_t NFCController::get_supported_rf_protocols() const
{
// nfc_rf_protocols_bitmask_t is mapped on NFC Forum types, nfc_tech_t is mapped on the underlying RF techs
// We therefore need to convert these
nfc_rf_protocols_bitmask_t rf_protocols = {0};
nfc_tech_t initiator_tech;
nfc_tech_t target_tech;
_driver->get_supported_nfc_techs(&initiator_tech, &target_tech);
// Note: we only support ISO-DEP tag emulation in this release,
// so mask out all other protocols
// rf_protocols.initiator_t1t = initiator_tech.nfc_type1;
// rf_protocols.initiator_t2t = initiator_tech.nfc_type2;
// rf_protocols.initiator_t3t = initiator_tech.nfc_type3;
// rf_protocols.initiator_iso_dep = initiator_tech.nfc_iso_dep_a || initiator_tech.nfc_iso_dep_b;
// rf_protocols.initiator_nfc_dep = initiator_tech.nfc_nfc_dep_a || initiator_tech.nfc_nfc_dep_f_212 || initiator_tech.nfc_nfc_dep_f_424;
// rf_protocols.target_t1t = target_tech.nfc_type1;
// rf_protocols.target_t2t = target_tech.nfc_type2;
// rf_protocols.target_t3t = target_tech.nfc_type3;
rf_protocols.target_iso_dep = target_tech.nfc_iso_dep_a || target_tech.nfc_iso_dep_b;
// rf_protocols.target_nfc_dep = target_tech.nfc_nfc_dep_a || target_tech.nfc_nfc_dep_f_212 || target_tech.nfc_nfc_dep_f_424;
return rf_protocols;
}
nfc_err_t NFCController::configure_rf_protocols(nfc_rf_protocols_bitmask_t rf_protocols)
{
if (_discovery_running) {
// Cannot configure RF protocols if discovery is running
return NFC_ERR_BUSY;
}
// Map to NFC techs
nfc_tech_t initiator_tech = {0};
nfc_tech_t target_tech = {0};
// Note: we only support ISO-DEP tag emulation in this release,
// so mask out all other protocols
target_tech.nfc_iso_dep_a = target_tech.nfc_iso_dep_b = true;
// Configure polling options (no need to set bailing flags as we're only using target mode)
polling_options_t options = {0};
options.listen_for = -1; // Listen forever
transceiver_set_protocols(_transceiver, initiator_tech, target_tech, options);
return NFC_OK;
}
nfc_err_t NFCController::start_discovery()
{
if (_discovery_running) {
// Cannot start discovery if it's already running
return NFC_ERR_BUSY;
}
transceiver_poll(_transceiver, &NFCController::s_polling_callback, this /* use this as callback argument */);
return NFC_OK;
}
nfc_err_t NFCController::cancel_discovery()
{
if (!_discovery_running) {
return NFC_OK;
}
transceiver_abort(_transceiver);
return NFC_OK;
}
nfc_transceiver_t *NFCController::transceiver() const
{
return _transceiver;
}
void NFCController::polling_callback(nfc_err_t ret)
{
// Polling has completed
_discovery_running = false;
NFC_DBG("Polling finished with result %u", ret);
if (ret == NFC_OK) {
// Check if a remote initiator was detected and if so, instantiate it
if (!transceiver_is_initiator_mode(_transceiver)) {
nfc_tech_t active_tech = transceiver_get_active_techs(_transceiver);
if ((active_tech.nfc_iso_dep_a || active_tech.nfc_iso_dep_b) && (_delegate != NULL)) {
Type4RemoteInitiator *type4_remote_initiator_ptr = new (std::nothrow) Type4RemoteInitiator(this, _ndef_buffer);
if (type4_remote_initiator_ptr != NULL) {
SharedPtr<NFCRemoteInitiator> type4_remote_initiator(type4_remote_initiator_ptr);
_delegate->on_nfc_initiator_discovered(type4_remote_initiator);
}
}
}
}
if (_delegate != NULL) {
Delegate::nfc_discovery_terminated_reason_t reason;
// Map reason
switch (ret) {
case NFC_OK:
reason = Delegate::nfc_discovery_terminated_completed;
break;
case NFC_ERR_ABORTED:
reason = Delegate::nfc_discovery_terminated_canceled;
break;
default:
// Any other error code means there was an error during the discovery process
reason = Delegate::nfc_discovery_terminated_rf_error;
break;
}
_delegate->on_discovery_terminated(reason);
}
}
void NFCController::scheduler_process(bool hw_interrupt)
{
_timeout.detach(); // Cancel timeout - if it triggers, it's ok as we'll have an "early" iteration which will likely be a no-op
// Process stack events
uint32_t timeout = nfc_scheduler_iteration(_scheduler, hw_interrupt ? EVENT_HW_INTERRUPT : EVENT_NONE);
_timeout.attach(callback(this, &NFCController::on_timeout), timeout);
}
void NFCController::on_hw_interrupt()
{
// Run scheduler - this is called in interrupt context
_timeout.detach(); // Cancel timeout - if it triggers anyways, it's ok
_queue->call(this, &NFCController::scheduler_process, true);
}
void NFCController::on_timeout()
{
// Run scheduler - this is called in interrupt context
_queue->call(this, &NFCController::scheduler_process, false);
}
void NFCController::s_polling_callback(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData)
{
NFCController *self = (NFCController *) pUserData;
self->polling_callback(ret);
}
// Implementation nfc_scheduler_timer_t
void nfc_scheduler_timer_init(nfc_scheduler_timer_t *timer)
{
(void)timer; // This is a no-op
}
void nfc_scheduler_timer_start(nfc_scheduler_timer_t *timer)
{
Timer *mbed_timer = (Timer *)timer;
mbed_timer->start();
}
uint32_t nfc_scheduler_timer_get(nfc_scheduler_timer_t *timer)
{
Timer *mbed_timer = (Timer *)timer;
return (uint32_t)mbed_timer->read_ms();
}
void nfc_scheduler_timer_stop(nfc_scheduler_timer_t *timer)
{
Timer *mbed_timer = (Timer *)timer;
mbed_timer->stop();
}
void nfc_scheduler_timer_reset(nfc_scheduler_timer_t *timer)
{
Timer *mbed_timer = (Timer *)timer;
mbed_timer->reset();
}

View File

@ -0,0 +1,42 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCControllerDriver.h"
using namespace mbed;
using namespace mbed::nfc;
NFCControllerDriver::NFCControllerDriver() : _delegate(NULL)
{
}
NFCControllerDriver::~NFCControllerDriver()
{
}
void NFCControllerDriver::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
void NFCControllerDriver::hw_interrupt()
{
if (_delegate != NULL) {
_delegate->on_hw_interrupt();
}
}

View File

@ -0,0 +1,425 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCEEPROM.h"
#include "ndef/ndef.h"
using namespace mbed;
using namespace mbed::nfc;
NFCEEPROM::NFCEEPROM(NFCEEPROMDriver *driver, events::EventQueue *queue, const Span<uint8_t> &ndef_buffer) : NFCTarget(ndef_buffer),
_delegate(NULL), _driver(driver), _initialized(false), _current_op(nfc_eeprom_idle), _ndef_buffer_read_sz(0), _eeprom_address(0), _operation_result(NFC_ERR_UNKNOWN)
{
_driver->set_delegate(this);
_driver->set_event_queue(queue);
}
nfc_err_t NFCEEPROM::initialize()
{
MBED_ASSERT(_initialized == false); // Initialize should only be called once
// Initialize driver
_driver->reset();
_initialized = true;
return NFC_OK;
}
void NFCEEPROM::set_delegate(NFCEEPROM::Delegate *delegate)
{
_delegate = delegate;
}
void NFCEEPROM::write_ndef_message()
{
MBED_ASSERT(_initialized == true);
if (_current_op != nfc_eeprom_idle) {
if (_delegate != NULL) {
_delegate->on_ndef_message_written(NFC_ERR_BUSY);
}
return;
}
// First update NDEF message if required
ndef_msg_encode(ndef_message());
_current_op = nfc_eeprom_write_start_session;
// Retrieve reader
ac_buffer_dup(&_ndef_buffer_reader, ac_buffer_builder_buffer(ndef_msg_buffer_builder(ndef_message())));
// Check that NDEF message is not too big
if (ac_buffer_reader_readable(&_ndef_buffer_reader) > _driver->read_max_size()) {
handle_error(NFC_ERR_BUFFER_TOO_SMALL);
return;
}
// Reset EEPROM address
_eeprom_address = 0;
// Go through the steps!
_driver->start_session();
// 1 - Start session
// 2 - Write bytes (can be repeated)
// 3 - Set NDEF message size
// 4 - End session
}
void NFCEEPROM::read_ndef_message()
{
MBED_ASSERT(_initialized == true);
if (_current_op != nfc_eeprom_idle) {
if (_delegate != NULL) {
_delegate->on_ndef_message_written(NFC_ERR_BUSY);
}
return;
}
_current_op = nfc_eeprom_read_start_session;
// Reset EEPROM address
_eeprom_address = 0;
// Go through the steps!
_driver->start_session();
// 1 - Start session
// 2 - Get NDEF message size
// 3 - Read bytes (can be repeated)
// 4 - End session
}
void NFCEEPROM::erase_ndef_message()
{
// We don't want to take any risks, so erase the whole address space
// And set the message size to 0
MBED_ASSERT(_initialized == true);
if (_current_op != nfc_eeprom_idle) {
if (_delegate != NULL) {
_delegate->on_ndef_message_erased(NFC_ERR_BUSY);
}
return;
}
_current_op = nfc_eeprom_read_start_session;
// Reset EEPROM address
_eeprom_address = 0;
// Go through the steps!
_driver->start_session();
// 1 - Start session
// 2 - Set addressable size to the max
// 3 - Erase bytes (can be repeated)
// 4 - Set addressable size to 0
// 5 - End session
}
void NFCEEPROM::on_session_started(bool success)
{
switch (_current_op) {
case nfc_eeprom_write_start_session:
if (!success) {
handle_error(NFC_ERR_CONTROLLER); // An EEPROM is not really a controller but close enough
return;
}
_current_op = nfc_eeprom_write_write_bytes;
continue_write();
break;
case nfc_eeprom_read_start_session:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
_current_op = nfc_eeprom_read_read_size;
_driver->read_size();
break;
case nfc_eeprom_erase_start_session:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
_current_op = nfc_eeprom_erase_write_max_size;
_driver->write_size(_driver->read_max_size());
break;
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::on_session_ended(bool success)
{
switch (_current_op) {
case nfc_eeprom_write_end_session:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
_current_op = nfc_eeprom_idle;
if (_delegate != NULL) {
_delegate->on_ndef_message_written(_operation_result);
}
break;
case nfc_eeprom_read_end_session:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
_current_op = nfc_eeprom_idle;
// Try to parse the NDEF message
ndef_msg_decode(ndef_message());
if (_delegate != NULL) {
_delegate->on_ndef_message_read(_operation_result);
}
break;
case nfc_eeprom_erase_end_session:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
_current_op = nfc_eeprom_idle;
if (_delegate != NULL) {
_delegate->on_ndef_message_erased(_operation_result);
}
break;
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::on_bytes_read(size_t count)
{
switch (_current_op) {
case nfc_eeprom_read_read_bytes: {
if (count == 0) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// Discard bytes that were actually read and update address
_eeprom_address += count;
ac_buffer_builder_t *buffer_builder = ndef_msg_buffer_builder(ndef_message());
ac_buffer_builder_write_n_skip(buffer_builder, count);
// Continue reading
continue_read();
break;
}
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::on_bytes_written(size_t count)
{
switch (_current_op) {
case nfc_eeprom_write_write_bytes:
if (count == 0) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// Skip bytes that were actually written and update address
_eeprom_address += count;
ac_buffer_read_n_skip(&_ndef_buffer_reader, count);
// Continue writing
continue_write();
break;
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::on_size_written(bool success)
{
switch (_current_op) {
case nfc_eeprom_write_write_size:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// End session
_current_op = nfc_eeprom_write_end_session;
_operation_result = NFC_OK;
_driver->end_session();
break;
case nfc_eeprom_erase_write_max_size:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// Start erasing bytes
_current_op = nfc_eeprom_erase_erase_bytes;
continue_erase();
break;
case nfc_eeprom_erase_write_0_size:
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// End session
_current_op = nfc_eeprom_erase_end_session;
_operation_result = NFC_OK;
_driver->end_session();
break;
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::on_size_read(bool success, size_t size)
{
switch (_current_op) {
case nfc_eeprom_read_read_size: {
if (!success) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// Reset NDEF message buffer builder
ac_buffer_builder_t *buffer_builder = ndef_msg_buffer_builder(ndef_message());
ac_buffer_builder_reset(buffer_builder);
// Check that we have a big enough buffer to read the message
if (size > ac_buffer_builder_writable(buffer_builder)) {
// Not enough space, close session
_current_op = nfc_eeprom_read_end_session;
_operation_result = NFC_ERR_BUFFER_TOO_SMALL;
_driver->end_session();
return;
}
// Save size and reset address
_eeprom_address = 0;
_ndef_buffer_read_sz = size;
// Start reading bytes
_current_op = nfc_eeprom_read_read_bytes;
continue_read();
break;
}
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::on_bytes_erased(size_t count)
{
switch (_current_op) {
case nfc_eeprom_erase_erase_bytes:
if (count == 0) {
handle_error(NFC_ERR_CONTROLLER);
return;
}
// Update address
_eeprom_address += count;
// Continue erasing
continue_erase();
break;
default:
// Should not happen, state machine is broken or driver is doing something wrong
handle_error(NFC_ERR_UNKNOWN);
return;
}
}
void NFCEEPROM::continue_write()
{
if (ac_buffer_reader_readable(&_ndef_buffer_reader) > 0) {
// Continue writing
_driver->write_bytes(_eeprom_address, ac_buffer_reader_current_buffer_pointer(&_ndef_buffer_reader), ac_buffer_reader_current_buffer_length(&_ndef_buffer_reader));
} else {
// Now update size
_current_op = nfc_eeprom_write_write_size;
_driver->write_size(_eeprom_address);
}
}
void NFCEEPROM::continue_erase()
{
if (_eeprom_address < _driver->read_max_size()) {
// Continue erasing
_driver->erase_bytes(_eeprom_address, _driver->read_max_size() - _eeprom_address);
} else {
// Now update size
_current_op = nfc_eeprom_erase_write_0_size;
_driver->write_size(0);
}
}
void NFCEEPROM::continue_read()
{
if (_eeprom_address < _ndef_buffer_read_sz) {
// Continue reading
ac_buffer_builder_t *buffer_builder = ndef_msg_buffer_builder(ndef_message());
_driver->read_bytes(_eeprom_address, ac_buffer_builder_write_position(buffer_builder), _ndef_buffer_read_sz - _eeprom_address);
} else {
// Done, close session
_operation_result = NFC_OK;
_driver->end_session();
}
}
void NFCEEPROM::handle_error(nfc_err_t ret)
{
// Save & reset current op
nfc_eeprom_operation_t last_op = _current_op;
_current_op = nfc_eeprom_idle;
if (_delegate != NULL) {
if (last_op <= nfc_eeprom_write_end_session) {
_delegate->on_ndef_message_written(ret);
} else if (last_op <= nfc_eeprom_read_end_session) {
_delegate->on_ndef_message_read(ret);
} else if (last_op <= nfc_eeprom_erase_end_session) {
_delegate->on_ndef_message_erased(ret);
}
}
}
NFCNDEFCapable::Delegate *NFCEEPROM::ndef_capable_delegate()
{
return _delegate;
}

View File

@ -0,0 +1,50 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCEEPROMDriver.h"
using namespace mbed;
using namespace mbed::nfc;
NFCEEPROMDriver::NFCEEPROMDriver() : _delegate(NULL), _event_queue(NULL)
{
}
NFCEEPROMDriver::~NFCEEPROMDriver()
{
}
void NFCEEPROMDriver::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
void NFCEEPROMDriver::set_event_queue(events::EventQueue *queue)
{
_event_queue = queue;
}
NFCEEPROMDriver::Delegate *NFCEEPROMDriver::delegate()
{
return _delegate;
}
events::EventQueue *NFCEEPROMDriver::event_queue()
{
return _event_queue;
}

View File

@ -0,0 +1,85 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCNDEFCapable.h"
#include "acore/ac_buffer.h"
#include "acore/ac_buffer_reader.h"
#include "acore/ac_buffer_builder.h"
#include "ndef/ndef.h"
using namespace mbed;
using namespace mbed::nfc;
NFCNDEFCapable::NFCNDEFCapable(const Span<uint8_t> &buffer)
{
ndef_msg_init(&_ndef_message, s_ndef_encode, s_ndef_decode, buffer.data(), buffer.size(), this);
}
void NFCNDEFCapable::parse_ndef_message(const ac_buffer_t &buffer)
{
ac_buffer_t reader;
ac_buffer_dup(&reader, &buffer);
Delegate *delegate = ndef_capable_delegate();
if (delegate != NULL) {
delegate->parse_ndef_message(make_const_Span(ac_buffer_reader_current_buffer_pointer(&reader), ac_buffer_reader_current_buffer_length(&reader)));
}
}
void NFCNDEFCapable::build_ndef_message(ac_buffer_builder_t &buffer_builder)
{
Delegate *delegate = ndef_capable_delegate();
if (delegate != NULL) {
size_t count = delegate->build_ndef_message(make_Span(ac_buffer_builder_write_position(&buffer_builder), ac_buffer_builder_writable(&buffer_builder)));
ac_buffer_builder_write_n_skip(&buffer_builder, count);
}
}
nfc_err_t NFCNDEFCapable::s_ndef_encode(ndef_msg_t *pTag, ac_buffer_builder_t *pBufferBldr, void *pUserData)
{
NFCNDEFCapable *self = (NFCNDEFCapable *)pUserData;
return self->ndef_encode(pBufferBldr);
}
nfc_err_t NFCNDEFCapable::s_ndef_decode(ndef_msg_t *pTag, ac_buffer_t *pBuffer, void *pUserData)
{
NFCNDEFCapable *self = (NFCNDEFCapable *)pUserData;
return self->ndef_decode(pBuffer);
}
nfc_err_t NFCNDEFCapable::ndef_encode(ac_buffer_builder_t *pBufferBldr)
{
build_ndef_message(*pBufferBldr);
return NFC_OK;
}
nfc_err_t NFCNDEFCapable::ndef_decode(ac_buffer_t *pBuffer)
{
parse_ndef_message(*pBuffer);
return NFC_OK;
}
ndef_msg_t *NFCNDEFCapable::ndef_message()
{
return &_ndef_message;
}
NFCNDEFCapable::Delegate *NFCNDEFCapable::ndef_capable_delegate()
{
return NULL;
}

View File

@ -0,0 +1,60 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCRemoteEndpoint.h"
#include "NFCController.h"
#include "acore/ac_buffer.h"
#include "acore/ac_buffer_reader.h"
#include "acore/ac_buffer_builder.h"
#include "stack/transceiver/transceiver.h"
using namespace mbed;
using namespace mbed::nfc;
NFCRemoteEndpoint::NFCRemoteEndpoint(NFCController *controller) : _controller(controller)
{
}
NFCRemoteEndpoint::~NFCRemoteEndpoint()
{
}
nfc_rf_protocols_bitmask_t NFCRemoteEndpoint::rf_protocols()
{
nfc_rf_protocols_bitmask_t rf_protocols = {0};
nfc_tech_t active_tech = transceiver_get_active_techs(_controller->transceiver());
if (!transceiver_is_initiator_mode(_controller->transceiver())) {
// Note: We only support ISO-DEP for now
rf_protocols.target_iso_dep = active_tech.nfc_iso_dep_a || active_tech.nfc_iso_dep_b;
}
return rf_protocols;
}
NFCController *NFCRemoteEndpoint::nfc_controller()
{
return _controller;
}
const NFCController *NFCRemoteEndpoint::nfc_controller() const
{
return _controller;
}

View File

@ -0,0 +1,55 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCRemoteInitiator.h"
using namespace mbed;
using namespace mbed::nfc;
NFCRemoteInitiator::NFCRemoteInitiator(NFCController *controller, const Span<uint8_t> &buffer) :
NFCRemoteEndpoint(controller), NFCNDEFCapable(buffer), _delegate(NULL)
{
}
NFCRemoteInitiator::~NFCRemoteInitiator()
{
}
void NFCRemoteInitiator::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
void NFCRemoteInitiator::connected()
{
if (_delegate != NULL) {
_delegate->on_connected();
}
}
void NFCRemoteInitiator::disconnected()
{
if (_delegate != NULL) {
_delegate->on_disconnected();
}
}
NFCNDEFCapable::Delegate *NFCRemoteInitiator::ndef_capable_delegate()
{
return _delegate;
}

View File

@ -0,0 +1,31 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NFCTarget.h"
using namespace mbed;
using namespace mbed::nfc;
NFCTarget::NFCTarget(const Span<uint8_t> &buffer) :
NFCNDEFCapable(buffer)
{
}
NFCTarget::~NFCTarget()
{
}

View File

@ -0,0 +1,140 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Type4RemoteInitiator.h"
#include "NFCController.h"
#include "acore/ac_buffer.h"
#include "acore/ac_buffer_reader.h"
#include "acore/ac_buffer_builder.h"
#include "stack/transceiver/transceiver.h"
#include "stack/tech/iso7816/iso7816.h"
#include "stack/tech/iso7816/iso7816_app.h"
#include "stack/tech/type4/type4_target.h"
using namespace mbed;
using namespace mbed::nfc;
Type4RemoteInitiator::Type4RemoteInitiator(NFCController *controller, const Span<uint8_t> &buffer) :
NFCRemoteInitiator(controller, buffer),
_is_connected(false), _is_disconnected(false)
{
// Init ISO7816
nfc_tech_iso7816_init(&_iso7816, nfc_controller()->transceiver(), &Type4RemoteInitiator::s_disconnected_callback, this);
// Init Type 4 app
nfc_tech_type4_target_init(&_type4, &_iso7816, ndef_message());
}
Type4RemoteInitiator::~Type4RemoteInitiator()
{
}
nfc_err_t Type4RemoteInitiator::connect()
{
if (_is_connected) {
return NFC_ERR_BUSY;
}
if (_is_disconnected) {
return NFC_ERR_DISCONNECTED;
}
// Connect ISO7816 stack
nfc_tech_iso7816_connect(&_iso7816);
// Call callback as it's a synchronous API
connected();
return NFC_OK;
}
nfc_err_t Type4RemoteInitiator::disconnect()
{
if (!_is_connected) {
return NFC_OK;
}
if (_is_disconnected) {
return NFC_OK;
}
// Disconnect ISO7816 stack
nfc_tech_iso7816_disconnect(&_iso7816);
return NFC_OK;
}
bool Type4RemoteInitiator::is_connected() const
{
return _is_connected;
}
bool Type4RemoteInitiator::is_disconnected() const
{
return _is_disconnected;
}
nfc_rf_protocols_bitmask_t Type4RemoteInitiator::rf_protocols()
{
nfc_rf_protocols_bitmask_t rf_protocols = {0};
nfc_tech_t active_tech = transceiver_get_active_techs(nfc_controller()->transceiver());
if (!transceiver_is_initiator_mode(nfc_controller()->transceiver())) {
// We only support ISO-DEP
rf_protocols.target_iso_dep = active_tech.nfc_iso_dep_a || active_tech.nfc_iso_dep_b;
}
return rf_protocols;
}
nfc_tag_type_t Type4RemoteInitiator::nfc_tag_type() const
{
nfc_tech_t active_tech = transceiver_get_active_techs(nfc_controller()->transceiver());
if (active_tech.nfc_iso_dep_a) {
return nfc_tag_type_4a;
} else { // if(active_tech.nfc_iso_dep_b)
return nfc_tag_type_4b;
}
}
bool Type4RemoteInitiator::is_iso7816_supported() const
{
return true;
}
void Type4RemoteInitiator::add_iso7816_application(nfc_tech_iso7816_app_t *application)
{
nfc_tech_iso7816_add_app(&_iso7816, application);
}
bool Type4RemoteInitiator::is_ndef_supported() const
{
return true;
}
void Type4RemoteInitiator::disconnected_callback()
{
// Call disconnected callback
disconnected();
}
void Type4RemoteInitiator::s_disconnected_callback(nfc_tech_iso7816_t *pIso7816, void *pUserData)
{
Type4RemoteInitiator *self = (Type4RemoteInitiator *) pUserData;
self->disconnected_callback();
}

View File

@ -0,0 +1,322 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "nfc/ndef/MessageBuilder.h"
namespace mbed {
namespace nfc {
namespace ndef {
MessageBuilder::MessageBuilder(const Span<uint8_t> &buffer) :
_message_buffer(buffer),
_position(0),
_message_started(false),
_message_ended(false),
_in_chunk(false)
{ }
bool MessageBuilder::append_record(
const RecordType &type,
const RecordPayload &payload,
bool is_last_record
)
{
Record record(
type,
payload,
/* id */ RecordID(),
/* chunk */ false,
is_last_record
);
return append_record(record);
}
bool MessageBuilder::append_record(
const RecordType &type,
const PayloadBuilder &builder,
bool is_last_record
)
{
Record record(
type,
RecordPayload(),
RecordID(),
/* chunk */ false,
is_last_record
);
return append_record(record, &builder);
}
bool MessageBuilder::append_record(const Record &record, const PayloadBuilder *builder)
{
if (_message_ended) {
return false;
}
if (record.type.value.size() > 255) {
return false;
}
if (record.id.size() > 255) {
return false;
}
if (!record.id.empty() && _in_chunk) {
if (record.chunk) {
// middle chunk
return false;
} else if (record.type.tnf == RecordType::unchanged) {
// terminating chunk
return false;
}
}
if (_in_chunk && record.type.tnf != RecordType::unchanged) {
return false;
}
if (!_in_chunk && record.chunk && record.type.tnf == RecordType::unchanged) {
return false;
}
if (record.type.tnf == RecordType::empty) {
if (!record.type.value.empty()) {
return false;
}
if (!record.id.empty()) {
return false;
}
if (get_payload_size(record, builder)) {
return false;
}
}
if (record.type.tnf == RecordType::well_known_type ||
record.type.tnf == RecordType::media_type ||
record.type.tnf == RecordType::absolute_uri ||
record.type.tnf == RecordType::external_type
) {
if (record.type.value.empty()) {
return false;
}
}
if (record.type.tnf == RecordType::unknown && !record.type.value.empty()) {
return false;
}
size_t record_size = compute_record_size(record, builder);
if (record_size > (_message_buffer.size() - _position)) {
return false;
}
append_header(record, builder);
append_type_length(record);
append_payload_length(record, builder);
append_id_length(record);
append_type(record);
append_id(record);
append_payload(record, builder);
if (record.chunk) {
_in_chunk = true;
} else if (record.type.tnf == RecordType::unchanged) {
// last chunk reached
_in_chunk = false;
}
return true;
}
void MessageBuilder::reset()
{
_position = 0;
_message_started = false;
_message_ended = false;
_in_chunk = false;
}
void MessageBuilder::reset(const Span<uint8_t> &buffer)
{
_message_buffer = buffer;
_position = 0;
_message_started = false;
_message_ended = false;
_in_chunk = false;
}
bool MessageBuilder::is_message_complete() const
{
return _message_ended;
}
Span<const uint8_t> MessageBuilder::get_message() const
{
if (is_message_complete()) {
return _message_buffer.first(_position);
} else {
return Span<const uint8_t>();
}
}
size_t MessageBuilder::compute_record_size(const Record &record, const PayloadBuilder *builder)
{
size_t record_size = 0;
record_size = 1; /* header */
record_size += 1; /* type length */
record_size += is_short_payload(record, builder) ? 1 : 4;
if (!record.id.empty()) {
record_size += 1;
}
record_size += record.type.value.size();
record_size += record.id.size();
record_size += get_payload_size(record, builder);
return record_size;
}
void MessageBuilder::append_header(const Record &record, const PayloadBuilder *builder)
{
uint8_t header = 0;
if (!_message_started) {
header |= Header::message_begin_bit;
_message_started = true;
}
if (record.last_record) {
header |= Header::message_end_bit;
_message_ended = true;
}
if (record.chunk) {
header |= Header::chunk_flag_bit;
}
if (is_short_payload(record, builder)) {
header |= Header::short_record_bit;
}
if (record.id.size()) {
header |= Header::id_length_bit;
}
header |= record.type.tnf;
_message_buffer[_position++] = header;
}
void MessageBuilder::append_type_length(const Record &record)
{
_message_buffer[_position++] = record.type.value.size();
}
void MessageBuilder::append_payload_length(const Record &record, const PayloadBuilder *builder)
{
size_t size = get_payload_size(record, builder);
if (is_short_payload(record, builder)) {
_message_buffer[_position++] = size;
} else {
_message_buffer[_position++] = (size >> 24) & 0xFF;
_message_buffer[_position++] = (size >> 16) & 0xFF;
_message_buffer[_position++] = (size >> 8) & 0xFF;
_message_buffer[_position++] = size & 0xFF;
}
}
void MessageBuilder::append_id_length(const Record &record)
{
if (record.id.empty()) {
return;
}
_message_buffer[_position++] = record.id.size();
}
void MessageBuilder::append_type(const Record &record)
{
if (record.type.value.empty()) {
return;
}
memcpy(
_message_buffer.data() + _position,
record.type.value.data(),
record.type.value.size()
);
_position += record.type.value.size();
}
void MessageBuilder::append_id(const Record &record)
{
if (record.id.empty()) {
return;
}
memcpy(
_message_buffer.data() + _position,
record.id.data(),
record.id.size()
);
_position += record.id.size();
}
void MessageBuilder::append_payload(const Record &record, const PayloadBuilder *builder)
{
size_t size = get_payload_size(record, builder);
if (!size) {
return;
}
if (builder) {
builder->build(_message_buffer.subspan(_position, size));
} else {
memcpy(
_message_buffer.data() + _position,
record.payload.data(),
size
);
}
_position += size;
}
bool MessageBuilder::is_short_payload(const Record &record, const PayloadBuilder *builder)
{
if (get_payload_size(record, builder) <= 255) {
return true;
} else {
return false;
}
}
size_t MessageBuilder::get_payload_size(const Record &record, const PayloadBuilder *builder)
{
return builder ? builder->size() : record.payload.size();
}
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,314 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "nfc/ndef/MessageParser.h"
#include "nfc/ndef/Record.h"
namespace {
struct buffer_iterator_t {
buffer_iterator_t(const mbed::Span<const uint8_t> &buffer) :
buffer(buffer),
position(0)
{ }
uint8_t operator*()
{
return buffer[position];
}
buffer_iterator_t &operator++()
{
++position;
return *this;
}
buffer_iterator_t operator++(int)
{
buffer_iterator_t previous = *this;
++*this;
return previous;
}
buffer_iterator_t &operator+=(size_t increment)
{
position += increment;
return *this;
}
operator bool() const
{
return (position >= buffer.size()) ? false : true;
}
size_t remaining_size() const
{
return buffer.size() - position;
}
void read_le(uint8_t *dest, size_t size)
{
memcpy(dest, buffer.data() + position, size);
position += size;
}
void read_be(uint8_t *dest, size_t size)
{
// TODO: Needs proper network to host function
std::reverse_copy(
buffer.data() + position,
buffer.data() + position + size,
dest
);
position += size;
}
mbed::Span<const uint8_t> get_underlying_buffer() const
{
return buffer.last(buffer.size() - position);
}
private:
mbed::Span<const uint8_t> buffer;
mbed::Span<const uint8_t>::index_type position;
};
} // end of anonymous namespace
namespace mbed {
namespace nfc {
namespace ndef {
struct MessageParser::parsing_state_t {
parsing_state_t(const Span<const uint8_t> &data_buffer) :
it(data_buffer),
first_record_parsed(false),
last_record_parsed(false),
error(false)
{ }
buffer_iterator_t it;
bool first_record_parsed: 1;
bool last_record_parsed: 1;
bool error: 1;
};
MessageParser::MessageParser() :
_delegate(NULL)
{ }
void MessageParser::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
void MessageParser::parse(const Span<const uint8_t> &data_buffer)
{
parsing_state_t parsing_state(data_buffer);
report_parsing_started();
while (parsing_state.it && parse_record(parsing_state));
if (!parsing_state.error && !parsing_state.last_record_parsed) {
report_parsing_error(MISSING_MESSAGE_END, parsing_state);
}
report_parsing_terminated();
}
bool MessageParser::parse_record(parsing_state_t &s)
{
if (s.error || s.last_record_parsed) {
return false;
}
// ensure that the header can be extracted
if (s.it.remaining_size() < 1) {
report_parsing_error(INSUFICIENT_DATA, s);
return false;
}
uint8_t header = *s.it++;
// NOTE: report an error until the chunk parsing design is sorted out
if (header & Header::chunk_flag_bit) {
report_parsing_error(CHUNK_RECORD_NOT_SUPPORTED, s);
return false;
}
// handle first record cases
if (s.first_record_parsed == false) {
if (header & Header::message_begin_bit) {
s.first_record_parsed = true;
} else {
report_parsing_error(INVALID_MESSAGE_START, s);
return false;
}
} else if (header & Header::message_begin_bit) {
report_parsing_error(INVALID_MESSAGE_START, s);
return false;
}
// handle last record
if (header & Header::message_end_bit) {
s.last_record_parsed = true;
}
// ensure their is enough space to contain the type length, payload
// length and id length
uint8_t lengths_size = compute_lengths_size(header);
if (s.it.remaining_size() < lengths_size) {
report_parsing_error(INSUFICIENT_DATA, s);
return false;
}
// extract the various length from the message
uint8_t type_length = extract_type_length(s);
uint32_t payload_length = extract_payload_length(s, header);
uint8_t id_length = extract_id_length(s, header);
// there should be enough bytes left in the buffer
if (s.it.remaining_size() < (type_length + id_length + payload_length)) {
report_parsing_error(INSUFICIENT_DATA, s);
return false;
}
// validate the Type Name Format of the header
switch (header & Header::tnf_bits) {
case RecordType::empty:
if (type_length || payload_length || id_length) {
report_parsing_error(INVALID_EMPTY_RECORD, s);
return false;
}
break;
case RecordType::well_known_type:
case RecordType::media_type:
case RecordType::absolute_uri:
case RecordType::external_type:
if (!type_length) {
report_parsing_error(MISSING_TYPE_VALUE, s);
return false;
}
break;
case RecordType::unknown:
if (type_length) {
report_parsing_error(INVALID_UNKNOWN_TYPE_LENGTH, s);
return false;
}
break;
case RecordType::unchanged:
// shouldn't be handled outside of chunk handling
report_parsing_error(INVALID_UNCHANGED_TYPE, s);
return false;
default:
report_parsing_error(INVALID_TYPE_NAME_FORMAT, s);
return false;
}
// build the record
Record record;
// flags
record.last_record = header & Header::message_end_bit;
// type
record.type.tnf = static_cast<RecordType::tnf_t>(header & Header::tnf_bits);
if (type_length) {
record.type.value = s.it.get_underlying_buffer().first(type_length);
s.it += type_length;
}
// id
if (id_length) {
record.id = s.it.get_underlying_buffer().first(id_length);
s.it += id_length;
}
// payload
if (payload_length) {
record.payload = s.it.get_underlying_buffer().first(payload_length);
s.it += payload_length;
}
s.it += payload_length;
report_record_parsed(record);
return true;
}
uint8_t MessageParser::compute_lengths_size(uint8_t header)
{
return 1 /* type_length size */ +
((header & Header::short_record_bit) ? 1 : 4) /* payload length */ +
((header & Header::id_length_bit) ? 1 : 0);
}
uint8_t MessageParser::extract_type_length(parsing_state_t &s)
{
return *s.it++;
}
uint32_t MessageParser::extract_payload_length(parsing_state_t &s, uint8_t header)
{
uint32_t payload_length = 0;
if (header & Header::short_record_bit) {
payload_length = *s.it++;
} else {
s.it.read_be(
reinterpret_cast<uint8_t *>(&payload_length),
sizeof(payload_length)
);
}
return payload_length;
}
uint8_t MessageParser::extract_id_length(parsing_state_t &s, uint8_t header)
{
return (header & Header::id_length_bit) ? *s.it++ : 0;
}
void MessageParser::report_parsing_started()
{
if (_delegate) {
_delegate->on_parsing_started();
}
}
void MessageParser::report_record_parsed(const Record &record)
{
if (_delegate) {
_delegate->on_record_parsed(record);
}
}
void MessageParser::report_parsing_terminated()
{
if (_delegate) {
_delegate->on_parsing_terminated();
}
}
void MessageParser::report_parsing_error(error_t error, parsing_state_t &parsing_state)
{
parsing_state.error = true;
if (_delegate) {
_delegate->on_parsing_error(error);
}
}
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,50 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nfc/ndef/RecordParser.h"
namespace mbed {
namespace nfc {
namespace ndef {
bool RecordParserChain::parse(const Record &record)
{
RecordParser *current_parser = _parsers;
while (current_parser) {
if (current_parser->parse(record)) {
return true;
}
current_parser = current_parser->_next_parser;
}
return false;
}
void RecordParserChain::set_next_parser(RecordParser *parser)
{
if (!_parsers) {
_parsers = parser;
} else {
RecordParser *current_parser = _parsers;
while (current_parser->_next_parser) {
current_parser = current_parser->_next_parser;
}
current_parser->_next_parser = parser;
}
}
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,174 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "nfc/ndef/common/Mime.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
Mime::Mime() :
_mime(NULL),
_type_size(0),
_content_size(0)
{ }
Mime::Mime(
const Span<const uint8_t> &mime_type,
const Span<const uint8_t> &content
) : _mime(new uint8_t[mime_type.size() + content.size()]),
_type_size(mime_type.size()),
_content_size(content.size())
{
memcpy(_mime, mime_type.data(), mime_type.size());
memcpy(_mime + mime_type.size(), content.data(), content.size());
}
Mime::Mime(const Mime &to_copy) :
_mime(new uint8_t[to_copy.mime_size()]),
_type_size(to_copy._type_size),
_content_size(to_copy._content_size)
{
memcpy(_mime, to_copy._mime, to_copy.mime_size());
}
Mime::~Mime()
{
delete[] _mime;
}
Mime &Mime::operator=(const Mime &to_copy)
{
if (this == &to_copy) {
return * this;
}
delete[] _mime;
_mime = new uint8_t[to_copy.mime_size()];
memcpy(_mime, to_copy._mime, to_copy.mime_size());
_type_size = to_copy._type_size;
_content_size = to_copy._content_size;
return *this;
}
void Mime::set_mime(
const Span<const uint8_t> &mime_type,
const Span<const uint8_t> &content
)
{
delete[] _mime;
_mime = new uint8_t[mime_type.size() + content.size()];
memcpy(_mime, mime_type.data(), mime_type.size());
memcpy(_mime + mime_type.size(), content.data(), content.size());
_type_size = mime_type.size();
_content_size = content.size();
}
Span<const uint8_t> Mime::get_mime_type() const
{
return make_const_Span(_mime, _type_size);
}
Span<const uint8_t> Mime::get_mime_content() const
{
return make_const_Span(_mime + _type_size, _content_size);
}
bool Mime::append_as_record(
MessageBuilder &message_builder,
bool is_last_record
) const
{
return message_builder.append_record(
RecordType(
RecordType::media_type,
get_mime_type()
),
get_mime_content(),
is_last_record
);
}
size_t Mime::get_record_size() const
{
return MessageBuilder::compute_record_size(
Record(
RecordType(
RecordType::media_type,
get_mime_type()
),
get_mime_content(),
RecordID(),
/* chunk */ false,
/* last record */ false
)
);
}
void Mime::move_data(
uint8_t *mime_record,
size_t mime_type_size,
size_t mime_content_size
)
{
delete[] _mime;
_mime = mime_record;
_type_size = mime_type_size;
_content_size = mime_content_size;
}
size_t Mime::mime_size() const
{
return _type_size + _content_size;
}
bool MimeParser::do_parse(const Record &record, Mime &mime)
{
if (record.type.tnf != RecordType::media_type) {
return false;
}
// A type and a payload should be present
if (record.type.value.empty() || record.payload.empty()) {
return false;
}
// create the buffer
size_t type_size = record.type.value.size();
size_t content_size = record.payload.size();
uint8_t *mime_buffer = new uint8_t[type_size + content_size];
// copy type
memcpy(mime_buffer, record.type.value.data(), type_size);
// copy content
memcpy(mime_buffer + type_size, record.payload.data(), content_size);
mime.move_data(mime_buffer, type_size, content_size);
return true;
}
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,124 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nfc/ndef/common/SimpleMessageParser.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
SimpleMessageParser::SimpleMessageParser() :
_message_parser(),
_record_parser_chain(),
_uri_parser(),
_text_parser(),
_mime_parser(),
_delegate(NULL)
{
// setup the parser chain
_record_parser_chain.set_next_parser(&_uri_parser);
_record_parser_chain.set_next_parser(&_text_parser);
_record_parser_chain.set_next_parser(&_mime_parser);
// wire event handling
_message_parser.set_delegate(this);
_uri_parser.set_delegate(this);
_text_parser.set_delegate(this);
_mime_parser.set_delegate(this);
}
void SimpleMessageParser::set_delegate(Delegate *delegate)
{
_delegate = delegate;
}
void SimpleMessageParser::parse(const Span<const uint8_t> &data_buffer)
{
_message_parser.parse(data_buffer);
}
void SimpleMessageParser::add_record_parser(RecordParser *parser)
{
_record_parser_chain.set_next_parser(parser);
}
void SimpleMessageParser::on_parsing_error(MessageParser::error_t error)
{
if (_delegate) {
_delegate->on_parsing_error(error);
}
}
void SimpleMessageParser::on_parsing_started()
{
if (_delegate) {
_delegate->on_parsing_started();
}
}
void SimpleMessageParser::on_record_parsed(const Record &record)
{
bool parsed = _record_parser_chain.parse(record);
if (!parsed && _delegate) {
_delegate->on_unknown_record_parsed(record);
}
}
void SimpleMessageParser::on_parsing_terminated()
{
if (_delegate) {
_delegate->on_parsing_terminated();
}
}
void SimpleMessageParser::on_record_parsed(
const URI &uri,
const RecordID &id
)
{
if (_delegate) {
_delegate->on_uri_parsed(uri, id);
}
}
void SimpleMessageParser::on_record_parsed(
const Text &text,
const RecordID &id
)
{
if (_delegate) {
_delegate->on_text_parsed(text, id);
}
}
void SimpleMessageParser::on_record_parsed(
const Mime &mime,
const RecordID &id
)
{
if (_delegate) {
_delegate->on_mime_parsed(mime, id);
}
}
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,206 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "nfc/ndef/common/Text.h"
namespace {
static const uint8_t utf16_encoding_bit = (1 << 7);
static const uint8_t language_code_size_mask = 0x3F;
static const uint8_t header_index = 0;
static const uint8_t language_code_index = 1;
static const uint8_t header_size = 1;
static const uint8_t text_record_type_value[] = { 'T' };
}
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
Text::Text() :
_text_record(NULL),
_text_record_size(0)
{ }
Text::Text(const Text &other) :
_text_record(other._text_record ? new uint8_t[other._text_record_size] : NULL),
_text_record_size(other._text_record_size)
{
memcpy(_text_record, other._text_record, _text_record_size);
}
Text::Text(
encoding_t text_encoding,
const Span<const uint8_t> &language_code,
const Span<const uint8_t> &text
) : _text_record(NULL),
_text_record_size(0)
{
set_text(text_encoding, language_code, text);
}
Text::~Text()
{
delete[] _text_record;
}
Text &Text::operator=(const Text &other)
{
if (this == &other) {
return *this;
}
_text_record_size = other._text_record_size;
delete[] _text_record;
if (!other._text_record) {
_text_record = NULL;
} else {
_text_record = new uint8_t[_text_record_size];
memcpy(_text_record, other._text_record, _text_record_size);
}
return *this;
}
void Text::set_text(
encoding_t text_encoding,
const Span<const uint8_t> &language_code,
const Span<const uint8_t> &text
)
{
delete[] _text_record;
_text_record_size = header_size + language_code.size() + text.size();
_text_record = new uint8_t[_text_record_size];
// build the header
_text_record[header_index] = 0;
if (text_encoding == UTF16) {
_text_record[header_index] |= utf16_encoding_bit;
}
_text_record[header_index] |= language_code.size();
// language code
memcpy(_text_record + language_code_index, language_code.data(), language_code.size());
// actual text
memcpy(_text_record + language_code_index + language_code.size(), text.data(), text.size());
}
Text::encoding_t Text::get_encoding() const
{
return (_text_record[header_index] & utf16_encoding_bit) ? UTF16 : UTF8;
}
Span<const uint8_t> Text::get_language_code() const
{
return make_const_Span(
_text_record + language_code_index,
_text_record[header_index] & language_code_size_mask
);
}
Span<const uint8_t> Text::get_text() const
{
if (!_text_record) {
return Span<const uint8_t>();
}
size_t language_code_size = get_language_code().size();
return make_const_Span(
_text_record + header_size + language_code_size,
_text_record_size - header_size - language_code_size
);
}
void Text::move_data(uint8_t *text, size_t size)
{
delete[] _text_record;
_text_record = text;
_text_record_size = size;
}
bool Text::append_as_record(
MessageBuilder &message_builder,
bool is_last_record
) const
{
if (!_text_record) {
return false;
}
// Build the record type
RecordType type(
RecordType::well_known_type,
text_record_type_value
);
// build the record payload
RecordPayload payload(_text_record, _text_record_size);
return message_builder.append_record(type, payload, is_last_record);
}
size_t Text::get_record_size() const
{
if (!_text_record) {
return 0;
}
return MessageBuilder::compute_record_size(
Record(
RecordType(
RecordType::well_known_type,
text_record_type_value
),
RecordPayload(_text_record, _text_record_size),
RecordID(),
/* chunk */ false,
/* last record */ false
)
);
}
bool TextParser::do_parse(const Record &record, Text &text)
{
if (record.type.tnf != RecordType::well_known_type) {
return false;
}
// the record type value should be equal to `T`
if (record.type.value != make_const_Span(text_record_type_value) ||
record.payload.empty()
) {
return false;
}
// create the buffer
size_t text_record_size = record.payload.size();
uint8_t *text_record = new uint8_t[text_record_size];
memcpy(text_record, record.payload.data(), text_record_size);
text.move_data(text_record, text_record_size);
return true;
}
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,187 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "nfc/ndef/common/URI.h"
namespace {
static const uint8_t uri_id_code_size = 1;
static const uint8_t uri_id_index = 0;
static const uint8_t uri_field_index = 1;
static const uint8_t uri_record_type_value[] = { 'U' } ;
}
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
URI::URI() :
_uri(NULL),
_uri_size(0)
{
}
URI::URI(uri_identifier_code_t id, const Span<const uint8_t> &uri_field) :
_uri(uri_field.size() ? new uint8_t[uri_id_code_size + uri_field.size()] : NULL),
_uri_size(uri_id_code_size + uri_field.size())
{
_uri[uri_id_index] = id;
memcpy(_uri + uri_field_index, uri_field.data(), uri_field.size());
}
URI::URI(const URI &other) :
_uri(other._uri ? new uint8_t[other._uri_size] : NULL),
_uri_size(other._uri_size)
{
memcpy(_uri, other._uri, other._uri_size);
}
URI::~URI()
{
delete[] _uri;
}
URI &URI::operator=(const URI &other)
{
delete[] _uri;
if (!other._uri) {
_uri = NULL;
_uri_size = 0;
} else {
_uri = new uint8_t[other._uri_size];
_uri_size = other._uri_size;
memcpy(_uri, other._uri, other._uri_size);
}
return *this;
}
void URI::set_uri(
uri_identifier_code_t id,
const Span<const uint8_t> &uri_field
)
{
delete[] _uri;
if (uri_field.empty()) {
_uri = NULL;
_uri_size = 0;
return;
}
_uri = new uint8_t[uri_id_code_size + uri_field.size()];
_uri_size = uri_id_code_size + uri_field.size();
_uri[uri_id_index] = id;
memcpy(_uri + uri_field_index, uri_field.data(), uri_field.size());
}
URI::uri_identifier_code_t URI::get_id() const
{
if (!_uri) {
return NA;
}
return static_cast<uri_identifier_code_t>(_uri[uri_id_index]);
}
Span<const uint8_t> URI::get_uri_field() const
{
if (!_uri) {
return Span<const uint8_t>();
}
return make_const_Span(
_uri + uri_field_index,
_uri_size - uri_id_code_size
);
}
bool URI::append_as_record(MessageBuilder &message_builder, bool is_last_record) const
{
if (!_uri) {
return false;
}
// Build the record type
RecordType type(
RecordType::well_known_type,
uri_record_type_value
);
// build the record payload
RecordPayload payload(_uri, _uri_size);
return message_builder.append_record(type, payload, is_last_record);
}
size_t URI::get_record_size() const
{
if (!_uri) {
return 0;
}
return MessageBuilder::compute_record_size(
Record(
RecordType(
RecordType::well_known_type,
uri_record_type_value
),
RecordPayload(_uri, _uri_size),
RecordID(),
/* chunk */ false,
/* last record */ false
)
);
}
void URI::move_data(uint8_t *new_uri, size_t new_uri_size)
{
delete[] _uri;
_uri = new_uri;
_uri_size = new_uri_size;
}
bool URIParser::do_parse(const Record &record, URI &uri)
{
if (record.type.tnf != RecordType::well_known_type) {
return false;
}
// the record type value should be equal to `U`
if (record.type.value != make_const_Span(uri_record_type_value) ||
record.payload.empty()
) {
return false;
}
// create the buffer
size_t uri_record_size = record.payload.size();
uint8_t *uri_record = new uint8_t[uri_record_size];
memcpy(uri_record, record.payload.data(), uri_record_size);
uri.move_data(uri_record, uri_record_size);
return true;
}
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,39 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "nfc/ndef/common/util.h"
namespace mbed {
namespace nfc {
namespace ndef {
namespace common {
Span<const uint8_t> span_from_cstr(const char *cstr)
{
return Span<const uint8_t>((const uint8_t *)cstr, strlen(cstr));
}
/**
* @}
*/
} // namespace common
} // namespace ndef
} // namespace nfc
} // namespace mbed

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ndef.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details NDEF tag abstraction
*/
#include "ndef.h"
/** \addtogroup NDEF
* @{
* \name Generic NDEF Tag
* @{
*/
/** Initialize NDEF tag abstraction
* \param pNdefTag pointer to ndef_tag_t structure to initialize
* \param encode function that will be called to generate the NDEF message before sending it to the other party
* \param decode function that will be called to parse the NDEF message after receiving it from the other party
* \param buffer underlying buffer to use (it should be big enough so that any NDEF message you might need could be stored inside)
* \param buffer_size size of the underlying buffer
* \param pImpl pointer to actual implementation
*/
void ndef_msg_init(ndef_msg_t *pNdef, ndef_encode_fn_t encode, ndef_decode_fn_t decode, uint8_t *data, size_t size, void *pUserData)
{
pNdef->encode = encode;
pNdef->decode = decode;
ac_buffer_builder_init(&pNdef->bufferBldr, data, size);
pNdef->pUserData = pUserData;
}
/** Get NDEF tag implementation
* \param pNdefTag pointer to ndef_tag_t structure
* \return implementation
*/
/*
void* ndef_tag_impl(ndef_tag_t* pNdefTag)
{
return pNdefTag->pImpl;
}
*/
/**
* @}
* @}
* */

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ndef.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
/** \addtogroup NDEF
* @{
* \name Generic NDEF Tag
* @{
*/
#ifndef NDEF_H_
#define NDEF_H_
#include "stack/nfc_common.h"
#ifdef __cplusplus
extern "C" {
#endif
//Generic interface for NDEF messages
typedef struct __ndef_msg ndef_msg_t;
/** Function called to generate the tag's content on read (target mode)
* \param pTag pointer to ndef_tag_t instance
* \param type pMem buffer in which to store the generated content
*/
typedef nfc_err_t (*ndef_encode_fn_t)(ndef_msg_t *pTag, ac_buffer_builder_t *pBufferBldr, void *pUserData);
/** Function called to decode the tag's content on write (target mode) or read (reader mode)
* \param pTag pointer to ndef_tag_t instance
* \param type pMem buffer containing the tag's content
*/
typedef nfc_err_t (*ndef_decode_fn_t)(ndef_msg_t *pTag, ac_buffer_t *pBuffer, void *pUserData);
struct __ndef_msg {
ndef_encode_fn_t encode;
ndef_decode_fn_t decode;
ac_buffer_builder_t bufferBldr;
void *pUserData;
};
void ndef_msg_init(ndef_msg_t *pNdef, ndef_encode_fn_t encode, ndef_decode_fn_t decode, uint8_t *data, size_t size, void *pUserData);
static inline nfc_err_t ndef_msg_encode(ndef_msg_t *pNdef)
{
if (pNdef->encode == NULL) {
return NFC_OK;
}
return pNdef->encode(pNdef, &pNdef->bufferBldr, pNdef->pUserData);
}
static inline nfc_err_t ndef_msg_decode(ndef_msg_t *pNdef)
{
if (pNdef->decode == NULL) {
return NFC_OK;
}
return pNdef->decode(pNdef, ac_buffer_builder_buffer(&pNdef->bufferBldr), pNdef->pUserData);
}
static inline ac_buffer_builder_t *ndef_msg_buffer_builder(ndef_msg_t *pNdef)
{
return &pNdef->bufferBldr;
}
//void* ndef_tag_impl(ndef_tag_t* pNdefTag);
#ifdef __cplusplus
}
#endif
#endif /* NDEF_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file nfc_common.h
* \copyright Copyright (c) ARM Ltd 2018
* \author Donatien Garnier
* \details Common includes for NFC Stack
*/
#ifndef NFC_COMMON_H_
#define NFC_COMMON_H_
#include "stddef.h"
#include "stdint.h"
#include "string.h"
#include "stdbool.h"
#include "nfc_errors.h"
#include "platform/nfc_debug.h"
#include "acore/ac_macros.h"
#include "acore/ac_buffer.h"
#include "acore/ac_buffer_reader.h"
#include "acore/ac_buffer_builder.h"
#include "acore/ac_stream.h"
#endif /* NFC_COMMON_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file nfc_errors.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details NFC Error codes
*/
/** \addtogroup Core
* @{
* \name Error codes
* @{
*/
#ifndef NFC_ERRORS_H_
#define NFC_ERRORS_H_
#define NFC_OK 0 ///< No error
#define NFC_ERR_UNKNOWN 1 ///< Unknown error
#define NFC_ERR_LENGTH 2 ///< Length of parameter is wrong
#define NFC_ERR_NOT_FOUND 3 ///< Could not find item
#define NFC_ERR_UNSUPPORTED 4 ///< This action is not supported
#define NFC_ERR_PARAMS 5 ///< These parameters are not correct
#define NFC_ERR_BUFFER_TOO_SMALL 6 ///< The buffer is too small to store all data (buffer overflow)
#define NFC_ERR_TIMEOUT 7 ///< Timeout
#define NFC_ERR_CRC 8 ///< Checksum does not match
#define NFC_ERR_NOPEER 9 ///< No target/initiator in vicinity
#define NFC_ERR_PARITY 10 ///< Parity error
#define NFC_ERR_FIELD 11 ///< No RF field detected (or RF field lost)
#define NFC_ERR_COLLISION 12 ///< Collision detected
#define NFC_ERR_WRONG_COMM 13 ///< Communication error
#define NFC_ERR_PROTOCOL 14 ///< Protocol is not conformant
#define NFC_ERR_BUSY 15 ///< Resource is busy
#define NFC_ERR_CONTROLLER 16 ///< Controller failure
#define NFC_ERR_HALTED 17 ///< Target has been halted
#define NFC_ERR_MAC 18 ///< MAC does not match
#define NFC_ERR_UNDERFLOW 19 ///< Could not send data in time
#define NFC_ERR_DISCONNECTED 20 ///< Link has disconnected
#define NFC_ERR_ABORTED 21 ///< Command was aborted
/** Type for NFC errors
*/
typedef int nfc_err_t;
#endif /* NFC_ERRORS_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_NFC_DEBUG_H
#define MBED_NFC_DEBUG_H
#if NFC_DEBUG && !defined(NDEBUG) && __DEBUG__
#ifdef __MODULE__
#define __NFC_MODULE__ __MODULE__
#else
#define __NFC_MODULE__ __FILE__
#endif
#include "stdio.h"
#include "stdarg.h"
static inline void nfc_dbg_print(const char *type, const char *module, unsigned int line, const char *fmt, ...)
{
#if !defined(NDEBUG)
printf("NFC [%s] %s:%u ", type, module, line);
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
printf("\r\n");
#endif
}
#if !defined(NFC_DBG)
#define NFC_DBG(...) nfc_dbg_print("DBG", __NFC_MODULE__, __LINE__, __VA_ARGS__)
#endif
#if !defined(NFC_WARN)
#define NFC_WARN(...) nfc_dbg_print("WARN", __NFC_MODULE__, __LINE__, __VA_ARGS__)
#endif
#if !defined(NFC_ERR)
#define NFC_ERR(...) nfc_dbg_print("ERR", __NFC_MODULE__, __LINE__, __VA_ARGS__)
#endif
#define NFC_DBG_BLOCK(x) x
#else
#if !defined(NFC_DBG)
#define NFC_DBG(...)
#endif
#if !defined(NFC_WARN)
#define NFC_WARN(...)
#endif
#if !defined(NFC_ERR)
#define NFC_ERR(...)
#endif
#define NFC_DBG_BLOCK(x)
#endif
#endif

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file nfc_scheduler.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "nfc_scheduler.c"
#endif
#include "platform/nfc_scheduler.h"
void nfc_scheduler_init(nfc_scheduler_t *pScheduler, nfc_scheduler_timer_t *pTimer)
{
pScheduler->pNext = NULL;
pScheduler->pTimer = pTimer;
//Start timer
nfc_scheduler_timer_start(pTimer);
}
#define MAX_TIMEOUT UINT32_MAX
uint32_t nfc_scheduler_iteration(nfc_scheduler_t *pScheduler, uint32_t events)
{
while (true) {
nfc_task_t *pPrioTask = NULL;
nfc_task_t *pPrioTaskPrevious = NULL;
uint32_t prioTaskEvent = 0;
int64_t timeout;
nfc_task_t *pPreviousTask = NULL;
nfc_task_t *pTask = pScheduler->pNext;
if (pTask == NULL) {
NFC_DBG("Empty queue, %lu ms elapsed", nfc_scheduler_timer_get(pScheduler->pTimer));
//Empty queue, return
return MAX_TIMEOUT;
}
//Get timer value
uint32_t timeElapsed = nfc_scheduler_timer_get(pScheduler->pTimer);
NFC_DBG("%lu ms elapsed", timeElapsed);
nfc_scheduler_timer_reset(pScheduler->pTimer);
do {
//Apply timeouts
if (pTask->events & EVENT_TIMEOUT) {
pTask->timeout -= timeElapsed;
}
pPreviousTask = pTask;
pTask = pTask->pNext;
} while (pTask != NULL);
pTask = pScheduler->pNext;
pPreviousTask = NULL;
timeout = MAX_TIMEOUT;
do {
//Check which task should be woken up first
if ((events & EVENT_HW_INTERRUPT) && (pTask->events & EVENT_HW_INTERRUPT)) {
//Hardware interrupts have prio
pPrioTask = pTask;
pPrioTaskPrevious = pPreviousTask;
timeout = 0;
events &= ~EVENT_HW_INTERRUPT; //Only one task gets triggered per event
prioTaskEvent = EVENT_HW_INTERRUPT;
break;
} else if ((pTask->events & EVENT_TIMEOUT) && (pTask->timeout < timeout)) {
pPrioTask = pTask;
pPrioTaskPrevious = pPreviousTask;
timeout = pTask->timeout;
prioTaskEvent = EVENT_TIMEOUT;
}
pPreviousTask = pTask;
pTask = pTask->pNext;
} while (pTask != NULL);
if (pPrioTask == NULL) {
//No task to wake up, exit
NFC_DBG("No task to wake up");
return MAX_TIMEOUT;
}
if (timeout > 0) {
//No task to wake up yet
if (timeout > MAX_TIMEOUT) {
NFC_DBG("No task to wake up");
return MAX_TIMEOUT;
} else {
NFC_DBG("No task to wake up, wait %lu ms", timeout);
return timeout;
}
}
//Dequeue task
if (pPrioTaskPrevious == NULL) {
pScheduler->pNext = pPrioTask->pNext;
} else {
pPrioTaskPrevious->pNext = pPrioTask->pNext;
}
pPrioTask->pNext = NULL;
//Execute task
NFC_DBG("Calling task %p - events %02X", pPrioTask, prioTaskEvent);
pPrioTask->fn(prioTaskEvent, pPrioTask->pUserData);
events &= ~EVENT_HW_INTERRUPT; //Only one task gets triggered per event
}
return MAX_TIMEOUT;
}
void nfc_scheduler_queue_task(nfc_scheduler_t *pScheduler, nfc_task_t *pTask)
{
pTask->timeout = pTask->timeoutInitial + nfc_scheduler_timer_get(pScheduler->pTimer);
NFC_DBG("Queuing task %p: events %1X, timeout %lu ms", pTask, pTask->events, pTask->timeout);
//Find last task
nfc_task_t *pPrevTask = pScheduler->pNext;
pTask->pNext = NULL;
if (pPrevTask == NULL) {
pScheduler->pNext = pTask;
return;
}
while (pPrevTask->pNext != NULL) {
pPrevTask = pPrevTask->pNext;
}
pPrevTask->pNext = pTask;
}
void nfc_scheduler_dequeue_task(nfc_scheduler_t *pScheduler, bool abort, nfc_task_t *pTask)
{
NFC_DBG("Dequeuing task %p", pTask);
//Find task
nfc_task_t *pPrevTask = pScheduler->pNext;
if (pPrevTask == NULL) {
pTask->pNext = NULL;
return;
}
if (pPrevTask == pTask) {
if (abort) {
pTask->fn(EVENT_ABORTED, pTask->pUserData);
}
pScheduler->pNext = pTask->pNext;
pTask->pNext = NULL;
return;
}
while (pPrevTask->pNext != NULL) {
if (pPrevTask->pNext == pTask) {
if (abort) {
pTask->fn(EVENT_ABORTED, pTask->pUserData);
}
pPrevTask->pNext = pTask->pNext;
pTask->pNext = NULL;
return;
}
pPrevTask = pPrevTask->pNext;
}
pTask->pNext = NULL;
}
void task_init(nfc_task_t *pTask, uint32_t events, uint32_t timeout, nfc_task_fn fn, void *pUserData)
{
pTask->events = events;
pTask->timeoutInitial = timeout;
pTask->fn = fn;
pTask->pUserData = pUserData;
pTask->pNext = NULL;
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file nfc_scheduler.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
/** \addtogroup Core
* @{
* \name Scheduler
* @{
*/
#ifndef NFC_SCHEDULER_H_
#define NFC_SCHEDULER_H_
#include "stack/nfc_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#define EVENT_NONE 0
#define EVENT_TIMEOUT 1
#define EVENT_ABORTED 2
#define EVENT_HW_INTERRUPT 4
struct __nfc_timer;
typedef struct __nfc_timer nfc_scheduler_timer_t;
struct __nfc_task;
typedef struct __nfc_task nfc_task_t;
typedef struct __scheduler {
nfc_task_t *pNext;
nfc_scheduler_timer_t *pTimer;
} nfc_scheduler_t;
typedef void (*nfc_task_fn)(uint32_t events, void *pUserData);
struct __nfc_task {
uint32_t events;
int64_t timeout; //millisecs
int64_t timeoutInitial;
nfc_task_fn fn;
void *pUserData;
nfc_task_t *pNext;
};
void nfc_scheduler_timer_init(nfc_scheduler_timer_t *timer);
void nfc_scheduler_timer_start(nfc_scheduler_timer_t *timer);
uint32_t nfc_scheduler_timer_get(nfc_scheduler_timer_t *timer);
void nfc_scheduler_timer_stop(nfc_scheduler_timer_t *timer);
void nfc_scheduler_timer_reset(nfc_scheduler_timer_t *timer);
/** Init scheduler
* \param pScheduler scheduler instance to init
* \param pTimer timer instance
*/
void nfc_scheduler_init(nfc_scheduler_t *pScheduler, nfc_scheduler_timer_t *pTimer);
/** Iterate through all tasks
* \param pScheduler scheduler instance
* \param events mask of events (except EVENT_TIMEOUT) that have been raised since this function last returned (0 on first call)
* \return time after which this function must be called again if no other event arises
*/
uint32_t nfc_scheduler_iteration(nfc_scheduler_t *pScheduler, uint32_t events);
/** Queue a task to execute
* \param pScheduler scheduler instance
* \param pTask task to queue
*
*/
void nfc_scheduler_queue_task(nfc_scheduler_t *pScheduler, nfc_task_t *pTask);
/** Remove a task to execute
* \param pScheduler scheduler instance
* \param pTask task to remove
* \param abort abort task if queued
*/
void nfc_scheduler_dequeue_task(nfc_scheduler_t *pScheduler, bool abort, nfc_task_t *pTask);
/** Initialize task with the following parameters
* \param pTask task to initialize
* \param events events on which to call task
* \param timeout if relevant
* \param fn function to be called
* \param pUserData data that will be passed to function
*/
void task_init(nfc_task_t *pTask, uint32_t events, uint32_t timeout, nfc_task_fn fn, void *pUserData);
#ifdef __cplusplus
}
#endif
#endif /* NFC_SCHEDULER_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file nfc_transport.c
* \copyright Copyright (c) ARM Ltd 2013-2018
* \author Donatien Garnier
* \details Transport layer
*/
/** \addtogroup Implementation
* @{
* \name Transport
* @{
*/
#include "stack/nfc_errors.h"
#include "nfc_transport.h"
/** Initialize transport with a specific implementation
* \param pTransport pointer to a nfc_transport_t structure to initialize
* \param write transport write function
* \param read transport read function
* \param pUser parameter that will be passed to any of the above functions
*/
void nfc_transport_init(nfc_transport_t *pTransport, nfc_transport_write_fn_t write, nfc_transport_read_fn_t read, void *pUser)
{
pTransport->write = write;
pTransport->read = read;
pTransport->pUser = pUser;
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file nfc_transport.h
* \copyright Copyright (c) ARM Ltd 2013-2018
* \author Donatien Garnier
*/
/** \addtogroup Implementation
* @{
* \name Transport
* @{
*/
#ifndef NFC_TRANSPORT_H_
#define NFC_TRANSPORT_H_
#include "stack/nfc_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Function called to write a register's value
* \param address address of the register to write to
* \param outBuf buffer to write
* \param outLen buffer's length
* \param pUser parameter passed to the nfc_transport_init function
*/
typedef void (*nfc_transport_write_fn_t)(uint8_t address, const uint8_t *outBuf, size_t outLen, void *pUser);
/** Function called to read a register's value
* \param address address to read packet from
* \param outBuf buffer to read
* \param outLen buffer's length
* \param pUser parameter passed to the nfc_transport_init function
*/
typedef void (*nfc_transport_read_fn_t)(uint8_t address, uint8_t *inBuf, size_t inLen, void *pUser);
typedef struct __transport {
nfc_transport_write_fn_t write;
nfc_transport_read_fn_t read;
void *pUser;
} nfc_transport_t;
void nfc_transport_init(nfc_transport_t *pTransport, nfc_transport_write_fn_t write, nfc_transport_read_fn_t read, void *pUser);
static inline void nfc_transport_write(nfc_transport_t *pTransport, uint8_t address, const uint8_t *outBuf, size_t outLen)
{
pTransport->write(address, outBuf, outLen, pTransport->pUser);
}
static inline void nfc_transport_read(nfc_transport_t *pTransport, uint8_t address, uint8_t *inBuf, size_t inLen)
{
pTransport->read(address, inBuf, inLen, pTransport->pUser);
}
#ifdef __cplusplus
}
#endif
#endif /* NFC_TRANSPORT_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,343 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file iso7816.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "iso7816.c"
#endif
#include "stack/nfc_errors.h"
#include "iso7816.h"
#include "iso7816_app.h"
#include "iso7816_defs.h"
#include "tech/isodep/isodep_target.h"
#include "platform/nfc_debug.h"
static void iso7816_disconnected(nfc_tech_iso7816_t *pIso7816, bool deselected);
static nfc_err_t iso7816_parse(nfc_tech_iso7816_t *pIso7816);
static void iso7816_receive(nfc_tech_iso7816_t *pIso7816);
static nfc_err_t iso7816_transmit(nfc_tech_iso7816_t *pIso7816);
static bool iso7816_mf_command(nfc_tech_iso7816_t *pIso7816);
static void iso_dep_received_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData);
static void iso_dep_transmitted_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData);
static void iso_dep_disconnected_cb(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData);
static void iso_dep_stream_transmit_cb(ac_buffer_t *ppDataIn, bool *pClose, size_t maxLength, void *pUserParam);
static void iso_dep_stream_receive_cb(ac_buffer_t *pDataOut, bool closed, void *pUserParam);
void nfc_tech_iso7816_init(nfc_tech_iso7816_t *pIso7816, nfc_transceiver_t *pTransceiver, nfc_tech_iso7816_disconnected_cb disconnectedCb, void *pUserData)
{
ac_buffer_init(&pIso7816->hist, NULL, 0);
nfc_tech_isodep_target_init(&pIso7816->isoDepTarget, pTransceiver, &pIso7816->hist, iso_dep_disconnected_cb, pIso7816);
pIso7816->pAppList = NULL;
pIso7816->pSelectedApp = NULL;
pIso7816->disconnectedCb = disconnectedCb;
ac_istream_init(&pIso7816->inputStream, iso_dep_stream_transmit_cb, pIso7816);
ac_ostream_init(&pIso7816->outputStream, iso_dep_stream_receive_cb, pIso7816);
ac_buffer_builder_init(&pIso7816->txBldr, pIso7816->txBuf, 2); //Just enough to fit sw
ac_buffer_builder_init(&pIso7816->rxBldr, pIso7816->rxBuf, ISO7816_RX_BUFFER_SIZE);
pIso7816->pUserData = pUserData;
}
void nfc_tech_iso7816_connect(nfc_tech_iso7816_t *pIso7816)
{
pIso7816->disconnected = false;
pIso7816->responseReady = true;
iso7816_receive(pIso7816);
nfc_tech_isodep_target_connect(&pIso7816->isoDepTarget);
}
void nfc_tech_iso7816_disconnect(nfc_tech_iso7816_t *pIso7816)
{
nfc_tech_isodep_target_disconnect(&pIso7816->isoDepTarget);
}
void nfc_tech_iso7816_add_app(nfc_tech_iso7816_t *pIso7816, nfc_tech_iso7816_app_t *pIso7816App)
{
nfc_tech_iso7816_app_t **ppPrevApp = &pIso7816->pAppList;
while (*ppPrevApp != NULL) {
ppPrevApp = &((*ppPrevApp)->pNext);
}
*ppPrevApp = pIso7816App;
pIso7816App->pNext = NULL;
}
nfc_err_t nfc_tech_iso7816_reply(nfc_tech_iso7816_t *pIso7816)
{
nfc_err_t ret;
//Serialize APDU and send
ac_buffer_builder_reset(&pIso7816->txBldr);
ac_buffer_builder_write_nu16(&pIso7816->txBldr, pIso7816->rApdu.sw);
ac_buffer_append(&pIso7816->rApdu.dataOut, ac_buffer_builder_buffer(&pIso7816->txBldr));
NFC_DBG("R-ADPU: (LE):%02X SW:%04X", ac_buffer_reader_readable(&pIso7816->rApdu.dataOut), pIso7816->rApdu.sw);
NFC_DBG_BLOCK(ac_buffer_dump(&pIso7816->rApdu.dataOut);)
ret = iso7816_transmit(pIso7816);
if (ret) {
return ret;
}
return NFC_OK;
}
void iso7816_disconnected(nfc_tech_iso7816_t *pIso7816, bool deselected)
{
pIso7816->disconnected = true;
if (pIso7816->pSelectedApp != NULL) {
//Deselect previous app
pIso7816->pSelectedApp->deselected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData);
pIso7816->pSelectedApp = NULL;
}
if (!deselected) {
pIso7816->disconnectedCb(pIso7816, pIso7816->pUserData);
}
}
nfc_err_t iso7816_parse(nfc_tech_iso7816_t *pIso7816)
{
//Reset R-APDU
ac_buffer_init(&pIso7816->rApdu.dataOut, NULL, 0);
pIso7816->rApdu.sw = ISO7816_SW_OK;
NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pIso7816->rxBldr));)
if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) < 4) {
NFC_ERR("C-APDU is too small");
pIso7816->rApdu.sw = ISO7816_SW_INVALID_CLASS;
nfc_tech_iso7816_reply(pIso7816);
return NFC_ERR_PROTOCOL;
}
pIso7816->cApdu.cla = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr));
pIso7816->cApdu.ins = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr));
pIso7816->cApdu.p1 = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr));
pIso7816->cApdu.p2 = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr));
ac_buffer_init(&pIso7816->cApdu.dataIn, NULL, 0);
pIso7816->cApdu.maxRespLength = 0;
if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) > 1) {
size_t lc = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr));
if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) >= lc) {
ac_buffer_split(&pIso7816->cApdu.dataIn, ac_buffer_builder_buffer(&pIso7816->rxBldr), ac_buffer_builder_buffer(&pIso7816->rxBldr), lc);
} else {
pIso7816->rApdu.sw = ISO7816_SW_WRONG_LENGTH;
nfc_tech_iso7816_reply(pIso7816);
return NFC_ERR_LENGTH; //Not a valid frame
}
}
if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) >= 1) {
pIso7816->cApdu.maxRespLength = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr));
}
NFC_DBG("C-APDU: CLA:%02X INS:%02X P1:%02X P2:%02X LC:%02X LE:%02X", pIso7816->cApdu.cla, pIso7816->cApdu.ins, pIso7816->cApdu.p1, pIso7816->cApdu.p2,
ac_buffer_reader_readable(&pIso7816->cApdu.dataIn), pIso7816->cApdu.maxRespLength);
if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) > 0) {
pIso7816->rApdu.sw = ISO7816_SW_WRONG_LENGTH;
nfc_tech_iso7816_reply(pIso7816);
return NFC_ERR_LENGTH; //Not a valid frame
}
//See if can select an app
if (iso7816_mf_command(pIso7816)) {
nfc_tech_iso7816_reply(pIso7816);
return NFC_OK;
}
//Pass command to selected app
if (pIso7816->pSelectedApp == NULL) {
pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND;
nfc_tech_iso7816_reply(pIso7816);
return NFC_ERR_NOT_FOUND; //Not a valid frame
}
pIso7816->pSelectedApp->apdu(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData);
return NFC_OK;
}
void iso7816_receive(nfc_tech_iso7816_t *pIso7816)
{
ac_buffer_builder_reset(&pIso7816->rxBldr);
nfc_tech_isodep_target_receive(&pIso7816->isoDepTarget, &pIso7816->outputStream, iso_dep_received_cb, pIso7816);
}
nfc_err_t iso7816_transmit(nfc_tech_iso7816_t *pIso7816)
{
return nfc_tech_isodep_target_transmit(&pIso7816->isoDepTarget, &pIso7816->inputStream, iso_dep_transmitted_cb, pIso7816);
}
/** Handle ISO7816-4 command
* \param pTarget pointer to target instance
* \param CLA ISO7816-4 class byte
* \param INS ISO7816-4 instruction byte
* \param P1 ISO7816-4 P1 byte
* \param P2 ISO7816-4 P2 byte
* \param pDataIn ISO7816-4 command payload
* \param pDataOut ISO7816-4 response payload
* \param SW status word
* \return true if command was handled, false if it should be passed to the selected application
*/
bool iso7816_mf_command(nfc_tech_iso7816_t *pIso7816)
{
nfc_tech_iso7816_app_t *pApp;
if (pIso7816->cApdu.cla != 0x00) {
return false;
}
switch (pIso7816->cApdu.ins) {
case ISO7816_INS_SELECT:
switch (pIso7816->cApdu.p1) {
case 0x04: //Selection by DF name
pApp = pIso7816->pAppList;
while (pApp != NULL) {
if (ac_buffer_reader_readable(&pIso7816->cApdu.dataIn) <= pApp->aidSize) {
if (ac_buffer_reader_cmp_bytes(&pIso7816->cApdu.dataIn, pApp->aid, ac_buffer_reader_readable(&pIso7816->cApdu.dataIn))) {
if (pIso7816->pSelectedApp != NULL) {
//Deselect previous app
pIso7816->pSelectedApp->deselected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData);
}
pIso7816->pSelectedApp = pApp;
pIso7816->pSelectedApp->selected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData);
pIso7816->rApdu.sw = ISO7816_SW_OK;
return true;
}
}
pApp = pApp->pNext;
}
pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND;
return true;
default:
if (pIso7816->pSelectedApp == NULL) {
pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND;
return true;
} else {
return false;
}
}
break;
default:
if (pIso7816->pSelectedApp == NULL) {
pIso7816->rApdu.sw = ISO7816_SW_INVALID_INS;
return true;
} else {
return false;
}
break;
}
}
void iso_dep_received_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData)
{
nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData;
(void) pIsodep;
if (ret) {
NFC_WARN("Got error %d", ret);
return;
}
//Parse received APDU
ret = iso7816_parse(pIso7816);
if (ret) {
NFC_WARN("Got error %d", ret);
return;
}
}
void iso_dep_transmitted_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData)
{
nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData;
(void) pIsodep;
if (ret) {
NFC_WARN("Got error %d", ret);
return;
}
//Advertise that we have space in our buffer?
//Switch to receive mode!
iso7816_receive(pIso7816);
}
void iso_dep_disconnected_cb(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData)
{
nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData;
(void) pIsodep;
NFC_DBG("ISO DEP %s", deselected ? "deselected" : "disconnected");
iso7816_disconnected(pIso7816, deselected);
if (deselected) {
// Re-connect immediately
nfc_tech_iso7816_connect(pIso7816);
}
}
void iso_dep_stream_transmit_cb(ac_buffer_t *pDataIn, bool *pClose, size_t maxLength, void *pUserParam)
{
nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserParam;
//Only close if buffer fits in this frame
if (maxLength >= ac_buffer_reader_readable(&pIso7816->rApdu.dataOut))
//if( ac_buffer_total_length(&pLlcp->tx) <= maxLength )
{
maxLength = ac_buffer_reader_readable(&pIso7816->rApdu.dataOut);
*pClose = true;
} else {
*pClose = false;
}
ac_buffer_split(pDataIn, &pIso7816->rApdu.dataOut, &pIso7816->rApdu.dataOut, maxLength);
}
void iso_dep_stream_receive_cb(ac_buffer_t *pDataOut, bool closed, void *pUserParam)
{
nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserParam;
(void) closed;
if (ac_buffer_reader_readable(pDataOut) > ac_buffer_builder_writable(&pIso7816->rxBldr)) {
NFC_ERR("Frame will not fit (%u > %u)", ac_buffer_reader_readable(pDataOut), ac_buffer_builder_writable(&pIso7816->rxBldr));
}
//Feed rx buffer
ac_buffer_builder_copy_n_bytes(&pIso7816->rxBldr, pDataOut, ac_buffer_reader_readable(pDataOut));
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file iso7816.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef ISO7816_H_
#define ISO7816_H_
#include "stack/nfc_common.h"
#include "transceiver/protocols.h"
#include "tech/isodep/isodep_target.h"
#ifdef __cplusplus
extern "C" {
#endif
struct nfc_tech_iso7816_c_apdu {
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
ac_buffer_t dataIn;
size_t maxRespLength;
};
struct nfc_tech_iso7816_r_apdu {
ac_buffer_t dataOut;
uint16_t sw;
};
#define ISO7816_RX_BUFFER_SIZE 256
typedef struct nfc_tech_iso7816_c_apdu nfc_tech_iso7816_c_apdu_t;
typedef struct nfc_tech_iso7816_r_apdu nfc_tech_iso7816_r_apdu_t;
typedef struct nfc_tech_iso7816 nfc_tech_iso7816_t;
typedef void (*nfc_tech_iso7816_disconnected_cb)(nfc_tech_iso7816_t *pIso7816, void *pUserData);
struct nfc_tech_iso7816_app;
typedef struct nfc_tech_iso7816_app nfc_tech_iso7816_app_t;
struct nfc_tech_iso7816 {
nfc_tech_isodep_target_t isoDepTarget;
nfc_tech_iso7816_app_t *pAppList;
nfc_tech_iso7816_app_t *pSelectedApp;
bool disconnected;
nfc_tech_iso7816_c_apdu_t cApdu;
nfc_tech_iso7816_r_apdu_t rApdu;
bool responseReady;
nfc_tech_iso7816_disconnected_cb disconnectedCb;
void *pUserData;
ac_buffer_t hist; //Historical bytes
ac_istream_t inputStream;
ac_ostream_t outputStream;
//PDU buffer (tx)
uint8_t txBuf[2];
ac_buffer_builder_t txBldr;
//Receive buffer
uint8_t rxBuf[ISO7816_RX_BUFFER_SIZE];
ac_buffer_builder_t rxBldr;
};
void nfc_tech_iso7816_init(nfc_tech_iso7816_t *pIso7816, nfc_transceiver_t *pTransceiver, nfc_tech_iso7816_disconnected_cb disconnectedCb, void *pUserData);
void nfc_tech_iso7816_add_app(nfc_tech_iso7816_t *pIso7816, nfc_tech_iso7816_app_t *pIso7816App);
void nfc_tech_iso7816_connect(nfc_tech_iso7816_t *pIso7816);
void nfc_tech_iso7816_disconnect(nfc_tech_iso7816_t *pIso7816);
nfc_err_t nfc_tech_iso7816_reply(nfc_tech_iso7816_t *pIso7816);
inline static nfc_tech_iso7816_c_apdu_t *nfc_tech_iso7816_c_apdu(nfc_tech_iso7816_t *pIso7816)
{
return &pIso7816->cApdu;
}
inline static nfc_tech_iso7816_r_apdu_t *nfc_tech_iso7816_r_apdu(nfc_tech_iso7816_t *pIso7816)
{
return &pIso7816->rApdu;
}
#ifdef __cplusplus
}
#endif
#endif /* ISO7816_H_ */

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file iso7816_app.c
* \copyright Copyright (c) ARM Ltd 2015-2018
* \author Donatien Garnier
*/
#include "iso7816_app.h"
void nfc_tech_iso7816_app_init(nfc_tech_iso7816_app_t *pIso7816App,
nfc_tech_iso7816_t *pIso7816,
const uint8_t *aid, size_t aidSize,
nfc_tech_iso7816_app_cb selected,
nfc_tech_iso7816_app_cb deselected,
nfc_tech_iso7816_app_cb apdu,
void *pUserData
)
{
pIso7816App->pIso7816 = pIso7816;
pIso7816App->aid = aid;
pIso7816App->aidSize = aidSize;
pIso7816App->selected = selected;
pIso7816App->deselected = deselected;
pIso7816App->apdu = apdu;
pIso7816App->pUserData = pUserData;
pIso7816App->pNext = NULL;
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file iso7816_app.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef TECH_ISO7816_ISO7816_APP_H_
#define TECH_ISO7816_ISO7816_APP_H_
#include "stack/nfc_common.h"
#include "iso7816.h"
#ifdef __cplusplus
extern "C" {
#endif
struct nfc_tech_iso7816;
struct nfc_tech_iso7816_app;
typedef void (*nfc_tech_iso7816_app_cb)(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData);
struct nfc_tech_iso7816_app {
nfc_tech_iso7816_t *pIso7816;
const uint8_t *aid;
size_t aidSize;
nfc_tech_iso7816_app_cb selected;
nfc_tech_iso7816_app_cb deselected;
nfc_tech_iso7816_app_cb apdu;
void *pUserData;
nfc_tech_iso7816_app_t *pNext;
};
void nfc_tech_iso7816_app_init(nfc_tech_iso7816_app_t *pIso7816App, nfc_tech_iso7816_t *pIso7816, const uint8_t *aid, size_t aidSize,
nfc_tech_iso7816_app_cb selected,
nfc_tech_iso7816_app_cb deselected,
nfc_tech_iso7816_app_cb apdu,
void *pUserData
);
inline static nfc_err_t nfc_tech_iso7816_app_reply(nfc_tech_iso7816_app_t *pIso7816App)
{
return nfc_tech_iso7816_reply(pIso7816App->pIso7816);
}
inline static nfc_tech_iso7816_c_apdu_t *nfc_tech_iso7816_app_c_apdu(nfc_tech_iso7816_app_t *pIso7816App)
{
return nfc_tech_iso7816_c_apdu(pIso7816App->pIso7816);
}
inline static nfc_tech_iso7816_r_apdu_t *nfc_tech_iso7816_app_r_apdu(nfc_tech_iso7816_app_t *pIso7816App)
{
return nfc_tech_iso7816_r_apdu(pIso7816App->pIso7816);
}
#ifdef __cplusplus
}
#endif
#endif /* TECH_ISO7816_ISO7816_APP_H_ */

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file iso7816_defs.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef ISO7816_DEFS_H_
#define ISO7816_DEFS_H_
#define ISO7816_INS_SELECT 0xA4
#define ISO7816_INS_READ_BINARY 0xB0
#define ISO7816_INS_UPDATE_BINARY 0xD6
#define ISO7816_INS_ENVELOPE 0xC2
#define ISO7816_SW_OK 0x9000
#define ISO7816_SW_INVALID_CLASS 0x6E00
#define ISO7816_SW_INVALID_INS 0x6D00
#define ISO7816_SW_NOT_FOUND 0x6A82
#define ISO7816_SW_WRONG_LENGTH 0x6700
#define ISO7816_PUT_SW(buf, sw) do{ *(buf)=(sw>>8) & 0xFF; *(buf+1)=(sw>>0) & 0xFF; } while(0);
#endif /* ISO7816_DEFS_H_ */

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file isodep.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef ISODEP_H_
#define ISODEP_H_
#include "stack/nfc_common.h"
#include "transceiver/transceiver.h"
#ifdef __cplusplus
extern "C" {
#endif
struct nfc_tech_isodep;
typedef struct nfc_tech_isodep nfc_tech_isodep_t;
typedef void (*nfc_tech_isodep_cb_t)(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData);
typedef void (*nfc_tech_isodep_disconnected_cb)(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData);
#ifdef __cplusplus
}
#endif
#endif /* ISODEP_H_ */

View File

@ -0,0 +1,685 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file isodep_target.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "isodep_target.c"
#endif
#include "isodep_target.h"
#include "stack/nfc_errors.h"
#include "transceiver/transceiver.h"
//Private defines
#define RATS 0xE0
#define FSDI_TO_FSD(x) (((x)<5)?(((x)<<3) + 16):((x)<8)?(((x)<<5)-96):256)
#define FSC_TO_FSCI(x) (((x)<=48)?(((x)-16)>>3):((x)<=128)?(((x)+96)>>5):8) //returns the closest lower or equal value
#define DID(x) ((x) & 0x0F)
#define FSDI(x) (((x) >> 4) & 0x0F)
#define FSCI_TO_FSC(x) FSDI_TO_FSD(x)
#define FSD_TO_FSDI(x) FSC_TO_FSCI(x)
//#define DI_TO_D(x) (1 << (x))
#define DI_TO_BITRATE(x) ((RF_BITRATE)((x) + RF_BITRATE_106K))
#define GET_FRAME_TYPE(pcb) ((((pcb) & 0xF0) == 0xD0)?PPS_FRAME:(((pcb) & 0xC0) == (0x00 << 6))?I_FRAME:((((pcb) & 0xC0) == (0x2 << 6))?R_FRAME:S_FRAME))
#define I_BLOCK_PCB 0
#define R_BLOCK_PCB 2
#define S_BLOCK_PCB 3
#define PCB_TYPE(pcb) (((pcb)>>6)&0x03)
#define BUILD_I_BLOCK_PCB(chaining, cid, nad, block_toggle) ( (0x0 << 6) | (((chaining)?1:0) << 4) \
| (((cid)?1:0) << 3) | (((nad)?1:0) << 2) | (1 << 1) | (((block_toggle)?1:0)) )
#define BUILD_S_BLOCK_PCB(cid, wtx_n_deselect) ( (0x3 << 6) | (((wtx_n_deselect)?0x3:0) << 4) \
| (((cid)?1:0) << 3) | (1 << 1) )
#define BUILD_R_BLOCK_PCB(cid, block_toggle, nak) ( (0x2 << 6) | (1 <<5) | (((nak)?1:0) << 4) \
| (((cid)?1:0) << 3) | (1 << 1) | (((block_toggle)?1:0)) )
#define PCB_IS_CID(pcb) (((pcb) & (1 << 3))?true:false)
#define PCB_BLOCK_TOGGLE(pcb) (((pcb) & 1)?true:false)
#define PCB_CHAINING(pcb) (((pcb) & 0x10)?true:false)
#define PCB_NACK(pcb) (((pcb) & 0x10)?true:false)
#define PCB_WTX(pcb) (((pcb)&0x30)==0x30)
#define WTXM_DEFAULT 10
//Parameters
#define FSC 256 //Maximum frame size the PICC (us) can receive -- TODO should be a parameter at some point -- linked to PN512 buffer
#define SFGI 2 //Guard time ~ 1.2ms
//#define FWI 6 //Max time before answer is ~ 19.3ms
#define FWI 14 //Max time before answer is ~ 19.3ms
typedef enum __dep_type dep_type_t;
enum __dep_type {
dep_type_information,
dep_type_response,
dep_type_supervisory,
};
//Local functions
static void dep_init(nfc_tech_isodep_target_t *pIsodepTarget);
static bool dep_ready(nfc_tech_isodep_target_t *pIsodepTarget);
static void dep_req_information(nfc_tech_isodep_target_t *pIsodepTarget, ac_buffer_t *pReq, bool moreInformation, uint8_t blockNumber);
static void dep_req_response(nfc_tech_isodep_target_t *pIsodepTarget, bool ack, uint8_t blockNumber);
static void dep_req_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool wtxNDeselect, uint8_t wtxm);
static dep_type_t dep_res_type(nfc_tech_isodep_target_t *pIsodepTarget);
static void dep_res_information(nfc_tech_isodep_target_t *pIsodepTarget, size_t maxLength, ac_buffer_t **ppRes, bool *pMoreInformation, uint8_t *pBlockNumber);
static void dep_res_response(nfc_tech_isodep_target_t *pIsodepTarget, bool *pAck, uint8_t *pBlockNumber);
static void dep_res_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool *pWtxNDeselect, uint8_t *pWtxm);
static void dep_disconnected(nfc_tech_isodep_target_t *pIsodepTarget, bool deselected);
static void command_init(nfc_tech_isodep_target_t *pIsodepTarget);
static nfc_err_t command_ats_req(nfc_tech_isodep_target_t *pIsodepTarget);
static nfc_err_t command_dep_req(nfc_tech_isodep_target_t *pIsodepTarget);
static nfc_err_t command_ats_res(nfc_tech_isodep_target_t *pIsodepTarget);
static nfc_err_t command_dep_res(nfc_tech_isodep_target_t *pIsodepTarget);
static void command_reply(nfc_tech_isodep_target_t *pIsodepTarget, bool depWait);
static void command_transceiver_cb(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData);
//High-level Target functions
void nfc_tech_isodep_target_init(nfc_tech_isodep_target_t *pIsodepTarget, nfc_transceiver_t *pTransceiver,
ac_buffer_t *pHist, nfc_tech_isodep_disconnected_cb disconnectedCb, void *pUserData)
{
pIsodepTarget->pTransceiver = pTransceiver;
pIsodepTarget->pHist = pHist;
pIsodepTarget->disconnectedCb = disconnectedCb;
pIsodepTarget->pUserData = pUserData;
dep_init(pIsodepTarget);
command_init(pIsodepTarget);
}
nfc_err_t nfc_tech_isodep_target_connect(nfc_tech_isodep_target_t *pIsodepTarget)
{
NFC_DBG("Connecting");
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_CONNECTING;
transceiver_set_crc(pIsodepTarget->pTransceiver, true, true);
command_transceiver_cb(pIsodepTarget->pTransceiver, NFC_OK, pIsodepTarget);
return NFC_OK;
}
void nfc_tech_isodep_target_disconnect(nfc_tech_isodep_target_t *pIsodepTarget)
{
// This should not be called within a callback
transceiver_abort(pIsodepTarget->pTransceiver);
dep_disconnected(pIsodepTarget, false);
}
nfc_err_t nfc_tech_isodep_target_transmit(nfc_tech_isodep_target_t *pIsodepTarget, ac_istream_t *pStream, nfc_tech_isodep_cb_t cb, void *pUserData)
{
if (pIsodepTarget->dep.pReqStream != NULL) {
return NFC_ERR_BUSY;
}
pIsodepTarget->dep.pResStream = pStream;
pIsodepTarget->dep.resCb = cb;
pIsodepTarget->dep.pResUserData = pUserData;
//Do we need to start transceiving?
if (pIsodepTarget->commands.state == ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD) {
command_reply(pIsodepTarget, false); //Force reply
}
return NFC_OK;
}
nfc_err_t nfc_tech_isodep_target_receive(nfc_tech_isodep_target_t *pIsodepTarget, ac_ostream_t *pStream, nfc_tech_isodep_cb_t cb, void *pUserData)
{
if (pIsodepTarget->dep.pResStream != NULL) {
return NFC_ERR_BUSY;
}
pIsodepTarget->dep.pReqStream = pStream;
pIsodepTarget->dep.reqCb = cb;
pIsodepTarget->dep.pReqUserData = pUserData;
return NFC_OK;
}
//DEP Layer
void dep_init(nfc_tech_isodep_target_t *pIsodepTarget)
{
//ac_buffer_init(&pIsodepTarget->dep.res, NULL, 0);
pIsodepTarget->dep.pReqStream = NULL;
pIsodepTarget->dep.pResStream = NULL;
pIsodepTarget->dep.reqCb = NULL;
pIsodepTarget->dep.pReqUserData = NULL;
pIsodepTarget->dep.resCb = NULL;
pIsodepTarget->dep.pResUserData = NULL;
pIsodepTarget->dep.blockNumber = 1; //Rule C
//pIsodepTarget->dep.pduState = ISO_DEP_TARGET_DEP_PDU_IDLE;
pIsodepTarget->dep.chaining = false;
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_IDLE;
}
bool dep_ready(nfc_tech_isodep_target_t *pIsodepTarget)
{
//Anything to send back?
if (pIsodepTarget->dep.frameState != ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED) {
return true;
}
if ((pIsodepTarget->dep.pResStream != NULL)) {
return true;
} else {
return false;
}
}
void dep_req_information(nfc_tech_isodep_target_t *pIsodepTarget, ac_buffer_t *pReq, bool moreInformation, uint8_t blockNumber)
{
(void) blockNumber;
pIsodepTarget->dep.blockNumber++;
pIsodepTarget->dep.blockNumber %= 2;
// Note: callbacks can call nfc_tech_isodep_target_transmit() - however we must make sure that we wait AFTER this routine has been processed to actually transmit
// To do so, reset state to ATS_RES_SENT state
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT;
if (!pIsodepTarget->dep.chaining
&& (pIsodepTarget->dep.pResStream != NULL)) {
//Sent the full frame
pIsodepTarget->dep.pResStream = NULL;
pIsodepTarget->dep.resCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_OK, pIsodepTarget->dep.pResUserData);
}
if (pIsodepTarget->dep.pReqStream != NULL) {
// Pull more
ac_ostream_push(pIsodepTarget->dep.pReqStream, pReq, !moreInformation);
if (!moreInformation) {
//Got the full frame
pIsodepTarget->dep.pReqStream = NULL;
pIsodepTarget->dep.reqCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_OK, pIsodepTarget->dep.pReqUserData);
}
}
// Update state
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED;
pIsodepTarget->dep.chaining = moreInformation;
}
void dep_req_response(nfc_tech_isodep_target_t *pIsodepTarget, bool ack, uint8_t blockNumber)
{
if (blockNumber != pIsodepTarget->dep.blockNumber) {
//Should be NACK
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_NACK_DIFF_BLOCK_NUMBER_RECEIVED;
} else {
if (ack) {
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_ACK_RECEIVED;
} else {
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED;
}
}
}
void dep_req_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool wtxNDeselect, uint8_t wtxm)
{
(void) wtxm;
if (wtxNDeselect) {
if ((pIsodepTarget->dep.frameState != ISO_DEP_TARGET_DEP_FRAME_WTX_SENT)) {
NFC_WARN("Unexpected WTX frame");
}
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_WTX_RECEIVED;
} else {
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED;
}
}
dep_type_t dep_res_type(nfc_tech_isodep_target_t *pIsodepTarget)
{
dep_type_t depType;
switch (pIsodepTarget->dep.frameState) {
case ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED:
depType = dep_type_supervisory; //Deselect
break;
case ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED:
case ISO_DEP_TARGET_DEP_FRAME_WTX_RECEIVED:
if (pIsodepTarget->dep.chaining) { //Need to ack?
depType = dep_type_response;
} else if (pIsodepTarget->dep.pResStream != NULL) { //Anything to send back?
depType = dep_type_information;
} else {
depType = dep_type_supervisory; //WTX
}
break;
case ISO_DEP_TARGET_DEP_FRAME_ACK_RECEIVED:
if ((pIsodepTarget->dep.pResStream != NULL) && (pIsodepTarget->dep.chaining)) {
depType = dep_type_information;
} else {
depType = dep_type_supervisory; //WTX
}
break;
case ISO_DEP_TARGET_DEP_FRAME_NACK_DIFF_BLOCK_NUMBER_RECEIVED:
depType = dep_type_response; //Should send ACK
break;
case ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED:
depType = dep_type_information;
break;
default:
depType = dep_type_supervisory; //ATN
break;
}
return depType;
}
void dep_res_information(nfc_tech_isodep_target_t *pIsodepTarget, size_t maxLength, ac_buffer_t **ppRes, bool *pMoreInformation, uint8_t *pBlockNumber)
{
*pBlockNumber = pIsodepTarget->dep.blockNumber;
if (pIsodepTarget->dep.frameState != ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED) {
if (pIsodepTarget->dep.pResStream != NULL) {
bool lastFrame = true;
ac_istream_pull(pIsodepTarget->dep.pResStream, &pIsodepTarget->dep.res, &lastFrame, maxLength);
pIsodepTarget->dep.chaining = !lastFrame;
}
} else {
//Retransmit previous frame (leave it as it is)
}
*ppRes = &pIsodepTarget->dep.res;
*pMoreInformation = pIsodepTarget->dep.chaining;
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_INFORMATION_SENT;
}
void dep_res_response(nfc_tech_isodep_target_t *pIsodepTarget, bool *pAck, uint8_t *pBlockNumber)
{
//Continue chaining or send ACK
*pAck = true;
*pBlockNumber = pIsodepTarget->dep.blockNumber;
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_ACK_SENT;
}
void dep_res_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool *pWtxNDeselect, uint8_t *pWtxm)
{
if (pIsodepTarget->dep.frameState == ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED) {
*pWtxNDeselect = false;
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT;
} else {
*pWtxNDeselect = true;
*pWtxm = WTXM_DEFAULT;
pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_WTX_SENT;
}
}
void dep_disconnected(nfc_tech_isodep_target_t *pIsodepTarget, bool deselected)
{
//Call callbacks if needed
if (pIsodepTarget->dep.pReqStream != NULL) {
pIsodepTarget->dep.reqCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_ERR_DISCONNECTED, pIsodepTarget->dep.pReqUserData);
pIsodepTarget->dep.pReqStream = NULL;
}
if (pIsodepTarget->dep.pReqStream != NULL) {
pIsodepTarget->dep.resCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_ERR_DISCONNECTED, pIsodepTarget->dep.pResUserData);
pIsodepTarget->dep.pResStream = NULL;
}
if (pIsodepTarget->commands.state != ISO_DEP_TARGET_COMMANDS_DISCONNECTED) {
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DISCONNECTED;
pIsodepTarget->disconnectedCb((nfc_tech_isodep_t *)pIsodepTarget, deselected, pIsodepTarget->pUserData);
}
}
//Commands Layer
void command_init(nfc_tech_isodep_target_t *pIsodepTarget)
{
ac_buffer_builder_init(&pIsodepTarget->commands.respBldr, pIsodepTarget->commands.respBuf, sizeof(pIsodepTarget->commands.respBuf));
pIsodepTarget->commands.pReq = NULL;
// Update if/when we support DIDs
//pIsodepTarget->commands.did = 0;
//pIsodepTarget->commands.didUsed = false;
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DISCONNECTED;
pIsodepTarget->commands.inPayloadSize = 0;
}
nfc_err_t command_ats_req(nfc_tech_isodep_target_t *pIsodepTarget)
{
//Check we are in a correct state -- this should be the first command received
if (pIsodepTarget->commands.state != ISO_DEP_TARGET_COMMANDS_CONNECTING) {
return NFC_ERR_PROTOCOL;
}
if (ac_buffer_reader_readable(pIsodepTarget->commands.pReq) < 2) {
NFC_ERR("Payload too short");
return NFC_ERR_PROTOCOL;
}
ac_buffer_read_n_skip(pIsodepTarget->commands.pReq, 1);
uint8_t b = ac_buffer_read_nu8(pIsodepTarget->commands.pReq);
//Save DID -- not supported for now
//pIsodepTarget->commands.did = DID(b);
uint8_t fsdi = FSDI(b);
pIsodepTarget->commands.inPayloadSize = FSDI_TO_FSD(fsdi);
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_ATS_REQ_RECVD;
return NFC_OK;
}
nfc_err_t command_dep_req(nfc_tech_isodep_target_t *pIsodepTarget)
{
if (pIsodepTarget->commands.state < ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT) {
return NFC_ERR_PROTOCOL;
}
if (ac_buffer_reader_readable(pIsodepTarget->commands.pReq) < 1) {
NFC_ERR("Payload too short");
return NFC_ERR_PROTOCOL;
}
uint8_t pcb = ac_buffer_read_nu8(pIsodepTarget->commands.pReq);
// Udpate if/when we support DIDs
/*
if( pfb & PFB_DID )
{
uint8_t did = ac_buffer_read_nu8(pIsodepTarget->commands.pReq);
if( pIsodepTarget->commands.did != did )
{
//Not for us
return NFC_ERR_PROTOCOL;
}
pIsodepTarget->commands.didUsed = true;
}
else
{
pIsodepTarget->commands.didUsed = false;
}
if( pfb & PFB_NAD )
{
ac_buffer_read_nu8(pIsodepTarget->commands.pReq); //Skip NAD
}
*/
uint8_t wtxm = 0;
switch (PCB_TYPE(pcb)) {
case I_BLOCK_PCB:
dep_req_information(pIsodepTarget, pIsodepTarget->commands.pReq, PCB_CHAINING(pcb), PCB_BLOCK_TOGGLE(pcb));
break;
case R_BLOCK_PCB:
dep_req_response(pIsodepTarget, !PCB_NACK(pcb), PCB_BLOCK_TOGGLE(pcb));
break;
case S_BLOCK_PCB:
if (PCB_WTX(pcb)) {
if (ac_buffer_reader_readable(pIsodepTarget->commands.pReq) < 1) {
NFC_ERR("Payload too short");
return NFC_ERR_PROTOCOL;
}
wtxm = ac_buffer_read_nu8(pIsodepTarget->commands.pReq);
}
dep_req_supervisory(pIsodepTarget, PCB_WTX(pcb), wtxm);
break;
default:
NFC_ERR("PCB is invalid");
return NFC_ERR_PROTOCOL;
}
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD;
return NFC_OK;
}
nfc_err_t command_ats_res(nfc_tech_isodep_target_t *pIsodepTarget)
{
//Send ATS back
if (ac_buffer_builder_writable(&pIsodepTarget->commands.respBldr) < 5) {
return NFC_ERR_BUFFER_TOO_SMALL;
}
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (5 + ac_buffer_size(pIsodepTarget->pHist)) & 0xFF);
//T0
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0x7 << 4) | FSC_TO_FSCI(FSC)); //TA(1), TB(1) and TC(1) are transmitted
//TA(1)
//For now only 106kbps supported
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (1 << 7) | (0x0 << 4) | 0x0);
//TODO when supporting other bitrates
//ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0 << 7) | (0x3 << 4) | 0x3); //106, 212, 414 kbps bitrates
//TB(1)
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (FWI << 4) | SFGI); //Specify guard-time and time between frames
//TC(1)
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0 << 1) | 0); //DID not supported, NAD not supported
ac_buffer_set_next(ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr), pIsodepTarget->pHist); //Queue general bytes
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT;
//TODO PPS
return NFC_OK;
}
nfc_err_t command_dep_res(nfc_tech_isodep_target_t *pIsodepTarget)
{
uint8_t pcb = 0;
// If/when supporting DIDs
/*
if( pIsodepTarget->commands.didUsed )
{
pcb |= PFB_DID;
}*/
ac_buffer_t *pDepBuf = NULL;
bool moreInformation = false;
bool ack = false;
bool wtxNDeselect = false;
uint8_t wtxm = 0;
uint8_t blockNumber = 0;
size_t maxLength = pIsodepTarget->commands.inPayloadSize - 1;
switch (dep_res_type(pIsodepTarget)) {
case dep_type_information:
dep_res_information(pIsodepTarget, maxLength, &pDepBuf, &moreInformation, &blockNumber);
pcb = BUILD_I_BLOCK_PCB(moreInformation, false, false, blockNumber);
break;
case dep_type_response:
dep_res_response(pIsodepTarget, &ack, &blockNumber);
pcb = BUILD_R_BLOCK_PCB(0, blockNumber, !ack);
break;
case dep_type_supervisory:
dep_res_supervisory(pIsodepTarget, &wtxNDeselect, &wtxm);
pcb = BUILD_S_BLOCK_PCB(0, wtxNDeselect);
break;
}
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, pcb);
/*
if( pIsodepTarget->commands.didUsed )
{
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, pIsodepTarget->commands.did);
}
*/
if (pDepBuf != NULL) {
ac_buffer_set_next(ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr), pDepBuf);
} else if (wtxNDeselect) {
ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, wtxm);
}
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DEP_RES_SENT;
return NFC_OK;
}
void command_reply(nfc_tech_isodep_target_t *pIsodepTarget, bool depWait)
{
nfc_err_t ret;
//Check whether we want to reply or wait for the higher layer to send us something
if ((pIsodepTarget->commands.state == ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD) && depWait && !dep_ready(pIsodepTarget)) {
return;
}
//Reply
ac_buffer_builder_reset(&pIsodepTarget->commands.respBldr);
switch (pIsodepTarget->commands.state) {
case ISO_DEP_TARGET_COMMANDS_ATS_REQ_RECVD:
ret = command_ats_res(pIsodepTarget);
break;
case ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD:
ret = command_dep_res(pIsodepTarget);
break;
default:
NFC_ERR("Unknown state %d", pIsodepTarget->commands.state);
//Go back to receive mode
nfc_transceiver_transceive(pIsodepTarget->pTransceiver, command_transceiver_cb, pIsodepTarget);
return;
}
if (ret) {
NFC_ERR("Error %d", ret);
//Go back to receive mode
nfc_transceiver_transceive(pIsodepTarget->pTransceiver, command_transceiver_cb, pIsodepTarget);
return;
}
NFC_DBG("Transceive");
if (pIsodepTarget->dep.frameState == ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT) {
transceiver_set_transceive_options(pIsodepTarget->pTransceiver, true, false, true);
} else {
transceiver_set_transceive_options(pIsodepTarget->pTransceiver, true, true, false);
}
NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr));)
//Send next frame
transceiver_set_write(pIsodepTarget->pTransceiver, ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr));
nfc_transceiver_transceive(pIsodepTarget->pTransceiver, command_transceiver_cb, pIsodepTarget);
NFC_DBG("Processed");
}
void command_transceiver_cb(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData)
{
nfc_tech_isodep_target_t *pIsodepTarget = (nfc_tech_isodep_target_t *) pUserData;
if (ret == NFC_ERR_ABORTED) {
// Just return
return;
}
if (pIsodepTarget->dep.frameState == ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT) {
NFC_DBG("Deselect sent and re-polled: %u", ret);
//We are now disconnected (deselected)
//Reset status
dep_init(pIsodepTarget);
command_init(pIsodepTarget);
transceiver_set_crc(pIsodepTarget->pTransceiver, true, true);
pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_CONNECTING;
//Call so that we can reinit higher layer
dep_disconnected(pIsodepTarget, true); //This will call us again
return;
}
//Prepare default empty reply
transceiver_set_write(pTransceiver, NULL);
transceiver_set_transceive_options(pTransceiver, false, true, false);
if (ret == NFC_ERR_FIELD) {
NFC_WARN("Lost initiator");
dep_disconnected(pIsodepTarget, false);
return;
} else if (ret) {
//We should ignore this error and wait for another frame
NFC_WARN("Got invalid frame (error %d)", ret);
nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget);
return;
}
NFC_DBG("Reading data from initiator");
ac_buffer_t *pDataInitiator = transceiver_get_read(pTransceiver); //In buffer
NFC_DBG_BLOCK(ac_buffer_dump(pDataInitiator);)
//Framing is handled by transceiver
if ((ac_buffer_reader_readable(pDataInitiator) < 1)) {
NFC_ERR("Empty initiator message");
//Go back to receive mode
nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget);
return;
}
pIsodepTarget->commands.pReq = pDataInitiator;
//Duplicate to peek on req
ac_buffer_t dataInitiatorDup;
ac_buffer_dup(&dataInitiatorDup, pDataInitiator);
uint8_t req = ac_buffer_read_nu8(&dataInitiatorDup);
switch (req) {
case RATS:
ret = command_ats_req(pIsodepTarget);
break;
default:
ret = command_dep_req(pIsodepTarget);
break;
}
if (ret) {
NFC_ERR("Error %d", ret);
//Go back to receive mode
nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget);
return;
}
NFC_DBG("Reply");
//Reply
command_reply(pIsodepTarget, true); //Make sure we send a WTX frame if we cannot respond straight away
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file isodep_target.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef ISODEP_TARGET_H_
#define ISODEP_TARGET_H_
#include "stack/nfc_common.h"
#include "transceiver/transceiver.h"
#include "isodep.h"
#ifdef __cplusplus
extern "C" {
#endif
struct nfc_tech_isodep_target;
typedef struct nfc_tech_isodep_target nfc_tech_isodep_target_t;
struct nfc_tech_isodep_target {
nfc_transceiver_t *pTransceiver;
struct {
ac_ostream_t *pReqStream;
ac_istream_t *pResStream;
nfc_tech_isodep_cb_t reqCb;
void *pReqUserData;
nfc_tech_isodep_cb_t resCb;
void *pResUserData;
ac_buffer_t res;
bool chaining;
uint8_t blockNumber;
enum {
ISO_DEP_TARGET_DEP_FRAME_IDLE,
ISO_DEP_TARGET_DEP_FRAME_WTX_RECEIVED,
ISO_DEP_TARGET_DEP_FRAME_WTX_SENT,
ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED,
ISO_DEP_TARGET_DEP_FRAME_INFORMATION_SENT,
ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED,
ISO_DEP_TARGET_DEP_FRAME_NACK_DIFF_BLOCK_NUMBER_RECEIVED,
ISO_DEP_TARGET_DEP_FRAME_NACK_SENT,
ISO_DEP_TARGET_DEP_FRAME_ACK_RECEIVED,
ISO_DEP_TARGET_DEP_FRAME_ACK_SENT,
ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED,
ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT,
} frameState;
} dep;
struct {
enum {
ISO_DEP_TARGET_COMMANDS_DISCONNECTED,
ISO_DEP_TARGET_COMMANDS_CONNECTING,
ISO_DEP_TARGET_COMMANDS_ATS_REQ_RECVD,
ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT,
ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD,
ISO_DEP_TARGET_COMMANDS_DEP_RES_SENT,
} state;
size_t inPayloadSize;
ac_buffer_builder_t respBldr;
uint8_t respBuf[32];
ac_buffer_t *pReq;
} commands;
ac_buffer_t *pHist;
nfc_tech_isodep_disconnected_cb disconnectedCb;
void *pUserData;
};
//High-level Target functions
void nfc_tech_isodep_target_init(nfc_tech_isodep_target_t *pIsodepTarget, nfc_transceiver_t *pTransceiver,
ac_buffer_t *pHist, nfc_tech_isodep_disconnected_cb disconnectedCb, void *pUserData);
nfc_err_t nfc_tech_isodep_target_connect(nfc_tech_isodep_target_t *pIsodepTarget);
void nfc_tech_isodep_target_disconnect(nfc_tech_isodep_target_t *pIsodepTarget);
nfc_err_t nfc_tech_isodep_target_transmit(nfc_tech_isodep_target_t *pIsodepTarget, ac_istream_t *pStream, nfc_tech_isodep_cb_t cb, void *pUserData);
nfc_err_t nfc_tech_isodep_target_receive(nfc_tech_isodep_target_t *pIsodepTarget, ac_ostream_t *pStream, nfc_tech_isodep_cb_t cb, void *pUserData);
#ifdef __cplusplus
}
#endif
#endif /* ISODEP_TARGET_H_ */

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file type4_target.c
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "type4_target.c"
#endif
#include "stack/nfc_errors.h"
#include "type4_target.h"
#include "tech/iso7816/iso7816_defs.h"
#define TYPE4_NDEF_VERSION 2
#if TYPE4_NDEF_VERSION == 2
static const uint8_t aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
#else
static const uint8_t aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 };
#endif
#define CC_FILE 0xE103 //Must not be changed
#define NDEF_FILE 0xA443
#define DEFAULT_FILE 0x0000
static void app_selected(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData);
static void app_deselected(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData);
static void app_apdu(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData);
static nfc_err_t data_read(nfc_tech_type4_target_t *pType4Target, ac_buffer_t *pBuf, uint16_t file, size_t off, size_t len);
static nfc_err_t data_write(nfc_tech_type4_target_t *pType4Target, ac_buffer_t *pBuf, uint16_t file, size_t off);
void nfc_tech_type4_target_init(nfc_tech_type4_target_t *pType4Target, nfc_tech_iso7816_t *pIso7816, ndef_msg_t *pNdef)
{
ac_buffer_builder_init(&pType4Target->ccFileBldr, pType4Target->ccFileBuf, /*sizeof(pType4Target->ccFileBuf)*/15);
ac_buffer_builder_init(&pType4Target->ndefFileBldr, pType4Target->ndefFileBuf, /*sizeof(pType4Target->ndefFileBuf)*/2);
pType4Target->selFile = DEFAULT_FILE;
pType4Target->pNdef = pNdef;
pType4Target->written = false;
nfc_tech_iso7816_app_init(&pType4Target->app, pIso7816, aid, sizeof(aid), app_selected, app_deselected, app_apdu, pType4Target);
nfc_tech_iso7816_add_app(pIso7816, &pType4Target->app);
}
void app_selected(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData)
{
nfc_tech_type4_target_t *pType4Target = (nfc_tech_type4_target_t *) pUserData;
NFC_DBG("Selected");
(void) pIso7816App;
ac_buffer_builder_reset(ndef_msg_buffer_builder(pType4Target->pNdef));
//Populate CC file
ac_buffer_builder_reset(&pType4Target->ccFileBldr);
ac_buffer_builder_write_nu16(&pType4Target->ccFileBldr, 15); //CC file is 15 bytes long
#if TYPE4_NDEF_VERSION == 2
ac_buffer_builder_write_nu8(&pType4Target->ccFileBldr, 0x20); //NFC Forum Tag Type 4 V2.0 compliant
#else
ac_buffer_builder_write_nu8(&pType4Target->ccFileBldr, 0x10); //NFC Forum Tag Type 4 V1.0 compliant
#endif
ac_buffer_builder_write_nu16(&pType4Target->ccFileBldr, 256 /* Max frame size */ - 2 /* SW */ - 3 /* ISO-DEP PFB + DID + NAD */); //Max data size that can be read from the tag
ac_buffer_builder_write_nu16(&pType4Target->ccFileBldr, 256 /* Max frame size */ - 6 /* CLA INS P1 P2 LC LE */ - 3 /* ISO-DEP PFB + DID + NAD */); //Max data size that can be written to the tag
ac_buffer_builder_write_nu8(&pType4Target->ccFileBldr, 0x04); //NDEF File Control TLV - Type
ac_buffer_builder_write_nu8(&pType4Target->ccFileBldr, 6); //NDEF File Control TLV - Length
ac_buffer_builder_write_nu16(&pType4Target->ccFileBldr, NDEF_FILE); //NDEF file id
ac_buffer_builder_write_nu16(&pType4Target->ccFileBldr, 2 /* length header */ + ac_buffer_builder_writable(ndef_msg_buffer_builder(pType4Target->pNdef))); //Max size of NDEF data
ac_buffer_builder_write_nu8(&pType4Target->ccFileBldr, 0x00); //Open read access
ac_buffer_builder_write_nu8(&pType4Target->ccFileBldr, 0x00); //Open write access
//Encode NDEF file
ndef_msg_encode(pType4Target->pNdef);
//Populate NDEF file
ac_buffer_builder_init(&pType4Target->ndefFileBldr, pType4Target->ndefFileBuf, /*sizeof(pType4Target->ndefFileBuf)*/2);
ac_buffer_builder_write_nu16(&pType4Target->ndefFileBldr, ac_buffer_reader_readable(ac_buffer_builder_buffer(ndef_msg_buffer_builder(pType4Target->pNdef))));
//Pad NDEF file with 0s
while (ac_buffer_builder_writable(ndef_msg_buffer_builder(pType4Target->pNdef)) > 0) {
ac_buffer_builder_write_nu8(ndef_msg_buffer_builder(pType4Target->pNdef), 0);
}
//No file selected
pType4Target->selFile = DEFAULT_FILE;
pType4Target->written = false;
}
void app_deselected(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData)
{
nfc_tech_type4_target_t *pType4Target = (nfc_tech_type4_target_t *) pUserData;
(void) pIso7816App;
//Reset buffers
ac_buffer_builder_reset(&pType4Target->ccFileBldr);
ac_buffer_builder_set_full(&pType4Target->ndefFileBldr); //To read length
ac_buffer_builder_reset(ndef_msg_buffer_builder(pType4Target->pNdef));
NFC_DBG("Deselected");
if (pType4Target->written) {
NFC_DBG("New content has been written");
//Try to parse NDEF
//Set buffer length based on file header
size_t length = ac_buffer_read_nu16(ac_buffer_builder_buffer(&pType4Target->ndefFileBldr));
NFC_DBG("Length is %lu", length);
if (length < ac_buffer_builder_writable(ndef_msg_buffer_builder(pType4Target->pNdef))) {
ac_buffer_builder_set_write_offset(ndef_msg_buffer_builder(pType4Target->pNdef), length);
ndef_msg_decode(pType4Target->pNdef);
} else {
NFC_ERR("Invalid length");
}
}
}
void app_apdu(nfc_tech_iso7816_app_t *pIso7816App, void *pUserData)
{
nfc_tech_type4_target_t *pType4Target = (nfc_tech_type4_target_t *) pUserData;
//Reset buffers
ac_buffer_builder_set_full(&pType4Target->ccFileBldr);
ac_buffer_builder_set_full(&pType4Target->ndefFileBldr);
ac_buffer_builder_set_full(ndef_msg_buffer_builder(pType4Target->pNdef)); //Set offset to 0, size to max
ac_buffer_set_next(ac_buffer_builder_buffer(&pType4Target->ndefFileBldr), ac_buffer_builder_buffer(ndef_msg_buffer_builder(pType4Target->pNdef)));
//Recover PDU
nfc_tech_iso7816_c_apdu_t *pCApdu = nfc_tech_iso7816_app_c_apdu(pIso7816App);
nfc_tech_iso7816_r_apdu_t *pRApdu = nfc_tech_iso7816_app_r_apdu(pIso7816App);
nfc_err_t ret;
switch (pCApdu->ins) {
case ISO7816_INS_SELECT:
switch (pCApdu->p1) {
case 0x00: //Selection by ID
case 0x02: //Selection by child ID
if (ac_buffer_reader_readable(&pCApdu->dataIn) != 2) {
pRApdu->sw = ISO7816_SW_NOT_FOUND;
break;
}
uint16_t file = ac_buffer_read_nu16(&pCApdu->dataIn);
if (file == NDEF_FILE) {
pType4Target->selFile = NDEF_FILE;
NFC_DBG("NDEF File selected");
pRApdu->sw = ISO7816_SW_OK;
} else if (file == CC_FILE) {
pType4Target->selFile = CC_FILE;
NFC_DBG("CC File selected");
pRApdu->sw = ISO7816_SW_OK;
} else {
//file = DEFAULT_FILE;
NFC_DBG("Could not select file %04X", file);
pRApdu->sw = ISO7816_SW_NOT_FOUND;
}
break;
default:
pRApdu->sw = ISO7816_SW_NOT_FOUND;
break;
}
break;
case 0xB0: //Read binary
NFC_DBG("Trying to read %d bytes at offset %d from file %04x", pCApdu->maxRespLength, (pCApdu->p1 << 8) | pCApdu->p2, pType4Target->selFile);
ret = data_read(pType4Target, &pRApdu->dataOut, pType4Target->selFile, (pCApdu->p1 << 8) | pCApdu->p2, pCApdu->maxRespLength);
if (ret == NFC_OK) {
NFC_DBG("Read %d bytes", ac_buffer_reader_readable(&pRApdu->dataOut));
NFC_DBG_BLOCK(ac_buffer_dump(&pRApdu->dataOut);)
pRApdu->sw = ISO7816_SW_OK;
} else {
NFC_DBG("Failed with ret code %d", ret);
pRApdu->sw = ISO7816_SW_WRONG_LENGTH;
}
break;
case 0xD6: //Update binary
NFC_DBG("Trying to write %d bytes at offset %d to file %04x", ac_buffer_reader_readable(&pCApdu->dataIn), (pCApdu->p1 << 8) | pCApdu->p2, pType4Target->selFile);
ret = data_write(pType4Target, &pCApdu->dataIn, pType4Target->selFile, (pCApdu->p1 << 8) | pCApdu->p2);
if (ret == NFC_OK) {
NFC_DBG("OK");
pRApdu->sw = ISO7816_SW_OK;
pType4Target->written = true;
} else {
NFC_DBG("Failed with ret code %d", ret);
pRApdu->sw = ISO7816_SW_WRONG_LENGTH;
}
break;
default:
pRApdu->sw = ISO7816_SW_INVALID_INS;
break;
}
//Send reply
nfc_tech_iso7816_app_reply(pIso7816App);
}
nfc_err_t data_read(nfc_tech_type4_target_t *pType4Target, ac_buffer_t *pBuf, uint16_t file, size_t off, size_t len)
{
ac_buffer_t *pFile;
switch (file) {
case CC_FILE:
pFile = ac_buffer_builder_buffer(&pType4Target->ccFileBldr);
break;
case NDEF_FILE:
pFile = ac_buffer_builder_buffer(&pType4Target->ndefFileBldr);
break;
default:
return NFC_ERR_NOT_FOUND;
}
if (off > ac_buffer_reader_readable(pFile)) {
return NFC_ERR_LENGTH;
}
ac_buffer_read_n_skip(pFile, off);
if (len > ac_buffer_reader_readable(pFile)) {
len = ac_buffer_reader_readable(pFile);
}
ac_buffer_split(pBuf, pFile, pFile, len);
return NFC_OK;
}
nfc_err_t data_write(nfc_tech_type4_target_t *pType4Target, ac_buffer_t *pBuf, uint16_t file, size_t off)
{
ac_buffer_t *pFile;
switch (file) {
case NDEF_FILE:
pFile = ac_buffer_builder_buffer(&pType4Target->ndefFileBldr);
break;
case CC_FILE: //Cannot write to CC file!
default:
return NFC_ERR_NOT_FOUND;
}
size_t len = ac_buffer_reader_readable(pBuf);
if (off > ac_buffer_reader_readable(pFile)) {
return NFC_ERR_LENGTH;
}
ac_buffer_read_n_skip(pFile, off);
if (len > ac_buffer_reader_readable(pFile)) {
len = ac_buffer_reader_readable(pFile);
}
while (len > 0) {
size_t cpy;
ac_buffer_builder_t builder;
ac_buffer_dup(ac_buffer_builder_buffer(&builder), pFile);
ac_buffer_builder_from_buffer(&builder);
cpy = ac_buffer_builder_writable(&builder);
cpy = MIN(cpy, len);
ac_buffer_builder_copy_n_bytes(&builder, pBuf, cpy);
pFile = ac_buffer_next(pFile);
len -= cpy;
}
return NFC_OK;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file type4_target.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef TECH_TYPE4_TYPE4_TARGET_H_
#define TECH_TYPE4_TYPE4_TARGET_H_
#include "stack/nfc_common.h"
#include "tech/iso7816/iso7816.h"
#include "tech/iso7816/iso7816_app.h"
#include "ndef/ndef.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct nfc_tech_type4_target nfc_tech_type4_target_t;
typedef void (*nfc_tech_type4_cb)(nfc_tech_type4_target_t *pType4Target, nfc_err_t ret, void *pUserData);
struct nfc_tech_type4_target {
nfc_tech_iso7816_app_t app;
ndef_msg_t *pNdef;
uint8_t ccFileBuf[15];
ac_buffer_builder_t ccFileBldr;
uint8_t ndefFileBuf[2];
ac_buffer_builder_t ndefFileBldr;
uint16_t selFile;
bool written;
};
void nfc_tech_type4_target_init(nfc_tech_type4_target_t *pType4Target, nfc_tech_iso7816_t *pIso7816, ndef_msg_t *pNdef);
#ifdef __cplusplus
}
#endif
#endif /* TECH_TYPE4_TYPE4_TARGET_H_ */

View File

@ -0,0 +1,356 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details PN512 implementation of the transceiver interface
*/
#define __DEBUG__ 4
#ifndef __MODULE__
#define __MODULE__ "pn512.c"
#endif
#include "stack/nfc_errors.h"
#include "stdlib.h"
#include "acore/ac_buffer.h"
#include "transceiver/transceiver.h"
#include "transceiver/protocols.h"
#include "pn512_rf.h"
#include "pn512_registers.h"
#include "pn512_cmd.h"
#include "pn512_hw.h"
#include "pn512_irq.h"
#include "pn512_poll.h"
#include "pn512_transceive.h"
#include "pn512_internal.h"
#include "pn512.h"
#define DEFAULT_READER_TRANSCEIVE_TIMEOUT 100
#define DEFAULT_TARGET_TRANSCEIVE_TIMEOUT -1
//Prototypes
#include "pn512_internal.h"
/** \addtogroup PN512
* @{
* \name Transceiver
* \details Implementation of the transceiver interface
* @{
*/
//PN 512 VTABLE
static const transceiver_impl_t pn512_impl = {
.set_protocols = pn512_set_protocols,
.poll = pn512_poll,
.transceive = pn512_transceive,
.abort = pn512_abort,
.set_crc = pn512_set_crc,
.set_timeout = pn512_set_timeout,
.set_transceive_options = pn512_set_transceive_options,
.set_transceive_framing = pn512_set_transceive_framing,
.set_write = pn512_set_write,
.get_read = pn512_get_read,
.set_last_byte_length = pn512_set_last_byte_length,
.get_last_byte_length = pn512_get_last_byte_length,
.set_first_byte_align = pn512_set_first_byte_align,
.close = pn512_close,
.sleep = pn512_sleep
};
/** Initialize PN512 transceiver
* \param pPN512 pointer to pn512_t structure to initialize
* \param pTransport pointer to already initialized nfc_transport_t structure
* \return NFC_OK (0) on success or NFC_ERR_* error on failure
*/
nfc_err_t pn512_init(pn512_t *pPN512, nfc_transport_t *pTransport, nfc_scheduler_timer_t *pTimer)
{
////
//For Self-test
////
#if NFC_PN512_SELFTEST
const uint8_t null_array[25] = {0};
#endif
////
uint8_t r;
//Init transceiver
transceiver_init((nfc_transceiver_t *)pPN512, pTransport, pTimer);
//Init buffer
ac_buffer_builder_init(&pPN512->readBufBldr, pPN512->payload, 256);
pPN512->readFirstByteAlign = 0;
pPN512->readLastByteLength = 8;
pPN512->writeLastByteLength = 8;
//Populate functions
pPN512->transceiver.fn = &pn512_impl;
//Init variables
memset(&pPN512->config.initiators, 0, sizeof(nfc_tech_t));
memset(&pPN512->config.targets, 0, sizeof(nfc_tech_t));
pPN512->timeout = -1;
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
pn512_hw_init(pPN512);
pn512_registers_init(pPN512); //Cannot switch page now
pn512_cmd_init(pPN512);
pn512_cmd_exec(pPN512, PN512_CMD_SOFTRST);
pn512_cmd_wait_idle(pPN512, -1);
//pn512_registers_init(pPN512);
//Put into known state
pn512_registers_reset(pPN512);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_fifo_clear(pPN512);
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pn512_cmd_wait_idle(pPN512, -1);
pn512_rf_field_switch_off(pPN512);
//Required for polling loop
srand(4242);
#if NFC_PN512_SELFTEST // Self test
pn512_cmd_exec(pPN512, PN512_CMD_SOFTRST);
pn512_cmd_wait_idle(pPN512, -1);
const uint8_t null_array_buf[25] = {0}; //FIXME
ac_buffer_t null_array;
ac_buffer_init(&null_array, null_array_buf, 25);
//Perform self test
pn512_fifo_write(pPN512, &null_array);
pn512_cmd_exec(pPN512, PN512_CMD_CONFIG);
while (pn512_cmd_get(pPN512) != PN512_CMD_IDLE);
pn512_register_write(pPN512, PN512_REG_AUTOTEST, 0x09);
ac_buffer_init(&null_array, null_array_buf, 1);
pn512_fifo_write(pPN512, &null_array);
pn512_cmd_exec(pPN512, PN512_CMD_CRC);
while (pn512_cmd_get(pPN512) != PN512_CMD_IDLE);
DBGX_ENTER();
NFC_DBG("Test result:");
while (pn512_fifo_length(pPN512)) {
ac_buffer_builder_t read_byte;
ac_buffer_builder_init(&read_byte, null_array_buf, 1);
pn512_fifo_read(pPN512, &read_byte);
DBGX("%02x ", null_array_buf[0]);
}
DBGX("\n");
DBGX_LEAVE();
#endif
r = pn512_register_read(pPN512, PN512_REG_VERSION);
NFC_DBG_BLOCK(
NFC_DBG("PN512 version %02x", r);
)
if ((r != 0x82) && (r != 0xB1) && (r != 0xB2)) {
return NFC_ERR_UNSUPPORTED; //PN512 not found
}
return NFC_OK;
}
/** Get pointer to nfc_transceiver_t structure
* \param pPN512 pointer to pn512_t instance
* \return pointer to initialized nfc_transceiver_t instance
*/
nfc_transceiver_t *pn512_get_transceiver(pn512_t *pPN512)
{
return &pPN512->transceiver;
}
void pn512_set_protocols(nfc_transceiver_t *pTransceiver, nfc_tech_t initiators, nfc_tech_t targets, polling_options_t options)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
//If different, reconfigure
if (memcmp(&initiators, &pPN512->config.initiators, sizeof(nfc_tech_t)) || memcmp(&targets, &pPN512->config.targets, sizeof(nfc_tech_t))) {
pPN512->config.initiators = initiators;
if (memcmp(&targets, &pPN512->config.targets, sizeof(nfc_tech_t))) {
pPN512->config.targets = targets;
pn512_poll_setup(pPN512);
}
pTransceiver->initiator_ntarget = false;
memset(&pTransceiver->active_tech, 0, sizeof(nfc_tech_t));
}
pPN512->config.options = options;
}
void pn512_poll(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
pn512_poll_hw(pPN512, pn512_transceiver_callback);
}
void pn512_set_crc(nfc_transceiver_t *pTransceiver, bool crc_out, bool crc_in)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pn512_framing_crc_set(pPN512, crc_out, crc_in);
}
void pn512_set_timeout(nfc_transceiver_t *pTransceiver, int timeout)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pPN512->timeout = timeout;
}
void pn512_set_transceive_options(nfc_transceiver_t *pTransceiver, bool transmit, bool receive, bool repoll)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if (transmit && receive) {
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
} else if (transmit && repoll) {
pPN512->nextFrameMode = pn512_transceive_mode_transmit_and_target_autocoll;
} else if (transmit) {
pPN512->nextFrameMode = pn512_transceive_mode_transmit;
} else if (receive) {
pPN512->nextFrameMode = pn512_transceive_mode_receive;
} else {
pPN512->nextFrameMode = pn512_transceive_mode_target_autocoll;
}
}
void pn512_set_transceive_framing(nfc_transceiver_t *pTransceiver, nfc_framing_t framing)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pn512_framing_set(pPN512, framing);
//Switch NFC tech if NFC DEP
if (pTransceiver->active_tech.nfc_nfc_dep_a
|| pTransceiver->active_tech.nfc_nfc_dep_f_212
|| pTransceiver->active_tech.nfc_nfc_dep_f_424) {
//FIXME
pTransceiver->active_tech.nfc_nfc_dep_a = 0;
pTransceiver->active_tech.nfc_nfc_dep_f_212 = 0;
pTransceiver->active_tech.nfc_nfc_dep_f_424 = 0;
switch (framing) {
case nfc_framing_target_a_106:
case nfc_framing_initiator_a_106:
pTransceiver->active_tech.nfc_nfc_dep_a = 1;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
pTransceiver->active_tech.nfc_nfc_dep_f_212 = 1;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
pTransceiver->active_tech.nfc_nfc_dep_f_424 = 1;
break;
default:
break;
}
}
}
void pn512_set_write(nfc_transceiver_t *pTransceiver, ac_buffer_t *pWriteBuf)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if (pWriteBuf == NULL) {
ac_buffer_init(&pPN512->writeBuf, NULL, 0);
return;
}
ac_buffer_dup(&pPN512->writeBuf, pWriteBuf);
}
ac_buffer_t *pn512_get_read(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
return ac_buffer_builder_buffer(&pPN512->readBufBldr);
}
void pn512_set_last_byte_length(nfc_transceiver_t *pTransceiver, size_t lastByteLength)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if ((lastByteLength > 8) || (lastByteLength == 0)) {
lastByteLength = 8;
}
pPN512->writeLastByteLength = lastByteLength;
}
void pn512_set_first_byte_align(nfc_transceiver_t *pTransceiver, size_t firstByteAlign)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
firstByteAlign &= 0x7;
pPN512->readFirstByteAlign = firstByteAlign;
}
size_t pn512_get_last_byte_length(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
return pPN512->readLastByteLength;
}
void pn512_transceive(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pn512_transceive_hw(pPN512, pPN512->nextFrameMode, pn512_transceiver_callback);
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
}
void pn512_abort(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
nfc_scheduler_dequeue_task(&pTransceiver->scheduler, true, &pPN512->transceiver.task);
}
void pn512_close(nfc_transceiver_t *pTransceiver)
{
//pn512_t* pPN512 = (pn512_t*) pTransceiver;
(void) pTransceiver;
//TODO
return;
}
void pn512_sleep(nfc_transceiver_t *pTransceiver, bool sleep)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if (sleep) {
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x30); //Receiver off + soft power down
} else {
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x00);
while (pn512_register_read(pPN512, PN512_REG_COMMAND) & 0x10);
}
}
void pn512_transceiver_callback(pn512_t *pPN512, nfc_err_t ret)
{
transceiver_callback(&pPN512->transceiver, ret);
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_H_
#define PN512_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "transceiver/transceiver.h"
#include "pn512_types.h"
#include "pn512_callback.h"
typedef enum __pn512_state {
pn512_state_ready,
pn512_state_target_autocoll,
pn512_state_initiator_transceive_first_frame,
pn512_state_transceive,
pn512_state_transceive_last_frame,
} pn512_state_t;
typedef enum __pn512_transceive_mode {
pn512_transceive_mode_idle,
pn512_transceive_mode_target_autocoll,
pn512_transceive_mode_transmit,
pn512_transceive_mode_transmit_and_target_autocoll,
pn512_transceive_mode_transceive,
pn512_transceive_mode_receive,
} pn512_transceive_mode_t;
struct __pn512 {
nfc_transceiver_t transceiver;
//Impl specific
pn512_registers_t registers;
bool rf_on;
struct {
bool out;
bool in;
} crc;
int timeout;
struct {
nfc_tech_t initiators;
nfc_tech_t targets;
polling_options_t options;
} config;
//Transceive options
pn512_transceive_mode_t nextFrameMode;
nfc_framing_t framing;
uint16_t irqsEn;
uint8_t payload[256]; //Incoming buffer
ac_buffer_builder_t readBufBldr;
ac_buffer_t writeBuf;
uint8_t readFirstByteAlign;
uint8_t readLastByteLength;
uint8_t writeLastByteLength;
//Task parameters
struct {
//Polling
struct {
enum {
pn512_polling_state_start_listening,
pn512_polling_state_listen_wait_for_remote_field,
pn512_polling_state_listen_anticollision,
pn512_polling_state_listen_no_target_found,
pn512_polling_state_start_polling,
pn512_polling_state_rf_collision_avoidance, // TID + n × TRFW, n is random, TID>4096/(13.56E6) ~ 302.06us, TRFW=51/(13.56E6) ~ 37.76us
pn512_polling_state_polling_nfc_a_start,
pn512_polling_state_polling_nfc_a_gt, // guard time nfc a >= 5.0 ms
pn512_polling_state_polling_nfc_a_anticollision, // polling for nfc a
pn512_polling_state_polling_nfc_b_start,
pn512_polling_state_polling_nfc_b_gt, // guard time nfc b >= 5.0 ms
pn512_polling_state_polling_nfc_b_anticollision, // polling for nfc b
pn512_polling_state_polling_nfc_f_start,
pn512_polling_state_polling_nfc_f_gt, // guard time nfc f >= 20 ms
pn512_polling_state_polling_nfc_f_anticollision, // polling for nfc f
pn512_polling_state_finish_polling,
} state;
pn512_cb_t cb;
} poll;
struct {
pn512_cb_t cb;
pn512_transceive_mode_t mode;
} transceive;
struct {
pn512_cb_t cb;
} rf;
struct {
union {
// ISO A
struct {
bool more_targets; // Collision detected
uint8_t cascade_level;
uint8_t cln[5];
uint8_t valid_bits; // valid bits within cascade level
} iso_a;
// ISO B
struct {
bool more_targets; // Collision detected
uint8_t slots_num_exponent;
uint8_t slot_number;
bool found_one;
} iso_b;
};
pn512_cb_t cb;
} anticollision;
};
};
nfc_err_t pn512_init(pn512_t *pPN512, nfc_transport_t *pTransport, nfc_scheduler_timer_t *pTimer);
nfc_transceiver_t *pn512_get_transceiver(pn512_t *pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_H_ */

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_callback.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef PN512_CALLBACK_H_
#define PN512_CALLBACK_H_
#include "stack/nfc_common.h"
#include "pn512_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*pn512_cb_t)(pn512_t *pPN512, nfc_err_t ret);
#ifdef __cplusplus
}
#endif
#endif /* PN512_CALLBACK_H_ */

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_cmd.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Format and execute PN512 commands
* \internal
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_cmd.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_cmd.h"
#define PN512_FIFO_SIZE 64
#include "pn512.h"
#include "pn512_registers.h"
#include "pn512_irq.h"
#include "pn512_hw.h"
/** \addtogroup PN512
* \internal
* @{
* \name Commands
* @{
*/
/** \internal Initialize underlying pn512_cmd_t structure
* \param pPN512 pointer to pn512_t structure
*/
void pn512_cmd_init(pn512_t *pPN512)
{
(void) pPN512;
}
//Fifo read / write
/** \internal Write bytes to FIFO
* \param pPN512 pointer to pn512_t structure
* \param pData buffer to write
*/
void pn512_fifo_write(pn512_t *pPN512, ac_buffer_t *pData)
{
uint8_t fifo_space = pn512_fifo_space(pPN512); //Do not call this fn twice
size_t len = ac_buffer_reader_readable(pData);
len = MIN(fifo_space, len);
pn512_register_switch_page(pPN512, PN512_REG_FIFODATA);
pn512_hw_write_buffer(pPN512, PN512_REG_FIFODATA, pData, len);
}
/** \internal Read bytes from FIFO
* \param pPN512 pointer to pn512_t structure
* \param pData buffer in which to read
*/
void pn512_fifo_read(pn512_t *pPN512, ac_buffer_builder_t *pData)
{
uint8_t fifo_len = pn512_fifo_length(pPN512); //Do not call this fn twice
size_t len = ac_buffer_builder_writable(pData);
len = MIN(fifo_len, len);
pn512_register_switch_page(pPN512, PN512_REG_FIFODATA);
pn512_hw_read_buffer(pPN512, PN512_REG_FIFODATA, pData, len);
}
/** \internal Clear FIFO
* Removes any bytes left in FIFO
* \param pPN512 pointer to pn512_t structure
*/
void pn512_fifo_clear(pn512_t *pPN512)
{
pn512_register_write(pPN512, PN512_REG_FIFOLEVEL, 0x80); //Flush FIFO
}
/** \internal Get space in FIFO
* \param pPN512 pointer to pn512_t structure
* \return number of bytes that can be written to FIFO
*/
size_t pn512_fifo_space(pn512_t *pPN512)
{
return PN512_FIFO_SIZE - pn512_register_read(pPN512, PN512_REG_FIFOLEVEL);
}
/** \internal Get FIFO length
* \param pPN512 pointer to pn512_t structure
* \return number of bytes that can be read from FIFO
*/
size_t pn512_fifo_length(pn512_t *pPN512)
{
return pn512_register_read(pPN512, PN512_REG_FIFOLEVEL);
}
/** \internal Execute command
* \param pPN512 pointer to pn512_t structure
* \param cmd PN512 command to execute
*/
void pn512_cmd_exec(pn512_t *pPN512, uint8_t cmd)
{
pn512_register_write(pPN512, PN512_REG_COMMAND, cmd);
}
/** \internal Wait for command completion
* \param pPN512 pointer to pn512_t structure
* \param timeout timeout in milliseconds or -1 for blocking mode
* \return NFC_OK on success or NFC_ERR_TIMEOUT on timeout
*/
nfc_err_t pn512_cmd_wait_idle(pn512_t *pPN512, int timeout)
{
(void) timeout;
while (pn512_cmd_get(pPN512) != PN512_CMD_IDLE) {
}
return NFC_OK;
}
/** \internal Read executed command
* \param pPN512 pointer to pn512_t structure
* \return PN512 command being executed
*/
uint8_t pn512_cmd_get(pn512_t *pPN512)
{
return pn512_register_read(pPN512, PN512_REG_COMMAND) & PN512_CMD_REG_MASK;
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_cmd.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_CMD_H_
#define PN512_CMD_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
#define PN512_CMD_IDLE 0x00 //No action, cancels current command execution
#define PN512_CMD_MEM 0x01 //Stores 25 bytes into the internal buffer
#define PN512_CMD_CONFIG 0x01 //Configures the PN512 for FeliCa, MIFARE and NFCIP-1 communication
#define PN512_CMD_RNDIDG 0x02 //Generates a 10-byte random ID number
#define PN512_CMD_CRC 0x03 //Activates the CRC coprocessor or performs a self test
#define PN512_CMD_TRANSMIT 0x04 //Transmits data from the FIFO buffer
#define PN512_CMD_NOCHANGE 0x07 //No command change
#define PN512_CMD_RECEIVE 0x08 //Activates the receiver circuits
#define PN512_CMD_TRANSCEIVE 0x0C //Transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
#define PN512_CMD_AUTOCOLL 0x0D //Handles FeliCa polling (Card Operation mode only) and MIFARE anticollision (Card Operation mode only)
#define PN512_CMD_MFAUTH 0x0E //Performs the MIFARE standard authentication as a reader
#define PN512_CMD_SOFTRST 0x0F //Resets the PN512
#define PN512_CMD_REG_MASK 0x0F
void pn512_cmd_init(pn512_t *pPN512);
//Fifo read / write
void pn512_fifo_write(pn512_t *pPN512, ac_buffer_t *pData);
void pn512_fifo_read(pn512_t *pPN512, ac_buffer_builder_t *pData);
//Fifo clear
void pn512_fifo_clear(pn512_t *pPN512);
//Fifo bytes read
size_t pn512_fifo_space(pn512_t *pPN512);
size_t pn512_fifo_length(pn512_t *pPN512);
//Execute command
void pn512_cmd_exec(pn512_t *pPN512, uint8_t cmd);
//Wait for command completion
nfc_err_t pn512_cmd_wait_idle(pn512_t *pPN512, int timeout);
//Read executed command
uint8_t pn512_cmd_get(pn512_t *pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_CMD_H_ */

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_hw.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Format and execute PN512 frames
*/
#include "stack/nfc_errors.h"
#include "pn512_hw.h"
//Platform specific
#include "platform/nfc_transport.h"
/** \addtogroup PN512
* \internal
* @{
* \name Hardware
* @{
*/
/** \internal Initialize underlying pn512_hw_t structure
* \param pPN512 pointer to pn512_t structure
*/
void pn512_hw_init(pn512_t *pPN512)
{
//Nothing to init in this implementation
(void) pPN512;
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_hw.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_HW_H_
#define PN512_HW_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
//Utility for transport: SPI address read/write
#define PN512_SPI_ADDR_R(x) ((1<<7) | ((x) << 1))
#define PN512_SPI_ADDR_W(x) ((0<<7) | ((x) << 1))
void pn512_hw_init(pn512_t *pPN512);
/** \internal Write bytes at the specified address on the underlying transport link
* \param pPN512 pointer to pn512_t structure
* \param addr address at which to write
* \param buf buffer to write
* \param len length of buffer
*/
static inline void pn512_hw_write(pn512_t *pPN512, uint8_t addr, uint8_t *buf, size_t len)
{
nfc_transport_write(((nfc_transceiver_t *)pPN512)->pTransport, addr, buf, len);
}
/** \internal Read bytes from the specified address on the underlying transport link
* \param pPN512 pointer to pn512_t structure
* \param addr address from which to read
* \param buf buffer to read
* \param len length of buffer
*/
static inline void pn512_hw_read(pn512_t *pPN512, uint8_t addr, uint8_t *buf, size_t len)
{
nfc_transport_read(((nfc_transceiver_t *)pPN512)->pTransport, addr, buf, len);
}
static inline void pn512_hw_write_buffer(pn512_t *pPN512, uint8_t addr, ac_buffer_t *pData, size_t len)
{
while (len > 0) {
if (ac_buffer_reader_readable(pData) == 0) {
return;
}
size_t cpyLen = MIN(len, ac_buffer_reader_current_buffer_length(pData));
nfc_transport_write(((nfc_transceiver_t *)pPN512)->pTransport, addr, ac_buffer_reader_current_buffer_pointer(pData), cpyLen);
ac_buffer_read_n_skip(pData, cpyLen);
len -= cpyLen;
}
}
static inline void pn512_hw_read_buffer(pn512_t *pPN512, uint8_t addr, ac_buffer_builder_t *pData, size_t len)
{
while (len > 0) {
if (ac_buffer_builder_writable(pData) == 0) {
return;
}
//Read payload
size_t cpyLen = MIN(len, ac_buffer_builder_space(pData));
nfc_transport_read(((nfc_transceiver_t *)pPN512)->pTransport, addr, ac_buffer_builder_write_position(pData), cpyLen);
ac_buffer_builder_write_n_skip(pData, cpyLen);
len -= cpyLen;
}
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_HW_H_ */

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_internal.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_INTERNAL_H_
#define PN512_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "transceiver/transceiver_internal.h"
#include "pn512.h"
#include "pn512_callback.h"
//Public
void pn512_set_protocols(nfc_transceiver_t *pTransceiver, nfc_tech_t initiators, nfc_tech_t targets, polling_options_t options);
void pn512_poll(nfc_transceiver_t *pTransceiver);
void pn512_set_crc(nfc_transceiver_t *pTransceiver, bool crc_out, bool crc_in);
void pn512_set_timeout(nfc_transceiver_t *pTransceiver, int timeout);
void pn512_set_transceive_options(nfc_transceiver_t *pTransceiver, bool transmit, bool receive, bool repoll);
void pn512_set_transceive_framing(nfc_transceiver_t *pTransceiver, nfc_framing_t framing);
void pn512_set_write(nfc_transceiver_t *pTransceiver, ac_buffer_t *pWriteBuf);
ac_buffer_t *pn512_get_read(nfc_transceiver_t *pTransceiver);
size_t pn512_get_last_byte_length(nfc_transceiver_t *pTransceiver);
void pn512_set_last_byte_length(nfc_transceiver_t *pTransceiver, size_t lastByteLength);
void pn512_set_first_byte_align(nfc_transceiver_t *pTransceiver, size_t firstByteAlign);
void pn512_abort(nfc_transceiver_t *pTransceiver);
void pn512_transceive(nfc_transceiver_t *pTransceiver);
void pn512_close(nfc_transceiver_t *pTransceiver);
void pn512_sleep(nfc_transceiver_t *pTransceiver, bool sleep);
void pn512_transceiver_callback(pn512_t *pPN512, nfc_err_t ret);
static inline void pn512_rf_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->rf.cb(pPN512, ret);
}
static inline void pn512_poll_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->poll.cb(pPN512, ret);
}
static inline void pn512_anticollision_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->anticollision.cb(pPN512, ret);
}
static inline void pn512_transceive_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->transceive.cb(pPN512, ret);
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_INTERNAL_H_ */

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_irq.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Manage PN512 interrupt requests
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_irq.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_irq.h"
#include "pn512_registers.h"
#include "pn512_hw.h"
#include "pn512.h"
/** \addtogroup PN512
* \internal
* @{
* \name Interrupts
* @{
*/
/**
* @}
* @}
* */

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_irq.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_IRQ_H_
#define PN512_IRQ_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
#include "pn512_registers.h"
#define PN512_IRQ_TX (1<<6)
#define PN512_IRQ_RX (1<<5)
#define PN512_IRQ_IDLE (1<<4)
#define PN512_IRQ_HIGH_ALERT (1<<3)
#define PN512_IRQ_LOW_ALERT (1<<2)
#define PN512_IRQ_ERR (1<<1)
#define PN512_IRQ_TIMER (1<<0)
#define PN512_IRQ_SIGIN (1<<(4+8))
#define PN512_IRQ_MODE (1<<(3+8))
#define PN512_IRQ_CRC (1<<(2+8))
#define PN512_IRQ_RF_ON (1<<(1+8))
#define PN512_IRQ_RF_OFF (1<<(0+8))
#define PN512_IRQ_NONE 0x00
#define PN512_IRQ_ALL 0x1F7F
#define PN512_REG_COMIEN_MASK 0x7F
#define PN512_REG_COMIEN_VAL 0x00
#define PN512_REG_DIVIEN_MASK 0x1F
#define PN512_REG_DIVIEN_VAL 0x80
#define PN512_REG_COMIRQ_MASK 0x7F
#define PN512_REG_COMIRQ_CLEAR 0x00
#define PN512_REG_DIVIRQ_MASK 0x1F
#define PN512_REG_DIVIRQ_CLEAR 0x00
/** \internal Set IRQ enable registers
* \param pPN512 pointer to pn512_t structure
* \param irqs MSB is DIVIEN value, LSB is COMIEN value
*/
static inline void pn512_irq_set(pn512_t *pPN512, uint16_t irqs) //ORed
{
pn512_register_write(pPN512, PN512_REG_COMIEN, PN512_REG_COMIEN_VAL | (PN512_REG_COMIEN_MASK & (irqs & 0xFF)));
pn512_register_write(pPN512, PN512_REG_DIVIEN, PN512_REG_DIVIEN_VAL | (PN512_REG_DIVIEN_MASK & (irqs >> 8)));
pPN512->irqsEn = irqs;
}
/** \internal Get IRQ enable registers
* \param pPN512 pointer to pn512_t structure
* \return MSB is DIVIEN value, LSB is COMIEN value
*/
static inline uint16_t pn512_irq_enabled(pn512_t *pPN512) //ORed
{
return pPN512->irqsEn /*(pn512_register_read(pPN512, PN512_REG_COMIEN_VAL) & PN512_REG_COMIEN_MASK)
| ((pn512_register_read(pPN512, PN512_REG_DIVIEN_VAL) & PN512_REG_DIVIEN_MASK) << 8)*/;
}
/** \internal Get IRQ status registers (masked with enabled IRQ register)
* \param pPN512 pointer to pn512_t structure
* \return MSB is DIVIRQ value, LSB is COMIRQ value
*/
static inline uint16_t pn512_irq_get(pn512_t *pPN512) //ORed
{
return ((pn512_register_read(pPN512, PN512_REG_COMIRQ) & PN512_REG_COMIEN_MASK)
| ((pn512_register_read(pPN512, PN512_REG_DIVIRQ) & PN512_REG_DIVIEN_MASK) << 8)) & pPN512->irqsEn;
}
/** \internal Clear some interrupts
* \param pPN512 pointer to pn512_t structure
* \param irqs MSB is DIVIEN value, LSB is COMIEN value
*/
static inline void pn512_irq_clear(pn512_t *pPN512, uint16_t irqs)
{
pn512_register_write(pPN512, PN512_REG_COMIRQ, PN512_REG_COMIRQ_CLEAR | (PN512_REG_COMIRQ_MASK & (irqs & 0xFF)));
pn512_register_write(pPN512, PN512_REG_DIVIRQ, PN512_REG_DIVIRQ_CLEAR | (PN512_REG_DIVIRQ_MASK & (irqs >> 8)));
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_IRQ_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_poll.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_POLL_H_
#define PN512_POLL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
void pn512_poll_setup(pn512_t *pPN512);
void pn512_poll_hw(pn512_t *pPN512, pn512_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif /* PN512_POLL_H_ */

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_registers.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Access to PN512 registers
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_registers.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_registers.h"
#include "pn512_hw.h"
#include "pn512.h"
#define REGISTER_PAGE(x) ((x)>>4)
#define REGISTER_ADDR(x) ((x)&0xF)
/** \addtogroup PN512
* \internal
* @{
* \name Registers
* @{
*/
static void pn512_register_switch_page_intl(pn512_t *pPN512, uint8_t page);
/** \internal Initialize underlying pn512_registers_t structure
* \param pPN512 pointer to pn512_t structure
*/
void pn512_registers_init(pn512_t *pPN512)
{
pPN512->registers.registers_page = 0;
}
#define PN512_CFG_INIT_LEN 9
static const uint8_t PN512_CFG_INIT_REGS[] = {
PN512_REG_DIVIEN,
PN512_REG_MODE,
PN512_REG_GSNOFF,
PN512_REG_RFCFG,
PN512_REG_CWGSP,
PN512_REG_MIFNFC,
PN512_REG_FELNFC2,
PN512_REG_RXSEL,
PN512_REG_TYPEB
};
static const uint8_t PN512_CFG_INIT_VALS[] = {
0x80,
0x3F,
0xF2,
0x68,
0x3F,
0x62,
0x80,
0x84,
0x00
}; //Timer: For now max prescaler, max reload value
/** \internal Switch to known (0) registers page, reset registers state
* \param pPN512 pointer to pn512_t structure
*/
void pn512_registers_reset(pn512_t *pPN512)
{
pn512_register_switch_page_intl(pPN512, 0);
for (int i = 0; i < PN512_CFG_INIT_LEN; i++) {
pn512_register_write(pPN512, PN512_CFG_INIT_REGS[i], PN512_CFG_INIT_VALS[i]);
}
}
/** \internal Write register
* \param pPN512 pointer to pn512_t structure
* \param address register address
* \param data value to write in register
*/
void pn512_register_write(pn512_t *pPN512, uint8_t address, uint8_t data)
{
NFC_DBG("Write [%02x] << %02x", address, data);
if (REGISTER_PAGE(address) != pPN512->registers.registers_page) {
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
address = REGISTER_ADDR(address);
pn512_hw_write(pPN512, address, &data, 1);
}
/** \internal Read register
* \param pPN512 pointer to pn512_t structure
* \param address register address
* \return data value read from register
*/
uint8_t pn512_register_read(pn512_t *pPN512, uint8_t address)
{
uint8_t data;
NFC_DBG_BLOCK(
uint8_t __dbg_addr;
__dbg_addr = address; //FIXME
)
if (REGISTER_PAGE(address) != pPN512->registers.registers_page) {
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
address = REGISTER_ADDR(address);
pn512_hw_read(pPN512, address, &data, 1);
NFC_DBG("Read [%02x] >> %02x", __dbg_addr, data);
return data;
}
void pn512_register_switch_page(pn512_t *pPN512, uint8_t address)
{
if (REGISTER_PAGE(address) != pPN512->registers.registers_page) {
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
}
/** \internal Switch registers page
* \param pPN512 pointer to pn512_t structure
* \param page registers page
*/
void pn512_register_switch_page_intl(pn512_t *pPN512, uint8_t page)
{
uint8_t pageRegValue;
pageRegValue = (1 << 7) | page;
pn512_hw_write(pPN512, PN512_REG_PAGE, &pageRegValue, 1);
pPN512->registers.registers_page = page;
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_registers.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_REGISTERS_H_
#define PN512_REGISTERS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
//Page 0 - Command and Status
#define PN512_REG_PAGE 0x00 //Selects the register page
#define PN512_REG_COMMAND 0x01 //Starts and stops command execution
#define PN512_REG_COMIEN 0x02 //Controls bits to enable and disable the passing of Interrupt Requests
#define PN512_REG_DIVIEN 0x03 //Controls bits to enable and disable the passing of Interrupt Requests
#define PN512_REG_COMIRQ 0x04 //Contains Interrupt Request bits
#define PN512_REG_DIVIRQ 0x05 //Contains Interrupt Request bits
#define PN512_REG_ERROR 0x06 //Error bits showing the error status of the last command executed
#define PN512_REG_STATUS1 0x07 //Contains status bits for communication
#define PN512_REG_STATUS2 0x08 //Contains status bits of the receiver and transmitter
#define PN512_REG_FIFODATA 0x09 //In- and output of 64 byte FIFO-buffer
#define PN512_REG_FIFOLEVEL 0x0A //Indicates the number of bytes stored in the FIFO
#define PN512_REG_WATERLEVEL 0x0B //Defines the level for FIFO under- and overflow warning
#define PN512_REG_CONTROL 0x0C //Contains miscellaneous Control Registers
#define PN512_REG_BITFRAMING 0x0D //Adjustments for bit oriented frames
#define PN512_REG_COLL 0x0E //Bit position of the first bit collision detected on the RF-interface
//Page 1 - Command
//#define PN512_REG_PAGE 0x10 //Selects the register page
#define PN512_REG_MODE 0x11 //Defines general modes for transmitting and receiving
#define PN512_REG_TXMODE 0x12 //Defines the data rate and framing during transmission
#define PN512_REG_RXMODE 0x13 //Defines the data rate and framing during receiving
#define PN512_REG_TXCONTROL 0x14 //Controls the logical behavior of the antenna driver pins TX1 and TX2
#define PN512_REG_TXAUTO 0x15 //Controls the setting of the antenna drivers
#define PN512_REG_TXSEL 0x16 //Selects the internal sources for the antenna driver
#define PN512_REG_RXSEL 0x17 //Selects internal receiver settings
#define PN512_REG_RXTHRESHOLD 0x18 //Selects thresholds for the bit decoder
#define PN512_REG_DEMOD 0x19 //Defines demodulator settings
#define PN512_REG_FELNFC1 0x1A //Defines the length of the valid range for the receive package
#define PN512_REG_FELNFC2 0x1B //Defines the length of the valid range for the receive package
#define PN512_REG_MIFNFC 0x1C //Controls the communication in ISO/IEC 14443/MIFARE and NFC target mode at 106 kbit
#define PN512_REG_MANUALRCV 0x1D //Allows manual fine tuning of the internal receiver
#define PN512_REG_TYPEB 0x1E //Configure the ISO/IEC 14443 type B
#define PN512_REG_SERIALSPEED 0x1F //Selects the speed of the serial UART interface
//Page 2 - CFG
//#define PN512_REG_PAGE 0x20 //Selects the register page
#define PN512_REG_CRCRESULT_MSB 0x21 //Shows the actual MSB and LSB values of the CRC calculation
#define PN512_REG_CRCRESULT_LSB 0x22 //Shows the actual MSB and LSB values of the CRC calculation
#define PN512_REG_GSNOFF 0x23 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation, when the driver is switched off
#define PN512_REG_MODWIDTH 0x24 //Controls the setting of the ModWidth
#define PN512_REG_TXBITPHASE 0x25 //Adjust the TX bit phase at 106 kbit
#define PN512_REG_RFCFG 0x26 //Configures the receiver gain and RF level
#define PN512_REG_GSNON 0x27 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation when the drivers are switched on
#define PN512_REG_CWGSP 0x28 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation during times of no modulation
#define PN512_REG_MODGSP 0x29 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation during modulation
#define PN512_REG_TMODE_TPRESCALERHIGH 0x2A //Defines settings for the internal timer
#define PN512_REG_TPRESCALERLOW 0x2B //Defines settings for the internal timer
#define PN512_REG_TRELOADHIGH 0x2C //Describes the 16-bit timer reload value
#define PN512_REG_TRELOADLOW 0x2D //Describes the 16-bit timer reload value
#define PN512_REG_TCOUNTERVALHIGH 0x2E //Shows the 16-bit actual timer value
#define PN512_REG_TCOUNTERVALLOW 0x2F //Shows the 16-bit actual timer value
//Page 3 - TestRegister
//#define PN512_REG_PAGE 0x30 //Selects the register page
#define PN512_REG_TESTSEL1 0x31 //General test signal configuration
#define PN512_REG_TESTSEL2 0x32 //General test signal configuration and PRBS control
#define PN512_REG_TESTPINEN 0x33 //Enables pin output driver on 8-bit parallel bus (Note: For serial interfaces only)
#define PN512_REG_TESTPINVALUE 0x34 //Defines the values for the 8-bit parallel bus when it is used as I/O bus
#define PN512_REG_TESTBUS 0x35 //Shows the status of the internal testbus
#define PN512_REG_AUTOTEST 0x36 //Controls the digital selftest
#define PN512_REG_VERSION 0x37 //Shows the version
#define PN512_REG_ANALOGTEST 0x38 //Controls the pins AUX1 and AUX2
#define PN512_REG_TESTDAC1 0x39 //Defines the test value for the TestDAC1
#define PN512_REG_TESTDAC2 0x3A //Defines the test value for the TestDAC2
#define PN512_REG_TESTADC 0x3B //Shows the actual value of ADC I and Q
void pn512_registers_init(pn512_t *pPN512);
void pn512_registers_reset(pn512_t *pPN512);
void pn512_register_write(pn512_t *pPN512, uint8_t address, uint8_t data);
uint8_t pn512_register_read(pn512_t *pPN512, uint8_t address);
void pn512_register_switch_page(pn512_t *pPN512, uint8_t address);
#ifdef __cplusplus
}
#endif
#endif /* PN512_REGISTERS_H_ */

View File

@ -0,0 +1,326 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_rf.c
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_rf.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_callback.h"
#include "pn512_rf.h"
#include "pn512_registers.h"
#include "pn512_timer.h"
#include "pn512_irq.h"
#include "pn512.h"
#include "pn512_internal.h"
#include "stdlib.h" //For rand() func
#define PN512_FRAMING_REGS 6
static const uint8_t framing_registers[] = { PN512_REG_MODE, PN512_REG_TXMODE, PN512_REG_RXMODE, PN512_REG_MODGSP, PN512_REG_RXTHRESHOLD, PN512_REG_MODWIDTH };
static const uint8_t framing_registers_mode_detector[] = { 0x3B, 0x80, 0x80, 0x3F, 0x55, 0x26 };
static const uint8_t framing_registers_initiator_iso14443a_106k[] = { 0x3D, 0x80, 0x80, 0x3F, 0x55, 0x26 };
static const uint8_t framing_registers_initiator_iso14443b_106k[] = { 0x3F, 0x83, 0x83, 0x04, 0x50, 0x26 };
static const uint8_t framing_registers_target_iso14443a_106k[] = { 0x3D, 0x80, 0x80, 0x3F, 0x55, 0x26 };
static const uint8_t framing_registers_felica_212k[] = { 0x3A, 0x92, 0x92, 0x12, 0x55, 0x15 };
static const uint8_t framing_registers_felica_414k[] = { 0x3A, 0xA2, 0xA2, 0x12, 0x55, 0x0A };
nfc_err_t pn512_framing_set(pn512_t *pPN512, nfc_framing_t framing)
{
if (framing == pPN512->framing) { //No need to do anything
return NFC_OK;
}
NFC_DBG("Switching to %u", framing);
const uint8_t *framing_registers_values;
switch (framing) {
case nfc_framing_target_mode_detector:
framing_registers_values = framing_registers_mode_detector;
break;
case nfc_framing_target_a_106:
framing_registers_values = framing_registers_target_iso14443a_106k;
break;
case nfc_framing_initiator_a_106:
framing_registers_values = framing_registers_initiator_iso14443a_106k;
break;
case nfc_framing_initiator_b_106:
framing_registers_values = framing_registers_initiator_iso14443b_106k;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
framing_registers_values = framing_registers_felica_212k;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
framing_registers_values = framing_registers_felica_414k;
break;
default:
return NFC_ERR_UNSUPPORTED;
}
for (int i = 0; i < PN512_FRAMING_REGS; i++) {
pn512_register_write(pPN512, framing_registers[i], framing_registers_values[i]);
}
pPN512->framing = framing;
pPN512->crc.out = true;
pPN512->crc.in = true;
//TODO initiator: PN512_REG_MODGSP
switch (pPN512->framing) {
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_b_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x10); //Act as initiator
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x00); //Act as target
break;
default:
return NFC_ERR_UNSUPPORTED;
}
#if 1
if ((pPN512->framing == nfc_framing_initiator_a_106) /*|| (pPN512->framing == pn512_framing_target_iso14443a_106k)*/) {
//Enable 100% ASK Modulation
pn512_register_write(pPN512, PN512_REG_TXAUTO, pn512_register_read(pPN512, PN512_REG_TXAUTO) | 0x40);
} else {
pn512_register_write(pPN512, PN512_REG_TXAUTO, pn512_register_read(pPN512, PN512_REG_TXAUTO) & (~0x40));
}
#endif
return NFC_OK;
}
nfc_err_t pn512_framing_crc_set(pn512_t *pPN512, bool out, bool in)
{
const uint8_t *framing_registers_values;
switch (pPN512->framing) {
case nfc_framing_target_mode_detector:
framing_registers_values = framing_registers_mode_detector;
break;
case nfc_framing_target_a_106:
framing_registers_values = framing_registers_target_iso14443a_106k;
break;
case nfc_framing_initiator_a_106:
framing_registers_values = framing_registers_initiator_iso14443a_106k;
break;
case nfc_framing_initiator_b_106:
framing_registers_values = framing_registers_initiator_iso14443b_106k;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
framing_registers_values = framing_registers_felica_212k;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
framing_registers_values = framing_registers_felica_414k;
break;
default:
return NFC_ERR_UNSUPPORTED;
}
if (pPN512->crc.out != out) {
pn512_register_write(pPN512, framing_registers[1], (framing_registers_values[1] & 0x7F) | (out ? 0x80 : 0x00)); //TXMODE
pPN512->crc.out = out;
}
if (pPN512->crc.in != in) {
pn512_register_write(pPN512, framing_registers[2], (framing_registers_values[2] & 0x7F) | (in ? 0x80 : 0x00)); //RXMODE
pPN512->crc.in = in;
}
return NFC_OK;
}
nfc_err_t pn512_framing_rx_multiple_enable(pn512_t *pPN512)
{
const uint8_t *framing_registers_values;
switch (pPN512->framing) {
case nfc_framing_target_mode_detector:
framing_registers_values = framing_registers_mode_detector;
break;
case nfc_framing_target_a_106:
framing_registers_values = framing_registers_target_iso14443a_106k;
break;
case nfc_framing_initiator_a_106:
framing_registers_values = framing_registers_initiator_iso14443a_106k;
break;
case nfc_framing_initiator_b_106:
framing_registers_values = framing_registers_initiator_iso14443b_106k;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
framing_registers_values = framing_registers_felica_212k;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
framing_registers_values = framing_registers_felica_414k;
break;
default:
return NFC_ERR_UNSUPPORTED;
}
pn512_register_write(pPN512, framing_registers[2], (framing_registers_values[2] & 0x7F) | (pPN512->crc.in ? 0x80 : 0x00) | 0x04); //RXMODE
return NFC_OK;
}
void pn512_rf_field_switch_off(pn512_t *pPN512)
{
pn512_register_write(pPN512, PN512_REG_TXAUTO, 0x00);
pn512_register_write(pPN512, PN512_REG_TXCONTROL, 0x80);
pPN512->rf_on = false;
}
void pn512_rf_field_nfcip1_rf_collision_avoidance_complete(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
uint16_t irq_res = pn512_irq_get(pPN512);
(void) events;
pn512_timer_stop(pPN512);
pn512_timer_config(pPN512, false, 0, 0xffff); //Deactivate autostart
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON | PN512_IRQ_TIMER);
if (irq_res & PN512_IRQ_RF_ON) {
NFC_DBG("External field on");
//Clear TXAUTO register
pn512_register_write(pPN512, PN512_REG_TXAUTO, 0x00);
pPN512->rf_on = false; //External field on
pn512_rf_callback(pPN512, NFC_OK);
return;
}
//Has our RF field been switched on?
if (pn512_register_read(pPN512, PN512_REG_TXAUTO) & 0x40) { //InitialRFOn bit is cleared automatically, if the RF field is switched on
NFC_ERR("InitialRFOn bit still set");
pn512_rf_callback(pPN512, NFC_ERR_UNKNOWN);
return;
}
pPN512->rf_on = true; //Own field on and guard time ok
NFC_DBG("RF field enabled");
pn512_rf_callback(pPN512, NFC_OK);
}
void pn512_rf_field_nfcip1_rf_collision_avoidance(pn512_t *pPN512, pn512_cb_t cb)
{
pPN512->rf.cb = cb;
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON | PN512_IRQ_TIMER);
//If our field is switched on, Wait TIRFG according to NFC-IP1 = 5ms => 67800 clock edges = (3+1)*8475
pn512_timer_config(pPN512, true, 3, 8475);
pn512_irq_set(pPN512, PN512_IRQ_RF_ON /* External field switched on */
| PN512_IRQ_TIMER /* Timer reached 0 */);
//Try to enable RF field in compliance with NFC-IP1
pn512_register_write(pPN512, PN512_REG_TXAUTO, 0x0F);
//Is external RF Field already on?
if (pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x4) {
NFC_DBG("External field already on");
pPN512->rf_on = false; //External field on
//Cancel
pn512_timer_stop(pPN512);
pn512_timer_config(pPN512, false, 0, 0xffff); //Deactivate autostart
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON | PN512_IRQ_TIMER);
pn512_rf_callback(pPN512, NFC_OK);
return;
}
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, -1, pn512_rf_field_nfcip1_rf_collision_avoidance_complete, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}
void pn512_rf_field_wait_for_external_complete_task(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
NFC_DBG("%lu events", events);
//Wake up PN512
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x00);
while (pn512_register_read(pPN512, PN512_REG_COMMAND) & 0x10);
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON);
if (events & EVENT_ABORTED) {
pn512_rf_callback(pPN512, NFC_ERR_ABORTED);
return;
}
if (events & EVENT_TIMEOUT) {
NFC_DBG("Timeout");
pn512_rf_callback(pPN512, NFC_ERR_TIMEOUT);
return;
}
NFC_DBG("On");
pn512_rf_callback(pPN512, NFC_OK);
}
void pn512_rf_field_wait_for_external(pn512_t *pPN512, int timeout, pn512_cb_t cb)
{
pPN512->rf.cb = cb;
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON);
NFC_DBG("Wait for RF field to come up (timeout %d)", timeout);
//Is external RF Field already on?
pn512_irq_set(pPN512, PN512_IRQ_RF_ON /* External field switched on */);
if (pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x4) {
NFC_DBG("RF field already on");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON);
pn512_rf_callback(pPN512, NFC_OK);
return;
}
//Send PN512 to sleep mode
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x30); //Receiver off + soft power down
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, timeout, pn512_rf_field_wait_for_external_complete_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_rf.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_RF_H_
#define PN512_RF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512_types.h"
#include "pn512_callback.h"
#include "pn512.h"
nfc_err_t pn512_framing_set(pn512_t *pPN512, nfc_framing_t framing);
nfc_err_t pn512_framing_crc_set(pn512_t *pPN512, bool out, bool in);
nfc_err_t pn512_framing_rx_multiple_enable(pn512_t *pPN512);
#define PN512_FRAMING_IS_TARGET( framing ) ((framing) <= nfc_framing_target_f_424)
void pn512_rf_field_switch_off(pn512_t *pPN512);
void pn512_rf_field_nfcip1_rf_collision_avoidance(pn512_t *pPN512, pn512_cb_t cb);
void pn512_rf_field_wait_for_external(pn512_t *pPN512, int timeout, pn512_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif /* PN512_RF_H_ */

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_timer.c
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#include "stack/nfc_errors.h"
#include "pn512_timer.h"
#include "pn512_registers.h"
void pn512_timer_config(pn512_t *pPN512, bool autostart, uint16_t prescaler, uint16_t countdown_value)
{
pn512_timer_stop(pPN512); //just in case...
pn512_register_write(pPN512, PN512_REG_TRELOADLOW, countdown_value & 0xFF);
pn512_register_write(pPN512, PN512_REG_TRELOADHIGH, (countdown_value >> 8) & 0xFF);
pn512_register_write(pPN512, PN512_REG_TPRESCALERLOW, prescaler & 0xFF);
pn512_register_write(pPN512, PN512_REG_TMODE_TPRESCALERHIGH, (autostart ? 0x80 : 0x00) | ((prescaler >> 8) & 0x0F));
}
void pn512_timer_start(pn512_t *pPN512)
{
//The control register also contains the initiator bit that we must set correctly
switch (pPN512->framing) {
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x50);
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
default:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x40);
break;
}
}
void pn512_timer_stop(pn512_t *pPN512)
{
//The control register also contains the initiator bit that we must set correctly
switch (pPN512->framing) {
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x90);
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
default:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x80);
break;
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_timer.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_TIMER_H_
#define PN512_TIMER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512_types.h"
void pn512_timer_config(pn512_t *pPN512, bool autostart, uint16_t prescaler, uint16_t countdown_value);
void pn512_timer_start(pn512_t *pPN512);
void pn512_timer_stop(pn512_t *pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_TIMER_H_ */

View File

@ -0,0 +1,441 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_transceive.c
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_transceive.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512.h"
#include "pn512_transceive.h"
#include "pn512_rf.h"
#include "pn512_irq.h"
#include "pn512_cmd.h"
#include "pn512_registers.h"
#include "pn512_internal.h"
#define TIMEOUT 1000
void pn512_transceive_hw_tx_iteration(pn512_t *pPN512, bool start)
{
uint16_t irqs_en = pn512_irq_enabled(pPN512);
if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) {
//Fill FIFO
pn512_fifo_write(pPN512, &pPN512->writeBuf);
if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) { //Did not fit in FIFO
pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT);
//Has low FIFO alert IRQ already been enabled?
if (!(irqs_en & PN512_IRQ_LOW_ALERT)) {
irqs_en |= PN512_IRQ_LOW_ALERT;
pn512_irq_set(pPN512, irqs_en);
}
} else {
if (irqs_en & PN512_IRQ_LOW_ALERT) {
//Buffer has been fully sent
irqs_en &= ~PN512_IRQ_LOW_ALERT;
pn512_irq_set(pPN512, irqs_en);
}
}
}
if (start) {
if ((pPN512->transceive.mode == pn512_transceive_mode_transmit) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) {
//Update bitframing register
pn512_register_write(pPN512, PN512_REG_BITFRAMING,
0x00 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
//Use transmit command
pn512_cmd_exec(pPN512, PN512_CMD_TRANSMIT);
} else {
NFC_DBG("Bitframing %02X", 0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
//Update bitframing register to start transmission
pn512_register_write(pPN512, PN512_REG_BITFRAMING,
0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
}
//Reset last byte length, first byte align
pPN512->writeLastByteLength = 8;
pPN512->readFirstByteAlign = 0;
}
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, TIMEOUT, pn512_transceive_hw_tx_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}
void pn512_transceive_hw_tx_task(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
if (events & EVENT_ABORTED) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_ERR("Aborted TX");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_ABORTED);
return;
}
NFC_DBG("TX task");
if (events & EVENT_TIMEOUT) {
// Check status
NFC_DBG("Status = %02X %02X", pn512_register_read(pPN512, PN512_REG_STATUS1), pn512_register_read(pPN512, PN512_REG_STATUS2));
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_ERR("Timeout on TX");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT);
return;
}
uint16_t irqs_en = pn512_irq_enabled(pPN512);
uint16_t irqs = pn512_irq_get(pPN512);
if (irqs & PN512_IRQ_RF_OFF) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
NFC_WARN("RF Off");
pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
return;
}
if (irqs & PN512_IRQ_TX) {
if (irqs_en & PN512_IRQ_LOW_ALERT) {
//If the transmission has been completed without us getting a chance to fill the buffer up it means that we had a buffer underflow
NFC_ERR("Buffer underflow");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_UNDERFLOW);
return;
}
//Transmission complete
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_TX | PN512_IRQ_LOW_ALERT);
//Start receiving
NFC_DBG("Transmission complete");
if (pPN512->transceive.mode != pn512_transceive_mode_transmit) {
if (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll) {
//Make sure bitframing reg is clean
pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00);
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pn512_transceive_hw_rx_start(pPN512);
//Start autocoll
pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL);
} else {
pn512_transceive_hw_rx_start(pPN512);
}
return;
} else {
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT);
pn512_transceive_callback(pPN512, NFC_OK);
return;
}
}
if ((irqs & PN512_IRQ_LOW_ALERT) && (ac_buffer_reader_readable(&pPN512->writeBuf) > 0)) {
//Continue to fill FIFO
pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT);
pn512_transceive_hw_tx_iteration(pPN512, false);
return;
}
if (irqs & PN512_IRQ_IDLE) {
pn512_irq_clear(pPN512, PN512_IRQ_ERR);
NFC_ERR("Modem went to idle");
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM);
return;
}
//Call back function
pn512_transceive_hw_tx_iteration(pPN512, false);
}
void pn512_transceive_hw_rx_start(pn512_t *pPN512)
{
uint16_t irqs_en = PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_ERR;
if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
irqs_en |= PN512_IRQ_RF_OFF;
}
pn512_irq_set(pPN512, irqs_en);
//Reset buffer except if data should be appended to this -- TODO
ac_buffer_builder_reset(&pPN512->readBufBldr);
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT,
pPN512->timeout, pn512_transceive_hw_rx_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler,
&pPN512->transceiver.task);
}
void pn512_transceive_hw_rx_task(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
NFC_DBG("RX task");
if (events & EVENT_ABORTED) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_ERR("Aborted RX");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_ABORTED);
return;
}
if (events & EVENT_TIMEOUT) {
NFC_WARN("Timeout");
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT);
return;
}
uint16_t irqs = pn512_irq_get(pPN512);
NFC_DBG("irqs %04x", irqs);
bool collision_detected = false;
if (irqs & PN512_IRQ_ERR) {
pn512_irq_clear(pPN512, PN512_IRQ_ERR);
uint8_t err_reg = pn512_register_read(pPN512, PN512_REG_ERROR);
NFC_ERR("Got error - error reg is %02X", err_reg);
// if err_reg == 0, sticky error that must have been cleared automatically, continue
if (err_reg != 0) {
//If it's a collsision, flag it but still carry on with RX procedure
collision_detected = true;
if ((err_reg == 0x08) || (err_reg == 0x0A)) { // Collision (and maybe parity) (and no other error)
irqs &= ~PN512_IRQ_ERR;
irqs |= PN512_IRQ_RX;
} else {
NFC_DBG_BLOCK(
//Empty FIFO into buffer
pn512_fifo_read(pPN512, &pPN512->readBufBldr);
NFC_DBG("Received");
ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));
NFC_DBG("Computed CRC = %02X %02X", pn512_register_read(pPN512, PN512_REG_CRCRESULT_MSB), pn512_register_read(pPN512, PN512_REG_CRCRESULT_LSB));
)
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM);
return;
}
}
}
if ((irqs & PN512_IRQ_RX) || (irqs & PN512_IRQ_HIGH_ALERT)) {
//Empty FIFO into buffer
pn512_fifo_read(pPN512, &pPN512->readBufBldr);
if ((ac_buffer_builder_writable(&pPN512->readBufBldr) == 0) && (pn512_fifo_length(pPN512) > 0)) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_WARN("RX buffer overflow");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_BUFFER_TOO_SMALL);
return; //overflow
}
if (irqs & PN512_IRQ_HIGH_ALERT) {
NFC_DBG("High alert");
pn512_irq_clear(pPN512, PN512_IRQ_HIGH_ALERT);
}
if (irqs & PN512_IRQ_RX) {
pn512_irq_clear(pPN512, PN512_IRQ_RX);
size_t last_byte_length = pn512_register_read(pPN512, PN512_REG_CONTROL) & 0x7;
if (last_byte_length == 0) {
last_byte_length = 8;
}
pPN512->readLastByteLength = last_byte_length;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT);
NFC_DBG("Received:");
NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));)
if ((pPN512->transceive.mode == pn512_transceive_mode_target_autocoll) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) {
//Check if target was activated
if (!(pn512_register_read(pPN512, PN512_REG_STATUS2) & 0x10)) {
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_PROTOCOL);
return;
}
//PN512 switches to transceive automatically
pPN512->transceive.mode = pn512_transceive_mode_transceive;
} else if (pPN512->transceive.mode == pn512_transceive_mode_receive) {
pPN512->transceive.mode = pn512_transceive_mode_transceive;
//pn512_cmd_exec(pPN512, PN512_CMD_IDLE); //Useful?
}
if (!collision_detected) {
pn512_transceive_callback(pPN512, NFC_OK);
} else {
pn512_transceive_callback(pPN512, NFC_ERR_COLLISION);
}
return;
}
}
if (irqs & PN512_IRQ_RF_OFF) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
return;
}
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT,
pPN512->timeout, pn512_transceive_hw_rx_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler,
&pPN512->transceiver.task);
}
void pn512_transceive_hw(pn512_t *pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb)
{
uint16_t irqs_en;
//Store callback
pPN512->transceive.cb = cb;
//Clear FIFO
pn512_fifo_clear(pPN512);
//Clear previous IRQs if present
pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_TX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_LOW_ALERT | PN512_IRQ_ERR | PN512_IRQ_IDLE | PN512_IRQ_RF_OFF);
if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
//RF off?
if (!(pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x04)) {
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
return;
}
} else if ((pPN512->transceive.mode != mode) && (mode == pn512_transceive_mode_transceive)) {
pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE);
}
pPN512->transceive.mode = mode;
if (mode == pn512_transceive_mode_receive) {
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pn512_transceive_hw_rx_start(pPN512);
pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE);
} else if (mode == pn512_transceive_mode_target_autocoll) {
//Make sure bitframing reg is clean
pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00);
pn512_transceive_hw_rx_start(pPN512);
//Start autocoll
pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL);
return;
} else {
NFC_DBG("Sending:");
NFC_DBG_BLOCK(ac_buffer_dump(&pPN512->writeBuf);)
//Transmit a frame to remote target/initiator
irqs_en = PN512_IRQ_TX | PN512_IRQ_IDLE;
if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
irqs_en |= PN512_IRQ_RF_OFF;
}
pn512_irq_set(pPN512, irqs_en);
pn512_transceive_hw_tx_iteration(pPN512, true);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_transceive.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_TRANSCEIVE_H_
#define PN512_TRANSCEIVE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
void pn512_transceive_hw(pn512_t *pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb);
void pn512_transceive_hw_tx_task(uint32_t events, void *pUserData);
void pn512_transceive_hw_tx_iteration(pn512_t *pPN512, bool start);
void pn512_transceive_hw_rx_start(pn512_t *pPN512);
void pn512_transceive_hw_rx_task(uint32_t events, void *pUserData);
#ifdef __cplusplus
}
#endif
#endif /* PN512_TRANSCEIVE_H_ */

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_types.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef TRANSCEIVER_PN512_PN512_TYPES_H_
#define TRANSCEIVER_PN512_PN512_TYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
typedef struct __pn512 pn512_t;
typedef struct __pn512_registers {
int8_t registers_page;
} pn512_registers_t;
#ifdef __cplusplus
}
#endif
#endif /* TRANSCEIVER_PN512_PN512_TYPES_H_ */

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file protocols.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details List of RF protocols
*/
/** \addtogroup Transceiver
* @{
* \name Protocols and RF configuration
* @{
*/
#ifndef PROTOCOLS_H_
#define PROTOCOLS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
typedef enum __RF_PROTOCOL {
__RF_PROTOCOL_UNKNOWN = 0,
//Reader
RF_PROTOCOL_ISO_14443_A_READER,
RF_PROTOCOL_ISO_14443_B_READER,
RF_PROTOCOL_INNOVATRON_READER,
RF_PROTOCOL_ISO_15693_READER,
RF_PROTOCOL_FELICA_READER,
//... add other protocols here
RF_PROTOCOL_ISO_14443_A_TARGET,
RF_PROTOCOL_ISO_14443_B_TARGET,
RF_PROTOCOL_INNOVATRON_TARGET,
RF_PROTOCOL_ISO_15693_TARGET,
RF_PROTOCOL_FELICA_TARGET,
RF_PROTOCOL_ISO_DEP_TARGET, //ISO 14443-4 transport protocol
RF_PROTOCOL_NFC_DEP_TARGET, //NFC-IP 1 transport protocol
//... add other protocols here
} RF_PROTOCOL;
#define RF_PROTOCOL_IS_TARGET(x) ((x)>=RF_PROTOCOL_ISO_14443_A_TARGET)
#define RF_PROTOCOL_IS_READER(x) (!RF_PROTOCOL_IS_TARGET(x))
typedef uint32_t RF_OPTION;
//These options can be ORed
#define RF_OPTION_NONE 0x00
#define RF_OPTION_COMPUTE_CRC 0x01
#define RF_OPTION_COMPUTE_PARITY 0x02
#define RF_OPTION_CHECK_CRC 0x04
#define RF_OPTION_CHECK_PARITY 0x08
#define RF_OPTION_CLOSE 0x10 //Last frame
typedef enum __RF_BITRATE {
RF_BITRATE_106K = 0x00,
RF_BITRATE_212K = 0x01,
RF_BITRATE_424K = 0x02,
RF_BITRATE_848K = 0x03,
} RF_BITRATE;
#ifdef __cplusplus
}
#endif
#endif /* PROTOCOLS_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file transceiver.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Transceiver
*/
/** \addtogroup Transceiver
* @{
* \name Initialization
* @{
*/
#include "transceiver.h"
/** Initialize nfc_transceiver_t structure
* \param pTransceiver pointer to nfc_transceiver_t structure to initialize
* \param pTransport pointer to already initialized nfc_transport_t structure
* \param pImpl pointer to the structure implementing the transceiver interface (eg pn512_t or pn532_t)
*/
void transceiver_init(nfc_transceiver_t *pTransceiver, nfc_transport_t *pTransport, nfc_scheduler_timer_t *pTimer)
{
pTransceiver->pTransport = pTransport;
nfc_scheduler_init(&pTransceiver->scheduler, pTimer);
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,272 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file transceiver.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef TRANSCEIVER_H_
#define TRANSCEIVER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
typedef struct __nfc_tech nfc_tech_t;
typedef struct __transceiver nfc_transceiver_t;
typedef struct __transceiver_impl transceiver_impl_t;
#include "protocols.h"
#include "platform/nfc_transport.h"
#include "platform/nfc_scheduler.h"
enum __nfc_framing {
nfc_framing_unknown,
nfc_framing_target_mode_detector, //Framing is unknown and will be detected by the hardware
nfc_framing_target_a_106,
nfc_framing_target_b_106,
nfc_framing_target_f_212,
nfc_framing_target_f_424,
nfc_framing_initiator_a_106,
nfc_framing_initiator_b_106,
nfc_framing_initiator_f_212,
nfc_framing_initiator_f_424,
};
typedef enum __nfc_framing nfc_framing_t;
struct __nfc_tech {
unsigned int nfc_type1 : 1;
unsigned int nfc_type2 : 1;
unsigned int nfc_type3 : 1;
unsigned int nfc_iso_dep_a : 1;
unsigned int nfc_iso_dep_b : 1;
unsigned int nfc_nfc_dep_a : 1;
unsigned int nfc_nfc_dep_f_212 : 1;
unsigned int nfc_nfc_dep_f_424 : 1;
};
typedef struct __polling_options polling_options_t;
struct __polling_options {
unsigned int bail_at_first_target : 1;
unsigned int bail_at_first_tech : 1;
int32_t listen_for;
};
typedef void (*transceiver_cb_t)(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData);
typedef void (*set_protocols_fn_t)(nfc_transceiver_t *pTransceiver, nfc_tech_t initiators, nfc_tech_t targets, polling_options_t options);
typedef void (*poll_fn_t)(nfc_transceiver_t *pTransceiver);
typedef void (*set_crc_fn_t)(nfc_transceiver_t *pTransceiver, bool crcOut, bool crcIn);
typedef void (*set_timeout_fn_t)(nfc_transceiver_t *pTransceiver, int timeout);
typedef void (*set_transceive_options_fn_t)(nfc_transceiver_t *pTransceiver, bool transmit, bool receive, bool repoll);
typedef void (*set_transceive_framing_fn_t)(nfc_transceiver_t *pTransceiver, nfc_framing_t framing);
typedef void (*set_write_fn_t)(nfc_transceiver_t *pTransceiver, ac_buffer_t *pWriteBuf); //Set write buffer
typedef ac_buffer_t *(*get_read_fn_t)(nfc_transceiver_t *pTransceiver); //Get read buffer
typedef size_t (*get_last_byte_length_fn_t)(nfc_transceiver_t *pTransceiver);
typedef void (*set_last_byte_length_fn_t)(nfc_transceiver_t *pTransceiver, size_t lastByteLength);
typedef size_t (*get_first_byte_align_fn_t)(nfc_transceiver_t *pTransceiver);
typedef void (*set_first_byte_align_fn_t)(nfc_transceiver_t *pTransceiver, size_t firstByteAlign);
typedef void (*transceive_fn_t)(nfc_transceiver_t *pTransceiver);
typedef void (*abort_fn_t)(nfc_transceiver_t *pTransceiver);
typedef void (*close_fn_t)(nfc_transceiver_t *pTransceiver);
typedef void (*sleep_fn_t)(nfc_transceiver_t *pTransceiver, bool sleep);
struct __transceiver_impl {
set_protocols_fn_t set_protocols;
poll_fn_t poll;
set_crc_fn_t set_crc;
set_timeout_fn_t set_timeout;
set_transceive_options_fn_t set_transceive_options;
set_transceive_framing_fn_t set_transceive_framing;
set_write_fn_t set_write;
get_read_fn_t get_read;
set_last_byte_length_fn_t set_last_byte_length;
get_last_byte_length_fn_t get_last_byte_length;
set_first_byte_align_fn_t set_first_byte_align;
transceive_fn_t transceive;
abort_fn_t abort;
close_fn_t close;
sleep_fn_t sleep;
};
typedef struct __nfc_a_info nfc_a_info_t;
struct __nfc_a_info {
uint8_t uid[10];
size_t uidLength;
uint8_t sak;
uint8_t atqa[2];
};
typedef struct __nfc_b_info nfc_b_info_t;
struct __nfc_b_info {
uint8_t pupi[4];
uint8_t application_data[4];
uint8_t protocol_info[3];
};
typedef struct __nfc_f_info nfc_f_info_t;
struct __nfc_f_info {
uint8_t nfcid2[8];
};
typedef struct __nfc_info nfc_info_t;
struct __nfc_info {
nfc_tech_t type;
union {
nfc_a_info_t nfcA;
nfc_b_info_t nfcB;
nfc_f_info_t nfcF;
};
};
#define MUNFC_MAX_REMOTE_TARGETS 4
struct __transceiver {
const transceiver_impl_t *fn; //vtable
bool initiator_ntarget;
nfc_info_t remote_targets[MUNFC_MAX_REMOTE_TARGETS];
size_t remote_targets_count;
nfc_tech_t active_tech;
transceiver_cb_t cb; //Callback to upper layer
void *pUserData;
nfc_task_t task; //Task for deferred execution
nfc_transport_t *pTransport;
nfc_scheduler_t scheduler;
};
void transceiver_init(nfc_transceiver_t *pTransceiver, nfc_transport_t *pTransport, nfc_scheduler_timer_t *pTimer);
static inline void transceiver_set_protocols(nfc_transceiver_t *pTransceiver, nfc_tech_t initiators, nfc_tech_t targets, polling_options_t options)
{
pTransceiver->fn->set_protocols(pTransceiver, initiators, targets, options);
}
static inline void transceiver_poll(nfc_transceiver_t *pTransceiver, transceiver_cb_t cb, void *pUserData)
{
pTransceiver->cb = cb;
pTransceiver->pUserData = pUserData;
pTransceiver->fn->poll(pTransceiver);
}
static inline void transceiver_set_crc(nfc_transceiver_t *pTransceiver, bool crcOut, bool crcIn)
{
pTransceiver->fn->set_crc(pTransceiver, crcOut, crcIn);
}
static inline void transceiver_set_timeout(nfc_transceiver_t *pTransceiver, int timeout)
{
pTransceiver->fn->set_timeout(pTransceiver, timeout);
}
static inline void transceiver_set_transceive_options(nfc_transceiver_t *pTransceiver, bool transmit, bool receive, bool repoll)
{
pTransceiver->fn->set_transceive_options(pTransceiver, transmit, receive, repoll);
}
static inline void transceiver_set_transceive_framing(nfc_transceiver_t *pTransceiver, nfc_framing_t framing)
{
pTransceiver->fn->set_transceive_framing(pTransceiver, framing);
}
static inline void transceiver_set_write(nfc_transceiver_t *pTransceiver, ac_buffer_t *pWriteBuf)
{
pTransceiver->fn->set_write(pTransceiver, pWriteBuf);
}
static inline ac_buffer_t *transceiver_get_read(nfc_transceiver_t *pTransceiver)
{
return pTransceiver->fn->get_read(pTransceiver);
}
static inline size_t transceiver_get_last_byte_length(nfc_transceiver_t *pTransceiver)
{
return pTransceiver->fn->get_last_byte_length(pTransceiver);
}
static inline void transceiver_set_last_byte_length(nfc_transceiver_t *pTransceiver, size_t lastByteLength)
{
pTransceiver->fn->set_last_byte_length(pTransceiver, lastByteLength);
}
static inline void transceiver_set_first_byte_align(nfc_transceiver_t *pTransceiver, size_t firstByteAlign)
{
pTransceiver->fn->set_first_byte_align(pTransceiver, firstByteAlign);
}
static inline void nfc_transceiver_transceive(nfc_transceiver_t *pTransceiver, transceiver_cb_t cb, void *pUserData)
{
pTransceiver->cb = cb;
pTransceiver->pUserData = pUserData;
pTransceiver->fn->transceive(pTransceiver);
}
static inline void transceiver_abort(nfc_transceiver_t *pTransceiver)
{
pTransceiver->fn->abort(pTransceiver);
}
static inline void transceiver_close(nfc_transceiver_t *pTransceiver)
{
pTransceiver->fn->close(pTransceiver);
}
static inline bool transceiver_is_initiator_mode(nfc_transceiver_t *pTransceiver)
{
return pTransceiver->initiator_ntarget;
}
static inline nfc_tech_t transceiver_get_active_techs(nfc_transceiver_t *pTransceiver)
{
return pTransceiver->active_tech;
}
static inline nfc_scheduler_t *transceiver_get_scheduler(nfc_transceiver_t *pTransceiver)
{
return &pTransceiver->scheduler;
}
static inline const nfc_info_t *transceiver_get_remote_target_info(nfc_transceiver_t *pTransceiver, size_t number)
{
if (number > pTransceiver->remote_targets_count) {
return NULL;
}
return &pTransceiver->remote_targets[number];
}
static inline size_t transceiver_get_remote_targets_count(nfc_transceiver_t *pTransceiver)
{
return pTransceiver->remote_targets_count;
}
static inline void transceiver_sleep(nfc_transceiver_t *pTransceiver, bool sleep)
{
pTransceiver->fn->sleep(pTransceiver, sleep);
}
#ifdef __cplusplus
}
#endif
#endif /* TRANSCEIVER_H_ */

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file transceiver_internal.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef TRANSCEIVER_INTERNAL_H_
#define TRANSCEIVER_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "transceiver.h"
static inline void transceiver_callback(nfc_transceiver_t *pTransceiver, nfc_err_t ret)
{
pTransceiver->cb(pTransceiver, ret, pTransceiver->pUserData);
}
#ifdef __cplusplus
}
#endif
#endif /* TRANSCEIVER_INTERNAL_H_ */

View File

@ -305,7 +305,7 @@ struct Span {
_data(other.data())
{
MBED_STATIC_ASSERT(
(span_detail::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value),
(span_detail::is_convertible<OtherElementType (*)[1], ElementType (*)[1]>::value),
"OtherElementType(*)[] should be convertible to ElementType (*)[]"
);
}
@ -594,7 +594,7 @@ struct Span<ElementType, SPAN_DYNAMIC_EXTENT> {
_data(other.data()), _size(other.size())
{
MBED_STATIC_ASSERT(
(span_detail::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value),
(span_detail::is_convertible<OtherElementType (*)[1], ElementType (*)[1]>::value),
"OtherElementType(*)[] should be convertible to ElementType (*)[]"
);
}