Add NFC Stack

pull/7822/head
Donatien Garnier 2018-08-13 18:14:54 +01:00
parent 5691a663b4
commit cd7f518596
49 changed files with 7905 additions and 0 deletions

View File

@ -0,0 +1,122 @@
/*
* 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.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
/** \addtogroup ACore
* @{
* \name Buffer
* @{
*/
#ifndef ACORE_BUFFER_H_
#define ACORE_BUFFER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stddef.h"
#include "stdbool.h"
typedef struct __ac_buffer
{
const uint8_t* data;
size_t size;
struct __ac_buffer* pNext;
} ac_buffer_t;
/** Initialize ac_buffer using underlying byte array, set ac_buffer's length to 0 (empty)
* \param pBuf pointer to ac_buffer_t structure to initialize
* \param data byte array to use
* \param size size of byte array
*/
void ac_buffer_init(ac_buffer_t* pBuf, const uint8_t* data, size_t size);
/** Copy pBufIn to pBuf
* \param pBuf pointer to ac_buffer_t structure to initialize
* \param pBufIn the source buffer
*/
void ac_buffer_dup(ac_buffer_t* pBuf, const ac_buffer_t* pBufIn);
/** Get buffer's underlying byte array
* \param pBuf pointer to ac_buffer_t structure
* \return underlying array
*/
static inline const uint8_t* ac_buffer_data(const ac_buffer_t* pBuf)
{
return pBuf->data;
}
/** Get buffer's size
* \param pBuf pointer to ac_buffer_t structure
* \return buffer's size
*/
static inline size_t ac_buffer_size(const ac_buffer_t* pBuf)
{
return pBuf->size;
}
/** Get next buffer in chain
* \param pBuf pointer to ac_buffer_t structure
* \return pointer to next buffer
*/
static inline ac_buffer_t* ac_buffer_next(const ac_buffer_t* pBuf)
{
return pBuf->pNext;
}
/** Set next buffer in chain
* \param pBuf pointer to ac_buffer_t structure
* \param pNextBuf pointer to next buffer (or NULL to break chain)
*/
static inline void ac_buffer_set_next(ac_buffer_t* pBuf, ac_buffer_t* pNextBuf)
{
pBuf->pNext = (ac_buffer_t*) pNextBuf;
}
/** Append buffer to end of chain
* \param pBuf pointer to ac_buffer_t structure
* \param pAppBuf pointer to buffer to append to chain
*/
void ac_buffer_append(ac_buffer_t* pBuf, ac_buffer_t* pAppBuf);
/** Truncate pBuf to length bytes and save the remaining bytes in pEndBuf
* \param pBuf The buffer to split (will be set to invalid state)
* \param pStartBuf A new buffer at the head of the split
* \param pEndBuf A new buffer at the tail of the split
* \param length How long pStartBuf should be (if longer than pBuf, then pStartBuf will be pBuf)
*/
void ac_buffer_split(ac_buffer_t* pStartBuf, ac_buffer_t* pEndBuf, ac_buffer_t* pBuf, size_t length);
//Debug
void ac_buffer_dump(ac_buffer_t* pBuf);
#ifdef __cplusplus
}
#endif
#endif /* ACORE_BUFFER_H_ */
/**
* @}
* @}
* */

View File

@ -0,0 +1,380 @@
/*
* 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.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/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_ac_buffer(ac_buffer_builder_t* pBuilder);
/** Reset ac_buffer builder
* \param pBuilder ac_buffer builder to reset
*/
void ac_buffer_builder_reset(ac_buffer_builder_t* pBuilder);
/** Set ac_buffer builder's ac_buffer to full size
* \param pBuilder ac_buffer builder to set to full size
*/
void ac_buffer_builder_set_full(ac_buffer_builder_t* pBuilder);
/** Get ac_buffer builder's length
* \param pBuilder ac_buffer builder to get length of
* \return number of valid bytes in ac_buffer
*/
static inline size_t ac_buffer_builder_length(ac_buffer_builder_t* pBuilder)
{
return ac_buffer_size(&pBuilder->ac_buffer);
}
/** Set ac_buffer builder's length
* \param pBuilder ac_buffer builder to set length of
* \param length number of valid bytes in ac_buffer
*/
static inline void ac_buffer_builder_set_length(ac_buffer_builder_t* pBuilder, size_t length)
{
if( ac_buffer_data(&pBuilder->ac_buffer) + length > pBuilder->data + pBuilder->size )
{
return;
}
pBuilder->ac_buffer.size = length;
}
/** Get ac_buffer builder's pointer to write position
* \param pBuilder ac_buffer builder
* \return pointer to write position
*/
static inline uint8_t* ac_buffer_builder_write_position(ac_buffer_builder_t* pBuilder)
{
return (uint8_t*)ac_buffer_data(&pBuilder->ac_buffer) + ac_buffer_size(&pBuilder->ac_buffer);
}
/** Get ac_buffer builder's write offset
* \param pBuilder ac_buffer builder
* \return write offset
*/
static inline size_t ac_buffer_builder_write_offset(ac_buffer_builder_t* pBuilder)
{
return ac_buffer_data(&pBuilder->ac_buffer) + ac_buffer_size(&pBuilder->ac_buffer) - pBuilder->data;
}
/** Set ac_buffer builder's write offset
* \param pBuilder ac_buffer builder
* \param off new write offset
*/
static inline void ac_buffer_builder_set_write_offset(ac_buffer_builder_t* pBuilder, size_t off)
{
if( off > pBuilder->size )
{
return;
}
if( pBuilder->data + off > pBuilder->ac_buffer.data )
{
pBuilder->ac_buffer.size = off - (pBuilder->ac_buffer.data - pBuilder->data);
}
else
{
pBuilder->ac_buffer.size = 0;
}
}
/** Get ac_buffer builder's read offset
* \param pBuilder ac_buffer builder
* \return read offset
*/
static inline size_t ac_buffer_builder_read_offset(ac_buffer_builder_t* pBuilder)
{
return ac_buffer_data(&pBuilder->ac_buffer) - pBuilder->data;
}
/** Set ac_buffer builder's read offset
* \param pBuilder ac_buffer builder
* \param off new read offset
*/
static inline void ac_buffer_builder_set_read_offset(ac_buffer_builder_t* pBuilder, size_t off)
{
if( off > pBuilder->size )
{
return;
}
if( pBuilder->data + off < pBuilder->ac_buffer.data + pBuilder->ac_buffer.size )
{
pBuilder->ac_buffer.size = pBuilder->ac_buffer.data - (pBuilder->data + off);
}
else
{
pBuilder->ac_buffer.size = 0;
}
pBuilder->ac_buffer.data = pBuilder->data + off;
}
/** Get ac_buffer builder's underlying ac_buffer
* \param pBuilder ac_buffer builder
* \return ac_buffer
*/
static inline ac_buffer_t* ac_buffer_builder_buffer(ac_buffer_builder_t* pBuilder)
{
return &pBuilder->ac_buffer;
}
/** Get space in ac_buffer builder
* \param pBuilder ac_buffer builder
* \return number of free bytes in ac_buffer builder
*/
static inline size_t ac_buffer_builder_space(ac_buffer_builder_t* pBuilder)
{
return pBuilder->size - (ac_buffer_data(&pBuilder->ac_buffer) - pBuilder->data + ac_buffer_size(&pBuilder->ac_buffer));
}
/** Is ac_buffer builder empty
* \param pBuilder ac_buffer builder
* \return true if ac_buffer builder is empty
*/
static inline bool ac_buffer_builder_empty(ac_buffer_builder_t* pBuilder)
{
return (ac_buffer_builder_length(pBuilder) == 0);
}
/** Is ac_buffer builder full
* \param pBuilder ac_buffer builder
* \return true if ac_buffer builder is full
*/
static inline bool ac_buffer_full(ac_buffer_builder_t* pBuilder)
{
return (ac_buffer_builder_space(pBuilder) == 0);
}
/** Write 8-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu8 8-bit value to write
*/
static inline void ac_buffer_builder_write_nu8(ac_buffer_builder_t* pBuilder, uint8_t hu8)
{
ac_buffer_builder_write_be(pBuilder, &hu8, 1);
}
/** Write 16-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu16 16-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu16(ac_buffer_builder_t* pBuilder, uint16_t hu16)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t*)&hu16, 2);
}
/** Write 24-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu24 24-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu24(ac_buffer_builder_t* pBuilder, uint32_t hu24)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t*)&hu24, 3);
}
/** Write 32-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu32 32-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu32(ac_buffer_builder_t* pBuilder, uint32_t hu32)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t*)&hu32, 4);
}
/** Write 64-bit value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param hu64 64-bit value to write in big-endian format
*/
static inline void ac_buffer_builder_write_nu64(ac_buffer_builder_t* pBuilder, uint64_t hu64)
{
ac_buffer_builder_write_be(pBuilder, (uint8_t*)&hu64, 8);
}
/** Write n-bytes value in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param data data to write
* \param size data length
*/
static inline void ac_buffer_builder_write_n_bytes(ac_buffer_builder_t* pBuilder, const uint8_t* data, size_t size)
{
ac_buffer_builder_write_le(pBuilder, data, size);
}
/** Write 8-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu8 8-bit value to write
*/
static inline void ac_buffer_builder_write_nu8_at(ac_buffer_builder_t* pBuilder, size_t off, uint8_t hu8)
{
ac_buffer_builder_write_be_at(pBuilder, off, &hu8, 1);
}
/** Write 16-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu16 16-bit value to write
*/
static inline void ac_buffer_builder_write_nu16_at(ac_buffer_builder_t* pBuilder, size_t off, uint16_t hu16)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t*)&hu16, 2);
}
/** Write 24-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu24 24-bit value to write
*/
static inline void ac_buffer_builder_write_nu24_at(ac_buffer_builder_t* pBuilder, size_t off, uint32_t hu24)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t*)&hu24, 3);
}
/** Write 32-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu32 32-bit value to write
*/
static inline void ac_buffer_builder_write_nu32_at(ac_buffer_builder_t* pBuilder, size_t off, uint32_t hu32)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t*)&hu32, 4);
}
/** Write 64-bit value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param hu64 64-bit value to write
*/
static inline void ac_buffer_builder_write_nu64_at(ac_buffer_builder_t* pBuilder, size_t off, uint64_t hu64)
{
ac_buffer_builder_write_be_at(pBuilder, off, (uint8_t*)&hu64, 8);
}
/** Write n-bytes value in ac_buffer builder at specified position
* \param pBuilder ac_buffer builder
* \param off offset at which to write
* \param data data to write
* \param size data length
*/
static inline void ac_buffer_builder_write_n_bytes_at(ac_buffer_builder_t* pBuilder, size_t off, const uint8_t* data, size_t size)
{
ac_buffer_builder_write_be_at(pBuilder, off, data, size);
}
/** Skip n-bytes in ac_buffer builder
* \param pBuilder ac_buffer builder
* \param size number of bytes to skip
*/
void ac_buffer_builder_write_n_skip(ac_buffer_builder_t* pBuilder, size_t size);
/** Copy n bytes from buffer to builder
* \param pBuilderOut ac_buffer builder
* \param pBufIn the input buffer
* \param size number of bytes to copy
*/
void ac_buffer_builder_copy_n_bytes(ac_buffer_builder_t* pBuilderOut, ac_buffer_t* pBufIn, size_t size);
/** Compact builder
* Will move underlying buffer's byte to start of allocated buffer
* \param pBuilder ac_buffer builder
*/
void ac_buffer_builder_compact(ac_buffer_builder_t* pBuilder);
/** Get number of writable bytes in ac_buffer builder
* \param pBuilder ac_buffer builder
* \return number of free bytes in ac_buffer builder
*/
static inline size_t ac_buffer_builder_writable(ac_buffer_builder_t* pBuilder)
{
return ac_buffer_builder_space(pBuilder);
}
#ifdef __cplusplus
}
#endif
#endif /* ACORE_BUFFER_BUILDER_H_ */
/**
* @}
* @}
* */

