mirror of https://github.com/ARMmbed/mbed-os.git
commit
f82feecc51
|
@ -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);
|
||||
}
|
|
@ -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/*"
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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_ */
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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_ */
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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 (*)[]"
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue