mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Add NFC Stack
							parent
							
								
									5691a663b4
								
							
						
					
					
						commit
						cd7f518596
					
				| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2017, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef ACORE_MACROS_H_
 | 
			
		||||
#define ACORE_MACROS_H_
 | 
			
		||||
 | 
			
		||||
//Macros
 | 
			
		||||
#ifndef MAX
 | 
			
		||||
#define MAX(a,b) (((a)>(b))?(a):(b))
 | 
			
		||||
#define MIN(a,b) (((a)<(b))?(a):(b))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * \file nfc_errors.h
 | 
			
		||||
 * \copyright Copyright (c) ARM Ltd 2013
 | 
			
		||||
 * \author Donatien Garnier
 | 
			
		||||
 * \details NFC Error codes
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** \addtogroup Core
 | 
			
		||||
 *  @{
 | 
			
		||||
 *  \name Error codes
 | 
			
		||||
 *  @{
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NFC_ERRORS_H_
 | 
			
		||||
#define NFC_ERRORS_H_
 | 
			
		||||
 | 
			
		||||
#define NFC_OK                    0   ///< No error
 | 
			
		||||
 | 
			
		||||
#define NFC_ERR_UNKNOWN           1   ///< Unknown error
 | 
			
		||||
#define NFC_ERR_LENGTH            2   ///< Length of parameter is wrong
 | 
			
		||||
#define NFC_ERR_NOT_FOUND         3   ///< Could not find item
 | 
			
		||||
#define NFC_ERR_UNSUPPORTED       4   ///< This action is not supported
 | 
			
		||||
#define NFC_ERR_PARAMS            5   ///< These parameters are not correct
 | 
			
		||||
#define NFC_ERR_BUFFER_TOO_SMALL  6   ///< The buffer is too small to store all data (buffer overflow)
 | 
			
		||||
#define NFC_ERR_TIMEOUT           7   ///< Timeout
 | 
			
		||||
#define NFC_ERR_CRC               8   ///< Checksum does not match
 | 
			
		||||
#define NFC_ERR_NOPEER            9   ///< No target/initiator in vicinity
 | 
			
		||||
#define NFC_ERR_PARITY            10  ///< Parity error
 | 
			
		||||
#define NFC_ERR_FIELD             11  ///< No RF field detected (or RF field lost)
 | 
			
		||||
#define NFC_ERR_COLLISION         12  ///< Collision detected
 | 
			
		||||
#define NFC_ERR_WRONG_COMM        13  ///< Communication error
 | 
			
		||||
#define NFC_ERR_PROTOCOL          14  ///< Protocol is not conformant
 | 
			
		||||
#define NFC_ERR_BUSY              15  ///< Resource is busy
 | 
			
		||||
#define NFC_ERR_CONTROLLER        16  ///< Controller failure
 | 
			
		||||
#define NFC_ERR_HALTED            17  ///< Target has been halted
 | 
			
		||||
#define NFC_ERR_MAC               18  ///< MAC does not match
 | 
			
		||||
#define NFC_ERR_UNDERFLOW         19  ///< Could not send data in time
 | 
			
		||||
#define NFC_ERR_DISCONNECTED      20  ///< Link has disconnected
 | 
			
		||||
#define NFC_ERR_ABORTED           21  ///< Command was aborted
 | 
			
		||||
 | 
			
		||||
/** Type for NFC errors
 | 
			
		||||
 */
 | 
			
		||||
typedef int nfc_err_t;
 | 
			
		||||
 | 
			
		||||
#endif /* NFC_ERRORS_H_ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,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
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * \file iso7816_app.c
 | 
			
		||||
 * \copyright Copyright (c) ARM Ltd 2015-2018
 | 
			
		||||
 * \author Donatien Garnier
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "iso7816_app.h"
 | 
			
		||||
 | 
			
		||||
void nfc_tech_iso7816_app_init(nfc_tech_iso7816_app_t* pIso7816App,
 | 
			
		||||
    nfc_tech_iso7816_t* pIso7816,
 | 
			
		||||
    const uint8_t* aid, size_t aidSize,
 | 
			
		||||
    nfc_tech_iso7816_app_cb selected,
 | 
			
		||||
    nfc_tech_iso7816_app_cb deselected,
 | 
			
		||||
    nfc_tech_iso7816_app_cb apdu,
 | 
			
		||||
    void* pUserData
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
  pIso7816App->pIso7816 = pIso7816;
 | 
			
		||||
  pIso7816App->aid = aid;
 | 
			
		||||
  pIso7816App->aidSize = aidSize;
 | 
			
		||||
  pIso7816App->selected = selected;
 | 
			
		||||
  pIso7816App->deselected = deselected;
 | 
			
		||||
  pIso7816App->apdu = apdu;
 | 
			
		||||
  pIso7816App->pUserData = pUserData;
 | 
			
		||||
  pIso7816App->pNext = NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * \file iso7816_defs.h
 | 
			
		||||
 * \copyright Copyright (c) ARM Ltd 2013
 | 
			
		||||
 * \author Donatien Garnier
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef ISO7816_DEFS_H_
 | 
			
		||||
#define ISO7816_DEFS_H_
 | 
			
		||||
 | 
			
		||||
#define ISO7816_INS_SELECT          0xA4
 | 
			
		||||
#define ISO7816_INS_READ_BINARY     0xB0
 | 
			
		||||
#define ISO7816_INS_UPDATE_BINARY   0xD6
 | 
			
		||||
#define ISO7816_INS_ENVELOPE        0xC2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define ISO7816_SW_OK               0x9000
 | 
			
		||||
#define ISO7816_SW_INVALID_CLASS    0x6E00
 | 
			
		||||
#define ISO7816_SW_INVALID_INS      0x6D00
 | 
			
		||||
#define ISO7816_SW_NOT_FOUND        0x6A82
 | 
			
		||||
#define ISO7816_SW_WRONG_LENGTH     0x6700
 | 
			
		||||
 | 
			
		||||
#define ISO7816_PUT_SW(buf, sw) do{ *(buf)=(sw>>8) & 0xFF; *(buf+1)=(sw>>0) & 0xFF; } while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* ISO7816_DEFS_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 *  @{
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
											
										
									
								
							| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 * @}
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
		Loading…
	
		Reference in New Issue