View File

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

View File

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

View File

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

View File

@ -0,0 +1,73 @@
/*
* 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.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/buffer.h"
typedef void (*ac_istream_fn)(ac_buffer_t* pDataIn, bool* pClose, size_t maxLength, void* pUserParam);
typedef void (*ac_ostream_fn)(ac_buffer_t* pDataOut, bool closed, void* pUserParam);
//Input stream -- pulled by consumer
struct __ac_istream
{
ac_istream_fn fn;
void* pUserParam;
};
//Output stream -- pushed by supplier
struct __ac_ostream
{
ac_ostream_fn fn;
void* pUserParam;
};
//Called by supplier
void ac_istream_init(ac_istream_t* pac_istream, ac_istream_fn fn, void* pUserParam);
//Called by consumer
void ac_istream_pull(ac_istream_t* pac_istream, ac_buffer_t* pDataIn, bool* pClose, size_t maxLength);
//Called by consumer
void ac_ostream_init(ac_ostream_t* pac_ostream, ac_ostream_fn fn, void* pUserParam);
//Called by supplier
void ac_ostream_push(ac_ostream_t* pac_ostream, ac_buffer_t* pDataOut, bool closed);
#ifdef __cplusplus
}
#endif
#endif /* ACORE_STREAM_H_ */

View File

@ -0,0 +1,105 @@
/*
* 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/buffer.h"
#include "acore/buffer_reader.h"
#include "acore/macros.h"
#include "acore/debug.h"
void ac_buffer_init(ac_buffer_t* pBuf, const uint8_t* data, size_t size)
{
pBuf->data = data;
pBuf->size = size;
pBuf->pNext = NULL;
}
void ac_buffer_dup(ac_buffer_t* pBuf, const ac_buffer_t* pBufIn)
{
if(pBuf != pBufIn)
{
memcpy(pBuf, pBufIn, sizeof(ac_buffer_t));
}
}
void ac_buffer_append(ac_buffer_t* pBuf, ac_buffer_t* pAppBuf)
{
while(pBuf->pNext != NULL)
{
pBuf = pBuf->pNext;
}
pBuf->pNext = pAppBuf;
}
void ac_buffer_split(ac_buffer_t* pStartBuf, ac_buffer_t* pEndBuf, ac_buffer_t* pBuf, size_t length)
{
ac_buffer_dup(pStartBuf, pBuf);
ac_buffer_dup(pEndBuf, pBuf);
ac_buffer_read_n_skip(pEndBuf, length);
while( length > ac_buffer_size(pStartBuf) )
{
length -= pStartBuf->size;
pStartBuf = pStartBuf->pNext;
}
pStartBuf->size = length;
pStartBuf->pNext = NULL;
}
/** Dump a ac_buffer's content to stdout (useful for debugging)
* \param pBuf pointer to ac_buffer_t structure
*/
void ac_buffer_dump(ac_buffer_t* pBuf)
{
#if !defined(NDEBUG)
ACORE_STDIO_LOCK();
while(pBuf != NULL)
{
size_t r = ac_buffer_size(pBuf);
size_t i = 0;
size_t j = 0;
while(i < r)
{
for(j = i; j < MIN(i + 16, r); j++)
{
ACORE_STDIO_PRINT("%02x ", ac_buffer_data(pBuf)[j]);
}
ACORE_STDIO_PRINT("\r\n");
i = j;
}
pBuf = ac_buffer_next(pBuf);
if(pBuf != NULL)
{
ACORE_STDIO_PRINT("->\r\n");
}
}
ACORE_STDIO_UNLOCK();
#else
(void)pBuf;
#endif
}

View File

@ -0,0 +1,119 @@
/*
* 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/buffer_builder.h"
#include "acore/buffer_reader.h"
#include "acore/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_ac_buffer(ac_buffer_builder_t* pBuilder)
{
pBuilder->data = (uint8_t*)pBuilder->ac_buffer.data;
pBuilder->size = pBuilder->ac_buffer.size;
pBuilder->ac_buffer.size = 0;
}
void ac_buffer_builder_reset(ac_buffer_builder_t* pBuilder)
{
ac_buffer_init(&pBuilder->ac_buffer, pBuilder->data, 0);
}
void ac_buffer_builder_set_full(ac_buffer_builder_t* pBuilder)
{
ac_buffer_init(&pBuilder->ac_buffer, pBuilder->data, pBuilder->size);
}
void ac_buffer_builder_write_be(ac_buffer_builder_t* pBuilder, const uint8_t* buf, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilder, size);
buf += size;
while(size > 0)
{
buf--;
*ac_buffer_builder_write_position(pBuilder) = *buf;
pBuilder->ac_buffer.size++;
size--;
}
}
void ac_buffer_builder_write_le(ac_buffer_builder_t* pBuilder, const uint8_t* buf, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilder, size);
memcpy(ac_buffer_builder_write_position(pBuilder), buf, size);
pBuilder->ac_buffer.size+=size;
}
void ac_buffer_builder_write_be_at(ac_buffer_builder_t* pBuilder, size_t pos, const uint8_t* buf, size_t size)
{
size_t currentPos = pBuilder->ac_buffer.size;
pBuilder->ac_buffer.size = pos;
ac_buffer_builder_write_be(pBuilder, buf, size);
pBuilder->ac_buffer.size = currentPos;
}
void ac_buffer_builder_write_le_at(ac_buffer_builder_t* pBuilder, size_t pos, const uint8_t* buf, size_t size)
{
size_t currentPos = pBuilder->ac_buffer.size;
pBuilder->ac_buffer.size = pos;
ac_buffer_builder_write_le(pBuilder, buf, size);
pBuilder->ac_buffer.size = currentPos;
}
void ac_buffer_builder_write_n_skip(ac_buffer_builder_t* pBuilder, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilder, size);
pBuilder->ac_buffer.size += size;
}
void ac_buffer_builder_copy_n_bytes(ac_buffer_builder_t* pBuilderOut, ac_buffer_t* pBufIn, size_t size)
{
ENSURE_WRITE_LENGTH(pBuilderOut, size);
if( ac_buffer_reader_readable(pBufIn) < size )
{
return;
}
while(size > 0)
{
size_t cpy = ac_buffer_reader_current_buffer_length(pBufIn);
cpy = MIN(cpy, size);
ac_buffer_builder_write_n_bytes(pBuilderOut, ac_buffer_reader_current_buffer_pointer(pBufIn), cpy);
ac_buffer_read_n_skip(pBufIn, cpy);
size -= cpy;
}
}
void ac_buffer_builder_compact(ac_buffer_builder_t* pBuilder)
{
memmove(pBuilder->data, ac_buffer_data(&pBuilder->ac_buffer), ac_buffer_size(&pBuilder->ac_buffer));
pBuilder->ac_buffer.data = pBuilder->data;
}

View File

@ -0,0 +1,183 @@
/*
* 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/buffer_reader.h"
#include "acore/macros.h"
#include "string.h"
#define VOID
#define ENSURE_READ_LENGTH(pBuf, n) do{ if( ac_buffer_reader_readable(pBuf) < n ) { return; } }while(0);
static inline void update_buf(ac_buffer_t* pBuf)
{
while( ac_buffer_size(pBuf) == 0 )
{
if( ac_buffer_next(pBuf) != NULL )
{
ac_buffer_t* pNext = ac_buffer_next(pBuf);
ac_buffer_init(pBuf, ac_buffer_data(pNext), ac_buffer_size(pNext));
pBuf->pNext = ac_buffer_next(pNext);
}
else if( pBuf->data != NULL )
{
ac_buffer_init(pBuf, NULL, 0);
}
else
{
return;
}
}
}
void ac_buffer_read_be(ac_buffer_t* pBuf, uint8_t* buf, size_t size)
{
ENSURE_READ_LENGTH(pBuf, size);
buf += size;
while(size > 0)
{
buf--;
*buf = *ac_buffer_data(pBuf);
pBuf->data++;
pBuf->size--;
update_buf(pBuf);
size--;
}
}
void ac_buffer_read_le(ac_buffer_t* pBuf, uint8_t* buf, size_t size)
{
ENSURE_READ_LENGTH(pBuf, size);
while(size > 0)
{
size_t cpy = ac_buffer_size(pBuf);
cpy = MIN(cpy, size);
memcpy(buf, ac_buffer_data(pBuf), cpy);
pBuf->data+=cpy;
pBuf->size-=cpy;
update_buf(pBuf);
size-=cpy;
buf+=cpy;
}
}
void ac_buffer_read_n_skip(ac_buffer_t* pBuf, size_t size)
{
ENSURE_READ_LENGTH(pBuf, size);
while(size > 0)
{
size_t cpy = ac_buffer_size(pBuf);
cpy = MIN(cpy, size);
pBuf->data+=cpy;
pBuf->size-=cpy;
update_buf(pBuf);
size-=cpy;
}
}
size_t ac_buffer_reader_readable(const ac_buffer_t* pBuf)
{
size_t r = 0;
while( pBuf != NULL )
{
r += ac_buffer_size(pBuf);
pBuf = ac_buffer_next(pBuf);
}
return r;
}
const uint8_t* ac_buffer_reader_current_buffer_pointer(ac_buffer_t* pBuf)
{
update_buf(pBuf);
return ac_buffer_data(pBuf);
}
size_t ac_buffer_reader_current_buffer_length(ac_buffer_t* pBuf)
{
update_buf(pBuf);
return ac_buffer_size(pBuf);
}
bool ac_buffer_reader_cmp_bytes(const ac_buffer_t* pBuf, const uint8_t* bytes, size_t length)
{
ac_buffer_t reader;
if( length > ac_buffer_reader_readable(pBuf) )
{
return false;
}
ac_buffer_dup(&reader, pBuf);
while(length > 0)
{
size_t sz = ac_buffer_reader_current_buffer_length(&reader);
if( sz > length )
{
sz = length;
}
int c = memcmp(ac_buffer_reader_current_buffer_pointer(&reader), bytes, sz);
if(c)
{
return false;
}
length -= sz;
bytes += sz;
ac_buffer_read_n_skip(&reader, sz);
}
return true;
}
bool ac_buffer_reader_cmp(const ac_buffer_t* pBuf1, const ac_buffer_t* pBuf2)
{
ac_buffer_t reader1;
ac_buffer_t reader2;
if( ac_buffer_reader_readable(pBuf1) != ac_buffer_reader_readable(pBuf2) )
{
return false;
}
ac_buffer_dup(&reader1, pBuf1);
ac_buffer_dup(&reader2, pBuf2);
size_t length = ac_buffer_reader_readable(pBuf1);
while(length > 0)
{
size_t sz1 = ac_buffer_reader_current_buffer_length(&reader1);
size_t sz2 = ac_buffer_reader_current_buffer_length(&reader2);
size_t sz = MIN(sz1, sz2);
int c = memcmp(ac_buffer_reader_current_buffer_pointer(&reader1), ac_buffer_reader_current_buffer_pointer(&reader2), sz);
if(c)
{
return false;
}
length -= sz;
ac_buffer_read_n_skip(&reader1, sz);
ac_buffer_read_n_skip(&reader2, sz);
}
return true;
}

View File

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

View File

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

View File

@ -0,0 +1,62 @@
/*
* 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)
#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", __MODULE__, __LINE__, __VA_ARGS__)
#endif
#if !defined(NFC_WARN)
#define NFC_WARN(...) nfc_dbg_print("WARN", __MODULE__, __LINE__, __VA_ARGS__)
#endif
#if !defined(NFC_ERR)
#define NFC_ERR(...) nfc_dbg_print("ERR", __MODULE__, __LINE__, __VA_ARGS__)
#endif
#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
#endif
#endif

View File

@ -0,0 +1,208 @@
/*
* 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
*/
#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)
{
bool triggered = false;
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
triggered = true;
}
return MAX_TIMEOUT;
}
void nfc_scheduler_queue_task(nfc_scheduler_t* pScheduler, nfc_task_t* pTask)
{
pTask->timeout = pTask->timeoutInitial + nfc_scheduler_timer_get(pScheduler->pTimer);
NFC_DBG("Queuing task %p: events %1X, timeout %lu ms", pTask, pTask->events, pTask->timeout);
//Find last task
nfc_task_t* pPrevTask = pScheduler->pNext;
pTask->pNext = NULL;
if( pPrevTask == NULL )
{
pScheduler->pNext = pTask;
return;
}
while( pPrevTask->pNext != NULL )
{
pPrevTask = pPrevTask->pNext;
}
pPrevTask->pNext = pTask;
}
void nfc_scheduler_dequeue_task(nfc_scheduler_t* pScheduler, bool abort, nfc_task_t* pTask)
{
NFC_DBG("Dequeuing task %p", pTask);
//Find task
nfc_task_t* pPrevTask = pScheduler->pNext;
if( pPrevTask == NULL )
{
pTask->pNext = NULL;
return;
}
if( pPrevTask == pTask )
{
if(abort)
{
pTask->fn(EVENT_ABORTED, pTask->pUserData);
}
pScheduler->pNext = pTask->pNext;
pTask->pNext = NULL;
return;
}
while( pPrevTask->pNext != NULL )
{
if(pPrevTask->pNext == pTask)
{
if(abort)
{
pTask->fn(EVENT_ABORTED, pTask->pUserData);
}
pPrevTask->pNext = pTask->pNext;
pTask->pNext = NULL;
return;
}
pPrevTask = pPrevTask->pNext;
}
pTask->pNext = NULL;
}
void task_init(nfc_task_t* pTask, uint32_t events, uint32_t timeout, nfc_task_fn fn, void* pUserData)
{
pTask->events = events;
pTask->timeoutInitial = timeout;
pTask->fn = fn;
pTask->pUserData = pUserData;
pTask->pNext = NULL;
}

View File

@ -0,0 +1,124 @@
/*
* 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 "core/fwk.h"
#ifdef __cplusplus
extern "C" {
#endif
#define EVENT_NONE 0
#define EVENT_TIMEOUT 1
#define EVENT_ABORTED 2
#define EVENT_HW_INTERRUPT 4
struct __nfc_timer;
typedef struct __nfc_timer nfc_scheduler_timer_t;
struct __nfc_task;
typedef struct __nfc_task nfc_task_t;
typedef struct __scheduler
{
nfc_task_t* pNext;
nfc_scheduler_timer_t* pTimer;
} nfc_scheduler_t;
typedef void (*nfc_task_fn)(uint32_t events, void* pUserData);
struct __nfc_task
{
uint32_t events;
int64_t timeout; //millisecs
int64_t timeoutInitial;
nfc_task_fn fn;
void* pUserData;
nfc_task_t* pNext;
};
void nfc_scheduler_timer_init(nfc_scheduler_timer_t* timer);
void nfc_scheduler_timer_start(nfc_scheduler_timer_t* timer);
uint32_t nfc_scheduler_timer_get(nfc_scheduler_timer_t* timer);
void nfc_scheduler_timer_stop(nfc_scheduler_timer_t* timer);
void nfc_scheduler_timer_reset(nfc_scheduler_timer_t* timer);
/** Init scheduler
* \param pScheduler scheduler instance to init
* \param pTimer timer instance
*/
void nfc_scheduler_init(nfc_scheduler_t* pScheduler, nfc_scheduler_timer_t* pTimer);
/** Iterate through all tasks
* \param pScheduler scheduler instance
* \param events mask of events (except EVENT_TIMEOUT) that have been raised since this function last returned (0 on first call)
* \return time after which this function must be called again if no other event arises
*/
uint32_t nfc_scheduler_iteration(nfc_scheduler_t* pScheduler, uint32_t events);
/** Queue a task to execute
* \param pScheduler scheduler instance
* \param pTask task to queue
*
*/
void nfc_scheduler_queue_task(nfc_scheduler_t* pScheduler, nfc_task_t* pTask);
/** Remove a task to execute
* \param pScheduler scheduler instance
* \param pTask task to remove
* \param abort abort task if queued
*/
void nfc_scheduler_dequeue_task(nfc_scheduler_t* pScheduler, bool abort, nfc_task_t* pTask);
/** Initialize task with the following parameters
* \param pTask task to initialize
* \param events events on which to call task
* \param timeout if relevant
* \param fn function to be called
* \param pUserData data that will be passed to function
*/
void task_init(nfc_task_t* pTask, uint32_t events, uint32_t timeout, nfc_task_fn fn, void* pUserData);
#ifdef __cplusplus
}
#endif
#endif /* NFC_SCHEDULER_H_ */
/**
* @}
* @}
* */

View File

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

View File

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

View File

@ -0,0 +1,366 @@
/*
* 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 "inc/nfc.h"
#include "iso7816.h"
#include "iso7816_app.h"
#include "iso7816_defs.h"
#include "tech/isodep/isodep_target.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(buffer_t* ppDataIn, bool* pClose, size_t maxLength, void* pUserParam);
static void iso_dep_stream_receive_cb(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)
{
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;
istream_init(&pIso7816->inputStream, iso_dep_stream_transmit_cb, pIso7816);
ostream_init(&pIso7816->outputStream, iso_dep_stream_receive_cb, pIso7816);
buffer_builder_init(&pIso7816->txBldr, pIso7816->txBuf, 2); //Just enough to fit sw
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
buffer_builder_reset(&pIso7816->txBldr);
buffer_builder_write_nu16(&pIso7816->txBldr, pIso7816->rApdu.sw);
buffer_append(&pIso7816->rApdu.dataOut, buffer_builder_buffer(&pIso7816->txBldr));
NFC_DBG("R-ADPU: (LE):%02X SW:%04X", buffer_reader_readable(&pIso7816->rApdu.dataOut), pIso7816->rApdu.sw);
DBG_BLOCK( 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;
}
pIso7816->disconnectedCb(pIso7816, deselected, pIso7816->pUserData);
}
nfc_err_t iso7816_parse(nfc_tech_iso7816_t* pIso7816)
{
//Reset R-APDU
buffer_init(&pIso7816->rApdu.dataOut, NULL, 0);
pIso7816->rApdu.sw = ISO7816_SW_OK;
DBG_BLOCK( buffer_dump(buffer_builder_buffer(&pIso7816->rxBldr)); )
if( buffer_reader_readable( 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 = buffer_read_nu8(buffer_builder_buffer(&pIso7816->rxBldr));
pIso7816->cApdu.ins = buffer_read_nu8(buffer_builder_buffer(&pIso7816->rxBldr));
pIso7816->cApdu.p1 = buffer_read_nu8(buffer_builder_buffer(&pIso7816->rxBldr));
pIso7816->cApdu.p2 = buffer_read_nu8(buffer_builder_buffer(&pIso7816->rxBldr));
buffer_init(&pIso7816->cApdu.dataIn, NULL, 0);
pIso7816->cApdu.maxRespLength = 0;
if( buffer_reader_readable(buffer_builder_buffer(&pIso7816->rxBldr)) > 1 )
{
size_t lc = buffer_read_nu8(buffer_builder_buffer(&pIso7816->rxBldr));
if( buffer_reader_readable(buffer_builder_buffer(&pIso7816->rxBldr)) >= lc )
{
buffer_split(&pIso7816->cApdu.dataIn, buffer_builder_buffer(&pIso7816->rxBldr), 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( buffer_reader_readable(buffer_builder_buffer(&pIso7816->rxBldr)) >= 1 )
{
pIso7816->cApdu.maxRespLength = buffer_read_nu8(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,
buffer_reader_readable(&pIso7816->cApdu.dataIn), pIso7816->cApdu.maxRespLength);
if( buffer_reader_readable(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)
{
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( buffer_reader_readable(&pIso7816->cApdu.dataIn) <= pApp->aidSize )
{
if( buffer_reader_cmp_bytes(&pIso7816->cApdu.dataIn, pApp->aid, 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 disconnected");
iso7816_disconnected(pIso7816, deselected);
}
void iso_dep_stream_transmit_cb(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 >= buffer_reader_readable(&pIso7816->rApdu.dataOut) )
//if( buffer_total_length(&pLlcp->tx) <= maxLength )
{
maxLength = buffer_reader_readable(&pIso7816->rApdu.dataOut);
*pClose = true;
}
else
{
*pClose = false;
}
buffer_split(pDataIn, &pIso7816->rApdu.dataOut, &pIso7816->rApdu.dataOut, maxLength);
}
void iso_dep_stream_receive_cb(buffer_t* pDataOut, bool closed, void* pUserParam)
{
nfc_tech_iso7816_t* pIso7816 = (nfc_tech_iso7816_t*) pUserParam;
(void) closed;
if( buffer_reader_readable(pDataOut) > buffer_builder_writeable(&pIso7816->rxBldr) )
{
NFC_ERR("Frame will not fit (%d > %d)", buffer_reader_readable(pDataOut), buffer_builder_writeable(&pIso7816->rxBldr) );
}
//Feed rx buffer
buffer_builder_copy_n_bytes(&pIso7816->rxBldr, pDataOut, buffer_reader_readable(pDataOut));
}

View File

@ -0,0 +1,114 @@
/*
* 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_
#ifdef __cplusplus
extern "C" {
#endif
#include "acore/fwk.h"
#include "transceiver/protocols.h"
#include "tech/isodep/isodep_target.h"
struct nfc_tech_iso7816_c_apdu
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
buffer_t dataIn;
size_t maxRespLength;
};
struct nfc_tech_iso7816_r_apdu
{
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, bool deselected, 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;
buffer_t hist; //Historical bytes
istream_t inputStream;
ostream_t outputStream;
//PDU buffer (tx)
uint8_t txBuf[2];
buffer_builder_t txBldr;
//Receive buffer
uint8_t rxBuf[ISO7816_RX_BUFFER_SIZE];
buffer_builder_t rxBldr;
};
void nfc_tech_iso7816_init(nfc_tech_iso7816_t* pIso7816, nfc_transceiver_t* pTransceiver, nfc_tech_iso7816_disconnected_cb disconnectedCb, void* pUserData);
void nfc_tech_iso7816_add_app(nfc_tech_iso7816_t* pIso7816, nfc_tech_iso7816_app_t* pIso7816App);
void nfc_tech_iso7816_connect(nfc_tech_iso7816_t* pIso7816);
void nfc_tech_iso7816_disconnect(nfc_tech_iso7816_t* pIso7816);
nfc_err_t nfc_tech_iso7816_reply(nfc_tech_iso7816_t* pIso7816);
inline static nfc_tech_iso7816_c_apdu_t* nfc_tech_iso7816_c_apdu(nfc_tech_iso7816_t* pIso7816)
{
return &pIso7816->cApdu;
}
inline static nfc_tech_iso7816_r_apdu_t* nfc_tech_iso7816_r_apdu(nfc_tech_iso7816_t* pIso7816)
{
return &pIso7816->rApdu;
}
#ifdef __cplusplus
}
#endif
#endif /* ISO7816_H_ */

View File

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

View File

@ -0,0 +1,81 @@
/*
* 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_
#ifdef __cplusplus
extern "C" {
#endif
#include "inc/nfc.h"
#include "iso7816.h"
struct nfc_tech_iso7816;
struct nfc_tech_iso7816_app;
typedef struct nfc_tech_iso7816 nfc_tech_iso7816_t;
typedef struct nfc_tech_iso7816_app nfc_tech_iso7816_app_t;
typedef void (*nfc_tech_iso7816_app_cb)( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData );
struct nfc_tech_iso7816_app
{
nfc_tech_iso7816_t* pIso7816;
const uint8_t* aid;
size_t aidSize;
nfc_tech_iso7816_app_cb selected;
nfc_tech_iso7816_app_cb deselected;
nfc_tech_iso7816_app_cb apdu;
void* pUserData;
nfc_tech_iso7816_app_t* pNext;
};
void nfc_tech_iso7816_app_init(nfc_tech_iso7816_app_t* pIso7816App, nfc_tech_iso7816_t* pIso7816, const uint8_t* aid, size_t aidSize,
nfc_tech_iso7816_app_cb selected,
nfc_tech_iso7816_app_cb deselected,
nfc_tech_iso7816_app_cb apdu,
void* pUserData
);
inline static nfc_err_t nfc_tech_iso7816_app_reply(nfc_tech_iso7816_app_t* pIso7816App)
{
return nfc_tech_iso7816_reply(pIso7816App->pIso7816);
}
inline static nfc_tech_iso7816_c_apdu_t* nfc_tech_iso7816_app_c_apdu(nfc_tech_iso7816_app_t* pIso7816App)
{
return nfc_tech_iso7816_c_apdu(pIso7816App->pIso7816);
}
inline static nfc_tech_iso7816_r_apdu_t* nfc_tech_iso7816_app_r_apdu(nfc_tech_iso7816_app_t* pIso7816App)
{
return nfc_tech_iso7816_r_apdu(pIso7816App->pIso7816);
}
#ifdef __cplusplus
}
#endif
#endif /* TECH_ISO7816_ISO7816_APP_H_ */

View File

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

View File

@ -0,0 +1,48 @@
/*
* 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_
#ifdef __cplusplus
extern "C" {
#endif
#include "transceiver/transceiver.h"
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);
struct nfc_tech_isodep
{
};
#ifdef __cplusplus
}
#endif
#endif /* ISODEP_H_ */

View File

@ -0,0 +1,750 @@
/*
* 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 "inc/nfc.h"
#include "isodep_target.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, 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, 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,
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, 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, 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)
{
//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, 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
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, 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;
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)
{
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( buffer_reader_readable(pIsodepTarget->commands.pReq) < 2 )
{
NFC_ERR("Payload too short");
return NFC_ERR_PROTOCOL;
}
buffer_read_n_skip(pIsodepTarget->commands.pReq, 1);
uint8_t b = 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( buffer_reader_readable(pIsodepTarget->commands.pReq) < 1 )
{
NFC_ERR("Payload too short");
return NFC_ERR_PROTOCOL;
}
uint8_t pcb = buffer_read_nu8(pIsodepTarget->commands.pReq);
// Udpate if/when we support DIDs
/*
if( pfb & PFB_DID )
{
uint8_t did = 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 )
{
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( buffer_reader_readable(pIsodepTarget->commands.pReq) < 1 )
{
NFC_ERR("Payload too short");
return NFC_ERR_PROTOCOL;
}
wtxm = 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 (buffer_builder_writeable(&pIsodepTarget->commands.respBldr) < 5 )
{
return NFC_ERR_BUFFER_TOO_SMALL;
}
buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (5 + buffer_size(pIsodepTarget->pHist)) & 0xFF);
//T0
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
buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (1 << 7) | (0x0 << 4) | 0x0);
//TODO when supporting other bitrates
//buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0 << 7) | (0x3 << 4) | 0x3); //106, 212, 414 kbps bitrates
//TB(1)
buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (FWI << 4) | SFGI); //Specify guard-time and time between frames
//TC(1)
buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0 << 1) | 0); //DID not supported, NAD not supported
buffer_set_next(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;
}*/
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;
}
buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, pcb);
/*
if( pIsodepTarget->commands.didUsed )
{
buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, pIsodepTarget->commands.did);
}
*/
if( pDepBuf != NULL )
{
buffer_set_next(buffer_builder_buffer(&pIsodepTarget->commands.respBldr), pDepBuf);
}
else if(wtxNDeselect)
{
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
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);
}
DBG_BLOCK( buffer_dump(buffer_builder_buffer(&pIsodepTarget->commands.respBldr)); )
//Send next frame
transceiver_set_write(pIsodepTarget->pTransceiver, 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 )
{
//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");
buffer_t* pDataInitiator = transceiver_get_read(pTransceiver); //In buffer
DBG_BLOCK( buffer_dump(pDataInitiator); )
//Framing is handled by transceiver
if( (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
buffer_t dataInitiatorDup;
buffer_dup(&dataInitiatorDup, pDataInitiator);
uint8_t req = buffer_read_nu8(&dataInitiatorDup);
switch(req)
{
case RATS:
ret = command_ats_req(pIsodepTarget);
break;
default:
ret = command_dep_req(pIsodepTarget);
break;
}
if(ret)
{
NFC_ERR("Error %d", ret);
//Go back to receive mode
nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget);
return;
}
NFC_DBG("Reply");
//Reply
command_reply(pIsodepTarget, true); //Make sure we send a WTX frame if we cannot respond straight away
}

View File

@ -0,0 +1,119 @@
/*
* 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_
#ifdef __cplusplus
extern "C" {
#endif
#include "inc/nfc.h"
#include "transceiver/transceiver.h"
#include "isodep.h"
struct nfc_tech_isodep_target;
typedef struct nfc_tech_isodep_target nfc_tech_isodep_target_t;
typedef struct nfc_tech_isodep_target nfc_tech_isodep_target_t;
struct nfc_tech_isodep_target
{
nfc_tech_isodep_t isodep;
nfc_transceiver_t* pTransceiver;
struct
{
ostream_t* pReqStream;
istream_t* pResStream;
nfc_tech_isodep_cb_t reqCb;
void* pReqUserData;
nfc_tech_isodep_cb_t resCb;
void* pResUserData;
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;
buffer_builder_t respBldr;
uint8_t respBuf[32];
buffer_t* pReq;
} commands;
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,
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, 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, ostream_t* pStream, nfc_tech_isodep_cb_t cb, void* pUserData);
#ifdef __cplusplus
}
#endif
#endif /* ISODEP_TARGET_H_ */

View File

@ -0,0 +1,377 @@
/*
* 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 "inc/nfc.h"
#include "stdlib.h"
#include "acore/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
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
buffer_t null_array;
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);
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))
{
buffer_builder_t read_byte;
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);
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;
return 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, buffer_t* pWriteBuf)
{
pn512_t* pPN512 = (pn512_t*) pTransceiver;
if( pWriteBuf == NULL )
{
buffer_init(&pPN512->writeBuf, NULL, 0);
return;
}
buffer_dup(&pPN512->writeBuf, pWriteBuf);
}
buffer_t* pn512_get_read(nfc_transceiver_t* pTransceiver)
{
pn512_t* pPN512 = (pn512_t*) pTransceiver;
return 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;
scheduler_dequeue_task(&pTransceiver->scheduler, true, &pPN512->transceiver.task);
}
void pn512_close(nfc_transceiver_t* pTransceiver)
{
//pn512_t* pPN512 = (pn512_t*) pTransceiver;
(void) pTransceiver;
//TODO
return;
}
void pn512_sleep(nfc_transceiver_t* pTransceiver, bool sleep)
{
pn512_t* pPN512 = (pn512_t*) pTransceiver;
if(sleep)
{
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x30); //Receiver off + soft power down
}
else
{
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x00);
while( pn512_register_read(pPN512, PN512_REG_COMMAND) & 0x10 );
}
}
void pn512_transceiver_callback(pn512_t* pPN512, nfc_err_t ret)
{
transceiver_callback(&pPN512->transceiver, ret);
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,167 @@
/*
* 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 "transceiver/transceiver.h"
typedef struct __pn512 pn512_t;
#include "pn512_callback.h"
#include "pn512_types.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;
typedef 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
buffer_builder_t readBufBldr;
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;
};
} pn512_t;
nfc_err_t pn512_init(pn512_t* pPN512, nfc_transport_t* pTransport, nfc_scheduler_timer_t* pTimer);
nfc_transceiver_t* pn512_get_transceiver(pn512_t* pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_H_ */

View File

@ -0,0 +1,37 @@
/*
* 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_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct __pn512 pn512_t;
typedef void (*pn512_cb_t)(pn512_t* pPN512, nfc_err_t ret);
#ifdef __cplusplus
}
#endif
#endif /* PN512_CALLBACK_H_ */

View File

@ -0,0 +1,149 @@
/*
* 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 "inc/nfc.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, buffer_t* pData)
{
uint8_t fifo_space = pn512_fifo_space(pPN512); //Do not call this fn twice
size_t len = 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, buffer_builder_t* pData)
{
uint8_t fifo_len = pn512_fifo_length(pPN512); //Do not call this fn twice
size_t len = buffer_builder_writeable(pData);
len = MIN(fifo_len, len);
pn512_register_switch_page(pPN512, PN512_REG_FIFODATA);
pn512_hw_read_buffer(pPN512, PN512_REG_FIFODATA, pData, len);
}
/** \internal Clear FIFO
* Removes any bytes left in FIFO
* \param pPN512 pointer to pn512_t structure
*/
void pn512_fifo_clear(pn512_t* pPN512)
{
pn512_register_write(pPN512, PN512_REG_FIFOLEVEL, 0x80); //Flush FIFO
}
/** \internal Get space in FIFO
* \param pPN512 pointer to pn512_t structure
* \return number of bytes that can be written to FIFO
*/
size_t pn512_fifo_space(pn512_t* pPN512)
{
return PN512_FIFO_SIZE - pn512_register_read(pPN512, PN512_REG_FIFOLEVEL);
}
/** \internal Get FIFO length
* \param pPN512 pointer to pn512_t structure
* \return number of bytes that can be read from FIFO
*/
size_t pn512_fifo_length(pn512_t* pPN512)
{
return pn512_register_read(pPN512, PN512_REG_FIFOLEVEL);
}
/** \internal Execute command
* \param pPN512 pointer to pn512_t structure
* \param cmd PN512 command to execute
*/
void pn512_cmd_exec(pn512_t* pPN512, uint8_t cmd)
{
pn512_register_write(pPN512, PN512_REG_COMMAND, cmd);
}
/** \internal Wait for command completion
* \param pPN512 pointer to pn512_t structure
* \param timeout timeout in milliseconds or -1 for blocking mode
* \return NFC_OK on success or NFC_ERR_TIMEOUT on timeout
*/
nfc_err_t pn512_cmd_wait_idle(pn512_t* pPN512, int timeout)
{
(void) timeout;
while( pn512_cmd_get(pPN512) != PN512_CMD_IDLE )
{
}
return NFC_OK;
}
/** \internal Read executed command
* \param pPN512 pointer to pn512_t structure
* \return PN512 command being executed
*/
uint8_t pn512_cmd_get(pn512_t* pPN512)
{
return pn512_register_read(pPN512, PN512_REG_COMMAND) & PN512_CMD_REG_MASK;
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,78 @@
/*
* 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 "inc/nfc.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, buffer_t* pData);
void pn512_fifo_read(pn512_t* pPN512, buffer_builder_t* pData);
//Fifo clear
void pn512_fifo_clear(pn512_t* pPN512);
//Fifo bytes read
size_t pn512_fifo_space(pn512_t* pPN512);
size_t pn512_fifo_length(pn512_t* pPN512);
//Execute command
void pn512_cmd_exec(pn512_t* pPN512, uint8_t cmd);
//Wait for command completion
nfc_err_t pn512_cmd_wait_idle(pn512_t* pPN512, int timeout);
//Read executed command
uint8_t pn512_cmd_get(pn512_t* pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_CMD_H_ */

View File

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

View File

@ -0,0 +1,97 @@
/*
* 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 "inc/nfc.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, buffer_t* pData, size_t len)
{
while( len > 0 )
{
if( buffer_reader_readable(pData) == 0 )
{
return;
}
size_t cpyLen = MIN(len, buffer_reader_current_buffer_length(pData));
nfc_transport_write(((nfc_transceiver_t*)pPN512)->pTransport, addr, buffer_reader_current_buffer_pointer(pData), cpyLen);
buffer_read_n_skip(pData, cpyLen);
len -= cpyLen;
}
}
static inline void pn512_hw_read_buffer(pn512_t* pPN512, uint8_t addr, buffer_builder_t* pData, size_t len)
{
while( len > 0 )
{
if( buffer_builder_writeable(pData) == 0 )
{
return;
}
//Read payload
size_t cpyLen = MIN(len, buffer_builder_space(pData));
nfc_transport_read(((nfc_transceiver_t*)pPN512)->pTransport, addr, buffer_builder_write_position(pData), cpyLen);
buffer_builder_write_n_skip(pData, cpyLen);
len -= cpyLen;
}
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_HW_H_ */

View File

@ -0,0 +1,82 @@
/*
* 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 "inc/nfc.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, buffer_t* pWriteBuf);
buffer_t* pn512_get_read(nfc_transceiver_t* pTransceiver);
size_t pn512_get_last_byte_length(nfc_transceiver_t* pTransceiver);
void pn512_set_last_byte_length(nfc_transceiver_t* pTransceiver, size_t lastByteLength);
void pn512_set_first_byte_align(nfc_transceiver_t* pTransceiver, size_t firstByteAlign);
void pn512_abort(nfc_transceiver_t* pTransceiver);
void pn512_transceive(nfc_transceiver_t* pTransceiver);
void pn512_close(nfc_transceiver_t* pTransceiver);
void pn512_sleep(nfc_transceiver_t* pTransceiver, bool sleep);
void pn512_transceiver_callback(pn512_t* pPN512, nfc_err_t ret);
static inline void pn512_rf_callback(pn512_t* pPN512, nfc_err_t ret)
{
pPN512->rf.cb(pPN512, ret);
}
static inline void pn512_poll_callback(pn512_t* pPN512, nfc_err_t ret)
{
pPN512->poll.cb(pPN512, ret);
}
static inline void pn512_anticollision_callback(pn512_t* pPN512, nfc_err_t ret)
{
pPN512->anticollision.cb(pPN512, ret);
}
static inline void pn512_transceive_callback(pn512_t* pPN512, nfc_err_t ret)
{
pPN512->transceive.cb(pPN512, ret);
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_INTERNAL_H_ */

View File

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

View File

@ -0,0 +1,109 @@
/*
* 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 "inc/nfc.h"
#include "pn512.h"
#include "pn512_registers.h"
#define PN512_IRQ_TX (1<<6)
#define PN512_IRQ_RX (1<<5)
#define PN512_IRQ_IDLE (1<<4)
#define PN512_IRQ_HIGH_ALERT (1<<3)
#define PN512_IRQ_LOW_ALERT (1<<2)
#define PN512_IRQ_ERR (1<<1)
#define PN512_IRQ_TIMER (1<<0)
#define PN512_IRQ_SIGIN (1<<(4+8))
#define PN512_IRQ_MODE (1<<(3+8))
#define PN512_IRQ_CRC (1<<(2+8))
#define PN512_IRQ_RF_ON (1<<(1+8))
#define PN512_IRQ_RF_OFF (1<<(0+8))
#define PN512_IRQ_NONE 0x00
#define PN512_IRQ_ALL 0x1F7F
#define PN512_REG_COMIEN_MASK 0x7F
#define PN512_REG_COMIEN_VAL 0x00
#define PN512_REG_DIVIEN_MASK 0x1F
#define PN512_REG_DIVIEN_VAL 0x80
#define PN512_REG_COMIRQ_MASK 0x7F
#define PN512_REG_COMIRQ_CLEAR 0x00
#define PN512_REG_DIVIRQ_MASK 0x1F
#define PN512_REG_DIVIRQ_CLEAR 0x00
/** \internal Set IRQ enable registers
* \param pPN512 pointer to pn512_t structure
* \param irqs MSB is DIVIEN value, LSB is COMIEN value
*/
static inline void pn512_irq_set(pn512_t* pPN512, uint16_t irqs) //ORed
{
pn512_register_write(pPN512, PN512_REG_COMIEN, PN512_REG_COMIEN_VAL | (PN512_REG_COMIEN_MASK & (irqs & 0xFF)));
pn512_register_write(pPN512, PN512_REG_DIVIEN, PN512_REG_DIVIEN_VAL | (PN512_REG_DIVIEN_MASK & (irqs >> 8)));
pPN512->irqsEn = irqs;
}
/** \internal Get IRQ enable registers
* \param pPN512 pointer to pn512_t structure
* \return MSB is DIVIEN value, LSB is COMIEN value
*/
static inline uint16_t pn512_irq_enabled(pn512_t* pPN512) //ORed
{
return pPN512->irqsEn /*(pn512_register_read(pPN512, PN512_REG_COMIEN_VAL) & PN512_REG_COMIEN_MASK)
| ((pn512_register_read(pPN512, PN512_REG_DIVIEN_VAL) & PN512_REG_DIVIEN_MASK) << 8)*/;
}
/** \internal Get IRQ status registers (masked with enabled IRQ register)
* \param pPN512 pointer to pn512_t structure
* \return MSB is DIVIRQ value, LSB is COMIRQ value
*/
static inline uint16_t pn512_irq_get(pn512_t* pPN512) //ORed
{
return ((pn512_register_read(pPN512, PN512_REG_COMIRQ) & PN512_REG_COMIEN_MASK)
| ((pn512_register_read(pPN512, PN512_REG_DIVIRQ) & PN512_REG_DIVIEN_MASK) << 8)) & pPN512->irqsEn;
}
/** \internal Clear some interrupts
* \param pPN512 pointer to pn512_t structure
* \param irqs MSB is DIVIEN value, LSB is COMIEN value
*/
static inline void pn512_irq_clear(pn512_t* pPN512, uint16_t irqs)
{
pn512_register_write(pPN512, PN512_REG_COMIRQ, PN512_REG_COMIRQ_CLEAR | (PN512_REG_COMIRQ_MASK & (irqs & 0xFF)));
pn512_register_write(pPN512, PN512_REG_DIVIRQ, PN512_REG_DIVIRQ_CLEAR | (PN512_REG_DIVIRQ_MASK & (irqs >> 8)));
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_IRQ_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*
* 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 "inc/nfc.h"
void pn512_poll_setup(pn512_t* pPN512);
void pn512_poll_hw(pn512_t* pPN512, pn512_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif /* PN512_POLL_H_ */

View File

@ -0,0 +1,157 @@
/*
* 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 "inc/nfc.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;
DBG_BLOCK(
uint8_t __dbg_addr;
__dbg_addr = address; //FIXME
)
if(REGISTER_PAGE(address) != pPN512->registers.registers_page)
{
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
address=REGISTER_ADDR(address);
pn512_hw_read(pPN512, address, &data, 1);
NFC_DBG("Read [%02x] >> %02x", __dbg_addr, data);
return data;
}
void pn512_register_switch_page(pn512_t* pPN512, uint8_t address)
{
if(REGISTER_PAGE(address) != pPN512->registers.registers_page)
{
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
}
/** \internal Switch registers page
* \param pPN512 pointer to pn512_t structure
* \param page registers page
*/
void pn512_register_switch_page_intl(pn512_t* pPN512, uint8_t page)
{
uint8_t pageRegValue;
pageRegValue = (1 << 7) | page;
pn512_hw_write(pPN512, PN512_REG_PAGE, &pageRegValue, 1);
pPN512->registers.registers_page = page;
}
/**
* @}
* @}
* */

View File

@ -0,0 +1,114 @@
/*
* 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 "inc/nfc.h"
#include "pn512.h"
//Page 0 - Command and Status
#define PN512_REG_PAGE 0x00 //Selects the register page
#define PN512_REG_COMMAND 0x01 //Starts and stops command execution
#define PN512_REG_COMIEN 0x02 //Controls bits to enable and disable the passing of Interrupt Requests
#define PN512_REG_DIVIEN 0x03 //Controls bits to enable and disable the passing of Interrupt Requests
#define PN512_REG_COMIRQ 0x04 //Contains Interrupt Request bits
#define PN512_REG_DIVIRQ 0x05 //Contains Interrupt Request bits
#define PN512_REG_ERROR 0x06 //Error bits showing the error status of the last command executed
#define PN512_REG_STATUS1 0x07 //Contains status bits for communication
#define PN512_REG_STATUS2 0x08 //Contains status bits of the receiver and transmitter
#define PN512_REG_FIFODATA 0x09 //In- and output of 64 byte FIFO-buffer
#define PN512_REG_FIFOLEVEL 0x0A //Indicates the number of bytes stored in the FIFO
#define PN512_REG_WATERLEVEL 0x0B //Defines the level for FIFO under- and overflow warning
#define PN512_REG_CONTROL 0x0C //Contains miscellaneous Control Registers
#define PN512_REG_BITFRAMING 0x0D //Adjustments for bit oriented frames
#define PN512_REG_COLL 0x0E //Bit position of the first bit collision detected on the RF-interface
//Page 1 - Command
//#define PN512_REG_PAGE 0x10 //Selects the register page
#define PN512_REG_MODE 0x11 //Defines general modes for transmitting and receiving
#define PN512_REG_TXMODE 0x12 //Defines the data rate and framing during transmission
#define PN512_REG_RXMODE 0x13 //Defines the data rate and framing during receiving
#define PN512_REG_TXCONTROL 0x14 //Controls the logical behavior of the antenna driver pins TX1 and TX2
#define PN512_REG_TXAUTO 0x15 //Controls the setting of the antenna drivers
#define PN512_REG_TXSEL 0x16 //Selects the internal sources for the antenna driver
#define PN512_REG_RXSEL 0x17 //Selects internal receiver settings
#define PN512_REG_RXTHRESHOLD 0x18 //Selects thresholds for the bit decoder
#define PN512_REG_DEMOD 0x19 //Defines demodulator settings
#define PN512_REG_FELNFC1 0x1A //Defines the length of the valid range for the receive package
#define PN512_REG_FELNFC2 0x1B //Defines the length of the valid range for the receive package
#define PN512_REG_MIFNFC 0x1C //Controls the communication in ISO/IEC 14443/MIFARE and NFC target mode at 106 kbit
#define PN512_REG_MANUALRCV 0x1D //Allows manual fine tuning of the internal receiver
#define PN512_REG_TYPEB 0x1E //Configure the ISO/IEC 14443 type B
#define PN512_REG_SERIALSPEED 0x1F //Selects the speed of the serial UART interface
//Page 2 - CFG
//#define PN512_REG_PAGE 0x20 //Selects the register page
#define PN512_REG_CRCRESULT_MSB 0x21 //Shows the actual MSB and LSB values of the CRC calculation
#define PN512_REG_CRCRESULT_LSB 0x22 //Shows the actual MSB and LSB values of the CRC calculation
#define PN512_REG_GSNOFF 0x23 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation, when the driver is switched off
#define PN512_REG_MODWIDTH 0x24 //Controls the setting of the ModWidth
#define PN512_REG_TXBITPHASE 0x25 //Adjust the TX bit phase at 106 kbit
#define PN512_REG_RFCFG 0x26 //Configures the receiver gain and RF level
#define PN512_REG_GSNON 0x27 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation when the drivers are switched on
#define PN512_REG_CWGSP 0x28 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation during times of no modulation
#define PN512_REG_MODGSP 0x29 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation during modulation
#define PN512_REG_TMODE_TPRESCALERHIGH 0x2A //Defines settings for the internal timer
#define PN512_REG_TPRESCALERLOW 0x2B //Defines settings for the internal timer
#define PN512_REG_TRELOADHIGH 0x2C //Describes the 16-bit timer reload value
#define PN512_REG_TRELOADLOW 0x2D //Describes the 16-bit timer reload value
#define PN512_REG_TCOUNTERVALHIGH 0x2E //Shows the 16-bit actual timer value
#define PN512_REG_TCOUNTERVALLOW 0x2F //Shows the 16-bit actual timer value
//Page 3 - TestRegister
//#define PN512_REG_PAGE 0x30 //Selects the register page
#define PN512_REG_TESTSEL1 0x31 //General test signal configuration
#define PN512_REG_TESTSEL2 0x32 //General test signal configuration and PRBS control
#define PN512_REG_TESTPINEN 0x33 //Enables pin output driver on 8-bit parallel bus (Note: For serial interfaces only)
#define PN512_REG_TESTPINVALUE 0x34 //Defines the values for the 8-bit parallel bus when it is used as I/O bus
#define PN512_REG_TESTBUS 0x35 //Shows the status of the internal testbus
#define PN512_REG_AUTOTEST 0x36 //Controls the digital selftest
#define PN512_REG_VERSION 0x37 //Shows the version
#define PN512_REG_ANALOGTEST 0x38 //Controls the pins AUX1 and AUX2
#define PN512_REG_TESTDAC1 0x39 //Defines the test value for the TestDAC1
#define PN512_REG_TESTDAC2 0x3A //Defines the test value for the TestDAC2
#define PN512_REG_TESTADC 0x3B //Shows the actual value of ADC I and Q
void pn512_registers_init(pn512_t* pPN512);
void pn512_registers_reset(pn512_t* pPN512);
void pn512_register_write(pn512_t* pPN512, uint8_t address, uint8_t data);
uint8_t pn512_register_read(pn512_t* pPN512, uint8_t address);
void pn512_register_switch_page(pn512_t* pPN512, uint8_t address);
#ifdef __cplusplus
}
#endif
#endif /* PN512_REGISTERS_H_ */

View File

@ -0,0 +1,343 @@
/*
* 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 "inc/nfc.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);
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);
scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}

View File

@ -0,0 +1,56 @@
/*
* 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 "inc/nfc.h"
#include "pn512_callback.h"
#include "pn512.h"
#include "pn512_rf.h"
typedef struct __pn512 pn512_t;
nfc_err_t pn512_framing_set(pn512_t* pPN512, nfc_framing_t framing);
nfc_err_t pn512_framing_crc_set(pn512_t* pPN512, bool out, bool in);
nfc_err_t pn512_framing_rx_multiple_enable(pn512_t* pPN512);
#define PN512_FRAMING_IS_TARGET( framing ) ((framing) <= nfc_framing_target_f_424)
void pn512_rf_field_switch_off(pn512_t* pPN512);
void pn512_rf_field_nfcip1_rf_collision_avoidance(pn512_t* pPN512, pn512_cb_t cb);
void pn512_rf_field_wait_for_external(pn512_t* pPN512, int timeout, pn512_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif /* PN512_RF_H_ */

View File

@ -0,0 +1,77 @@
/*
* 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 "inc/nfc.h"
#include "pn512_timer.h"
#include "pn512_registers.h"
void pn512_timer_config(pn512_t* pPN512, bool autostart, uint16_t prescaler, uint16_t countdown_value)
{
pn512_timer_stop(pPN512); //just in case...
pn512_register_write(pPN512, PN512_REG_TRELOADLOW, countdown_value & 0xFF);
pn512_register_write(pPN512, PN512_REG_TRELOADHIGH, (countdown_value >> 8) & 0xFF);
pn512_register_write(pPN512, PN512_REG_TPRESCALERLOW, prescaler & 0xFF);
pn512_register_write(pPN512, PN512_REG_TMODE_TPRESCALERHIGH, (autostart?0x80:0x00) | ((prescaler>>8) & 0x0F) );
}
void pn512_timer_start(pn512_t* pPN512)
{
//The control register also contains the initiator bit that we must set correctly
switch(pPN512->framing)
{
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x50);
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
default:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x40);
break;
}
}
void pn512_timer_stop(pn512_t* pPN512)
{
//The control register also contains the initiator bit that we must set correctly
switch(pPN512->framing)
{
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x90);
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
default:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x80);
break;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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 "inc/nfc.h"
typedef struct __pn512 pn512_t;
void pn512_timer_config(pn512_t* pPN512, bool autostart, uint16_t prescaler, uint16_t countdown_value);
void pn512_timer_start(pn512_t* pPN512);
void pn512_timer_stop(pn512_t* pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_TIMER_H_ */

View File

@ -0,0 +1,495 @@
/*
* 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 "inc/nfc.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( buffer_reader_readable(&pPN512->writeBuf) > 0 )
{
//Fill FIFO
pn512_fifo_write(pPN512, &pPN512->writeBuf);
if (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);
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) && (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
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);
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
{
DBG_BLOCK(
//Empty FIFO into buffer
pn512_fifo_read(pPN512, &pPN512->readBufBldr);
NFC_DBG("Received");
buffer_dump( 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( (buffer_builder_writeable(&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:");
DBG_BLOCK( buffer_dump( 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);
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:");
DBG_BLOCK( buffer_dump(&pPN512->writeBuf); )
//Transmit a frame to remote target/initiator
irqs_en = PN512_IRQ_TX | PN512_IRQ_IDLE;
if( PN512_FRAMING_IS_TARGET(pPN512->framing) )
{
irqs_en |= PN512_IRQ_RF_OFF;
}
pn512_irq_set(pPN512, irqs_en);
pn512_transceive_hw_tx_iteration(pPN512, true);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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 "pn512.h"
void pn512_transceive_hw(pn512_t* pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb);
void pn512_transceive_hw_tx_task(uint32_t events, void* pUserData);
void pn512_transceive_hw_tx_iteration(pn512_t* pPN512, bool start);
void pn512_transceive_hw_rx_start(pn512_t* pPN512);
void pn512_transceive_hw_rx_task(uint32_t events, void* pUserData);
#ifdef __cplusplus
}
#endif
#endif /* PN512_TRANSCEIVE_H_ */

View File

@ -0,0 +1,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_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
typedef struct __pn512_registers
{
int8_t registers_page;
} pn512_registers_t;
#ifdef __cplusplus
}
#endif
#endif /* TRANSCEIVER_PN512_PN512_TYPES_H_ */

View File

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

View File

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

View File

@ -0,0 +1,280 @@
/*
* 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 "inc/nfc.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"
typedef enum __nfc_framing nfc_framing_t;
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 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;
} nfc_tech_t;
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, buffer_t* pWriteBuf); //Set write buffer
typedef 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, buffer_t* pWriteBuf)
{
pTransceiver->fn->set_write(pTransceiver, pWriteBuf);
}
static inline buffer_t* transceiver_get_read(nfc_transceiver_t* pTransceiver)
{
return pTransceiver->fn->get_read(pTransceiver);
}
static inline size_t transceiver_get_last_byte_length(nfc_transceiver_t* pTransceiver)
{
return pTransceiver->fn->get_last_byte_length(pTransceiver);
}
static inline void transceiver_set_last_byte_length(nfc_transceiver_t* pTransceiver, size_t lastByteLength)
{
pTransceiver->fn->set_last_byte_length(pTransceiver, lastByteLength);
}
static inline void transceiver_set_first_byte_align(nfc_transceiver_t* pTransceiver, size_t firstByteAlign)
{
pTransceiver->fn->set_first_byte_align(pTransceiver, firstByteAlign);
}
static inline void nfc_transceiver_transceive(nfc_transceiver_t* pTransceiver, transceiver_cb_t cb, void* pUserData)
{
pTransceiver->cb = cb;
pTransceiver->pUserData = pUserData;
pTransceiver->fn->transceive(pTransceiver);
}
static inline void transceiver_abort(nfc_transceiver_t* pTransceiver)
{
pTransceiver->fn->abort(pTransceiver);
}
static inline void transceiver_close(nfc_transceiver_t* pTransceiver)
{
pTransceiver->fn->close(pTransceiver);
}
static inline bool transceiver_is_initiator_mode(nfc_transceiver_t* pTransceiver)
{
return pTransceiver->initiator_ntarget;
}
static inline nfc_tech_t transceiver_get_active_techs(nfc_transceiver_t* pTransceiver)
{
return pTransceiver->active_tech;
}
static inline nfc_scheduler_t* transceiver_get_scheduler(nfc_transceiver_t* pTransceiver)
{
return &pTransceiver->scheduler;
}
static inline const nfc_info_t* transceiver_get_remote_target_info(nfc_transceiver_t* pTransceiver, size_t number)
{
if( number > pTransceiver->remote_targets_count )
{
return NULL;
}
return &pTransceiver->remote_targets[number];
}
static inline size_t transceiver_get_remote_targets_count(nfc_transceiver_t* pTransceiver)
{
return pTransceiver->remote_targets_count;
}
static inline void transceiver_sleep(nfc_transceiver_t* pTransceiver, bool sleep)
{
pTransceiver->fn->sleep(pTransceiver, sleep);
}
#ifdef __cplusplus
}
#endif
#endif /* TRANSCEIVER_H_ */

View File

@ -0,0 +1,41 @@
/*
* 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 "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_ */