+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-#include <stdio.h>
-#include <string.h>
-
-#include "chb.h"
-#include "chb_drvr.h"
-#include "chb_buf.h"
-
-static chb_pcb_t pcb;
-// these are for the duplicate checking and rejection
-static U8 prev_seq = 0xFF;
-static U16 prev_src_addr = 0xFFFE;
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_init()
-{
- memset(&pcb, 0, sizeof(chb_pcb_t));
- pcb.src_addr = chb_get_short_addr();
- chb_drvr_init();
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-chb_pcb_t *chb_get_pcb()
-{
- return &pcb;
-}
-
-/**************************************************************************/
-/*!
- Requires the dest addr, location to store data, and len of payload.
- Returns the length of the hdr.
-*/
-/**************************************************************************/
-static U8 chb_gen_hdr(U8 *hdr, U16 addr, U8 len)
-{
- U8 *hdr_ptr = hdr;
-
- // calc frame size and put in 0 position of array
- // frame size = hdr sz + payload len + fcs len
- *hdr_ptr++ = CHB_HDR_SZ + len + CHB_FCS_LEN;
-
- // use default fcf byte 0 val but test for ack request. we won't request
- // ack if broadcast. all other cases we will.
- *hdr_ptr++ = CHB_FCF_BYTE_0 | ((addr != 0xFFFF) << CHB_ACK_REQ_POS);
- *hdr_ptr++ = CHB_FCF_BYTE_1;
-
- *hdr_ptr++ = pcb.seq++;
-
- // fill out dest pan ID, dest addr, src addr
- *(U16 *)hdr_ptr = CFG_CHIBI_PANID;
- hdr_ptr += sizeof(U16);
- *(U16 *)hdr_ptr = addr;
- hdr_ptr += sizeof(U16);
- *(U16 *)hdr_ptr = pcb.src_addr;
- hdr_ptr += sizeof(U16);
-
- // return the len of the header
- return hdr_ptr - hdr;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U8 chb_write(U16 addr, U8 *data, U8 len)
-{
- // U8 status, frm_len, hdr_len, hdr[CHB_HDR_SZ + 1];
- U8 status, frm_len, hdr[CHB_HDR_SZ + 1];
-
- while (len > 0)
- {
- // calculate which frame len to use. if greater than max payload, split
- // up operation.
- frm_len = (len > CHB_MAX_PAYLOAD) ? CHB_MAX_PAYLOAD : len;
-
- // gen frame header
- // hdr_len = chb_gen_hdr(hdr, addr, frm_len);
- chb_gen_hdr(hdr, addr, frm_len);
-
- // send data to chip
- status = chb_tx(hdr, data, frm_len);
-
- if (status != CHB_SUCCESS)
- {
- switch (status)
- {
- case RADIO_SUCCESS:
- // fall through
- case CHB_SUCCESS_DATA_PENDING:
- pcb.txd_success++;
- break;
-
- case CHB_NO_ACK:
- pcb.txd_noack++;
- break;
-
- case CHB_CHANNEL_ACCESS_FAILURE:
- pcb.txd_channel_fail++;
- break;
-
- default:
- break;
- }
- return status;
- }
-
- // adjust len and restart
- len = len - frm_len;
- }
- return CHB_SUCCESS;
-}
-
-/**************************************************************************/
-/*!
- Read data from the buffer. Need to pass in a buffer of at leasts max frame
- size and two 16-bit containers for the src and dest addresses.
-
- The read function will automatically populate the addresses and the data with
- the frm payload. It will then return the len of the payload.
-*/
-/**************************************************************************/
-U8 chb_read(chb_rx_data_t *rx)
-{
- U8 i, len, seq, *data_ptr;
-
- data_ptr = rx->data;
-
- // first byte is always len. check it to make sure
- // we have a valid len byte.
- if ((len = chb_buf_read()) > CHB_MAX_FRAME_LENGTH)
- {
- return 0;
- }
- *data_ptr++ = len;
-
- // load the rest of the data into buffer
- for (i=0; i<len; i++)
- {
- *data_ptr++ = chb_buf_read();
- }
-
- // we're using the buffer that's fed in as an argument as a temp
- // buffer as well to save resources.
- // we'll use it as temp storage to parse the frame. then move the frame
- // down so that only the payload will be in the buffer.
-
- // extract the sequence number
- data_ptr = rx->data + 3; // location of sequence number
- seq = *data_ptr;
-
- // parse the buffer and extract the dest and src addresses
- data_ptr = rx->data + 6; // location of dest addr
- rx->dest_addr = *(U16 *)data_ptr;
- data_ptr += sizeof(U16);
- rx->src_addr = *(U16 *)data_ptr;
- data_ptr += sizeof(U16);
-
- // if the data in the rx buf is 0, then clear the rx_flag. otherwise, keep it raised
- if (!chb_buf_get_len())
- {
- pcb.data_rcv = false;
- }
-
-#if (CFG_CHIBI_PROMISCUOUS == 1)
- // if we're in promiscuous mode, we don't want to do any duplicate rejection and we don't want to move the payload
- // to the front of the buffer. We want to capture the full frame so just keep the frame intact and return the length.
- return len;
-#else
- // duplicate frame check (dupe check). we want to remove frames that have been already been received since they
- // are just retries.
- // note: this dupe check only removes duplicate frames from the previous transfer. if another frame from a different
- // node comes in between the dupes, then the dupe will show up as a received frame.
- if ((seq == prev_seq) && (rx->src_addr == prev_src_addr))
- {
- // this is a duplicate frame from a retry. the remote node thinks we didn't receive
- // it properly. discard.
- return 0;
- }
- else
- {
- prev_seq = seq;
- prev_src_addr = rx->src_addr;
- }
-
- // move the payload down to the beginning of the data buffer
- memmove(rx->data, data_ptr, len - CHB_HDR_SZ);
- // finally, return the len of the payload
- return len - CHB_HDR_SZ - CHB_FCS_LEN;
-#endif
-}
-
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-#ifndef CHIBI_H
-#define CHIBI_H
-
-#include "types.h"
-
-#define CHB_HDR_SZ 9 // FCF + seq + pan_id + dest_addr + src_addr (2 + 1 + 2 + 2 + 2)
-#define CHB_FCS_LEN 2
-#define CHB_MAX_PAYLOAD 100
-
-
-// frame_type = data
-// security enabled = false
-// frame pending = false
-// ack request = false
-// pan ID compression = true
-#define CHB_FCF_BYTE_0 0x41
-
-// dest addr = 16-bit
-// frame version = 802.15.4 (not 2003)
-// src addr = 16-bit
-#define CHB_FCF_BYTE_1 0x98
-
-#define CHB_ACK_REQ_POS 5
-
-enum
-{
- CHB_SUCCESS = 0,
- CHB_SUCCESS_DATA_PENDING = 1,
- CHB_CHANNEL_ACCESS_FAILURE = 3,
- CHB_NO_ACK = 5,
- CHB_INVALID = 7
-};
-
-// Chibi Protocol control block
-typedef struct
-{
- U16 src_addr;
- U8 seq;
- volatile bool data_rcv;
- volatile bool tx_end;
-
- // stats
- U16 rcvd_xfers;
- U16 txd_success;
- U16 txd_noack;
- U16 txd_channel_fail;
- U16 overflow;
- U16 underrun;
- U8 battlow;
- U8 ed;
- U8 crc;
-} chb_pcb_t;
-
-typedef struct
-{
- U8 len;
- U16 src_addr;
- U16 dest_addr;
- U8 data[CHB_MAX_PAYLOAD];
-} chb_rx_data_t;
-
-void chb_init();
-chb_pcb_t *chb_get_pcb();
-U8 chb_write(U16 addr, U8 *data, U8 len);
-U8 chb_read(chb_rx_data_t *rx);
-
-#endif
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-#include <stdio.h>
-#include "chb_buf.h"
-#include "projectconfig.h"
-
-static U8 chb_buf[CFG_CHIBI_BUFFERSIZE];
-static volatile U32 rd_ptr, wr_ptr;
-static volatile U32 len;
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_buf_init()
-{
- rd_ptr = 0;
- wr_ptr = 0;
- len = 0;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_buf_write(U8 data)
-{
- chb_buf[wr_ptr] = data;
- wr_ptr = (wr_ptr + 1) % CFG_CHIBI_BUFFERSIZE;
- len++;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U8 chb_buf_read()
-{
- U8 data;
-
- data = chb_buf[rd_ptr];
- rd_ptr = (rd_ptr + 1) % CFG_CHIBI_BUFFERSIZE;
- len--;
- return data;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U32 chb_buf_get_len()
-{
- return len;
-}
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-#ifndef CHB_BUF_H
-#define CHB_BUF_H
-
-#include "types.h"
-
-void chb_buf_init();
-void chb_buf_write(U8 data);
-U8 chb_buf_read();
-U32 chb_buf_get_len();
-
-#endif
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-#include <stdio.h>
-#include "chb.h"
-#include "chb_drvr.h"
-#include "chb_buf.h"
-#include "chb_spi.h"
-#include "chb_eeprom.h"
-
-#include "core/systick/systick.h"
-#include "core/timer16/timer16.h"
-
-// store string messages in flash rather than RAM
-const char chb_err_overflow[] = "BUFFER FULL. TOSSING INCOMING DATA\r\n";
-const char chb_err_init[] = "RADIO NOT INITIALIZED PROPERLY\r\n";
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-static U8 chb_get_state()
-{
- return chb_reg_read(TRX_STATUS) & 0x1f;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-static U8 chb_get_status()
-{
- return chb_reg_read(TRX_STATE) >> CHB_TRAC_STATUS_POS;
-}
-
-/**************************************************************************/
-/*!
- Cause a blocking delay for x microseconds
-*/
-/**************************************************************************/
-static void chb_delay_us(U16 usec)
-{
- // Determine maximum delay using a 16 bit timer
- // ToDo: Move this to a macro or fixed value!
- uint32_t maxus = 0xFFFF / (CFG_CPU_CCLK / 1000000);
-
- // Check if delay can be done in one operation
- if (usec <= maxus)
- {
- timer16DelayUS(0, usec);
- return;
- }
-
- // Split delay into several steps (to stay within limit of 16-bit timer)
- do
- {
- if (usec >= maxus)
- {
- timer16DelayUS(0, maxus);
- usec -= maxus;
- }
- else
- {
- timer16DelayUS(0, usec);
- usec = 0;
- }
- } while (usec > 0);
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_reset()
-{
- CHB_RST_DISABLE();
- CHB_SLPTR_DISABLE();
-
- // wait a bit while transceiver wakes up
- chb_delay_us(TIME_P_ON_TO_CLKM_AVAIL);
-
- // reset the device
- CHB_RST_ENABLE();
- chb_delay_us(TIME_RST_PULSE_WIDTH);
- CHB_RST_DISABLE();
-
- // check that we have the part number that we're expecting
- while (1)
- {
- // if you're stuck in this loop, that means that you're not reading
- // the version and part number register correctly. possible that version number
- // changes. if so, update version num in header file
- if ((chb_reg_read(VERSION_NUM) == CHB_AT86RF212_VER_NUM) && (chb_reg_read(PART_NUM) == CHB_AT86RF212_PART_NUM))
- {
- break;
- }
- }
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U8 chb_reg_read(U8 addr)
-{
- U8 val = 0;
-
- /* Add the register read command to the register address. */
- addr |= 0x80;
-
- CHB_ENTER_CRIT();
- CHB_SPI_ENABLE();
-
- /*Send Register address and read register content.*/
- val = chb_xfer_byte(addr);
- val = chb_xfer_byte(val);
-
- CHB_SPI_DISABLE();
- CHB_LEAVE_CRIT();
-
- return val;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U16 chb_reg_read16(U8 addr)
-{
- U8 i;
- U16 val = 0;
-
- for (i=0; i<2; i++)
- {
- addr |= chb_reg_read(addr + i) << (8 * i);
- }
- return val;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_reg_write(U8 addr, U8 val)
-{
- // U8 dummy;
-
- /* Add the Register Write command to the address. */
- addr |= 0xC0;
-
- CHB_ENTER_CRIT();
- CHB_SPI_ENABLE();
-
- /*Send Register address and write register content.*/
- // dummy = chb_xfer_byte(addr);
- // dummy = chb_xfer_byte(val);
- chb_xfer_byte(addr);
- chb_xfer_byte(val);
-
- CHB_SPI_DISABLE();
- CHB_LEAVE_CRIT();
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_reg_write16(U8 addr, U16 val)
-{
- U8 i;
-
- for (i=0; i<2; i++)
- {
- chb_reg_write(addr + i, val >> (8 * i));
- }
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_reg_write64(U8 addr, U8 *val)
-{
- U8 i;
-
- for (i=0; i<8; i++)
- {
- chb_reg_write(addr + i, *(val + i));
- }
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_reg_read_mod_write(U8 addr, U8 val, U8 mask)
-{
- U8 tmp;
-
- tmp = chb_reg_read(addr);
- val &= mask; // mask off stray bits from val
- tmp &= ~mask; // mask off bits in reg val
- tmp |= val; // copy val into reg val
- chb_reg_write(addr, tmp); // write back to reg
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_frame_write(U8 *hdr, U8 hdr_len, U8 *data, U8 data_len)
-{
- //U8 i, dummy;
- U8 i;
-
- // dont allow transmission longer than max frame size
- if ((hdr_len + data_len) > 127)
- {
- return;
- }
-
- // initiate spi transaction
- CHB_ENTER_CRIT();
- CHB_SPI_ENABLE();
-
- // send fifo write command
- // dummy = chb_xfer_byte(CHB_SPI_CMD_FW);
- chb_xfer_byte(CHB_SPI_CMD_FW);
-
- // write hdr contents to fifo
- for (i=0; i<hdr_len; i++)
- {
- // dummy = chb_xfer_byte(*hdr++);
- chb_xfer_byte(*hdr++);
- }
-
- // write data contents to fifo
- for (i=0; i<data_len; i++)
- {
- // dummy = chb_xfer_byte(*data++);
- chb_xfer_byte(*data++);
- }
-
- // terminate spi transaction
- CHB_SPI_DISABLE();
- CHB_LEAVE_CRIT();
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-static void chb_frame_read()
-{
- U8 i, len, data;
-
- // CHB_ENTER_CRIT();
- CHB_SPI_ENABLE();
-
- /*Send frame read command and read the length.*/
- chb_xfer_byte(CHB_SPI_CMD_FR);
- len = chb_xfer_byte(0);
-
- /*Check for correct frame length.*/
- if ((len >= CHB_MIN_FRAME_LENGTH) && (len <= CHB_MAX_FRAME_LENGTH))
- {
- // check to see if there is room to write the frame in the buffer. if not, then drop it
- if (len < (CFG_CHIBI_BUFFERSIZE - chb_buf_get_len()))
- {
- chb_buf_write(len);
-
- for (i=0; i<len; i++)
- {
- data = chb_xfer_byte(0);
- chb_buf_write(data);
- }
- }
- else
- {
- // we've overflowed the buffer. toss the data and do some housekeeping
- chb_pcb_t *pcb = chb_get_pcb();
-
- // read out the data and throw it away
- for (i=0; i<len; i++)
- {
- data = chb_xfer_byte(0);
- }
-
- // Increment the overflow stat
- pcb->overflow++;
-
- // print the error message
- printf(chb_err_overflow);
- }
- }
-
- CHB_SPI_DISABLE();
- CHB_LEAVE_CRIT();
-}
-
-/**************************************************************************/
-/*!
- Read directly from the SRAM on the radio. This is only used for debugging
- purposes.
-*/
-/**************************************************************************/
-#ifdef CHB_DEBUG
-void chb_sram_read(U8 addr, U8 len, U8 *data)
-{
- U8 i, dummy;
-
- CHB_ENTER_CRIT();
- CHB_SPI_ENABLE();
-
- /*Send SRAM read command.*/
- dummy = chb_xfer_byte(CHB_SPI_CMD_SR);
-
- /*Send address where to start reading.*/
- dummy = chb_xfer_byte(addr);
-
- for (i=0; i<len; i++)
- {
- *data++ = chb_xfer_byte(0);
- }
-
- CHB_SPI_DISABLE();
- CHB_LEAVE_CRIT();
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_sram_write(U8 addr, U8 len, U8 *data)
-{
- U8 i, dummy;
-
- CHB_ENTER_CRIT();
- CHB_SPI_ENABLE();
-
- /*Send SRAM write command.*/
- dummy = chb_xfer_byte(CHB_SPI_CMD_SW);
-
- /*Send address where to start writing to.*/
- dummy = chb_xfer_byte(addr);
-
- for (i=0; i<len; i++)
- {
- dummy = chb_xfer_byte(*data++);
- }
-
- CHB_SPI_DISABLE();
- CHB_LEAVE_CRIT();
-}
-#endif
-
-/**************************************************************************/
-/*!
- Set the channel mode, BPSK, OQPSK, etc...
-*/
-/**************************************************************************/
-void chb_set_mode(U8 mode)
-{
- switch (mode)
- {
- case OQPSK_868MHZ:
- chb_reg_read_mod_write(TRX_CTRL_2, 0x08, 0x3f); // 802.15.4-2006, channel page 2, channel 0 (868 MHz, Europe)
- chb_reg_read_mod_write(RF_CTRL_0, CHB_OQPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
- break;
- case OQPSK_915MHZ:
- chb_reg_read_mod_write(TRX_CTRL_2, 0x0c, 0x3f); // 802.15.4-2006, channel page 2, channels 1-10 (915 MHz, US)
- chb_reg_read_mod_write(RF_CTRL_0, CHB_OQPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
- break;
- case OQPSK_780MHZ:
- chb_reg_read_mod_write(TRX_CTRL_2, 0x1c, 0x3f); // 802.15.4-2006, channel page 5, channel 0-3 (780 MHz, China)
- chb_reg_read_mod_write(RF_CTRL_0, CHB_OQPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
- break;
- case BPSK40_915MHZ:
- chb_reg_read_mod_write(TRX_CTRL_2, 0x00, 0x3f); // 802.15.4-2006, BPSK, 40 kbps
- chb_reg_read_mod_write(RF_CTRL_0, CHB_BPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
- break;
- case BPSK20_868MHZ:
- chb_reg_read_mod_write(TRX_CTRL_2, 0x00, 0x3f); // 802.15.4-2006, BPSK, 20 kbps
- chb_reg_read_mod_write(RF_CTRL_0, CHB_BPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
- break;
- }
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U8 chb_set_channel(U8 channel)
-{
- U8 state;
-
-#if (CHB_CHINA == 1)
-
- // this if for China only which uses a 780 MHz frequency band
- if ((chb_reg_read(TRX_CTRL2) & 0x3f) != 0x1c)
- {
- chb_reg_read_mod_write(TRX_CTRL2, 0x1c, 0x3f);
- }
-
- if (channel > 3)
- {
- channel = 0;
- }
-
- channel = (channel << 1) + 11;
-
- chb_reg_read_mod_write(CC_CTRL_1, 0x4, 0x7); // set 769 MHz base frequency for China
- chb_reg_write(CC_CTRL_0, channel); // set the center frequency for the channel
-
-#else
- //if (channel == 0)
- //{
- // // Channel 0 is for European use only. make sure we are using channel page 2,
- // // channel 0 settings for 100 kbps
- // if ((chb_reg_read(TRX_CTRL_2) & 0x3f) != 0x08)
- // {
- // chb_reg_read_mod_write(TRX_CTRL_2, 0x08, 0x3f);
- // }
- //}
- //else if (channel > 10)
- //{
- // // if the channel is out of bounds for page 2, then default to channel 1 and
- // // assume we're on the US frequency of 915 MHz
- // channel = 1;
- // if ((chb_reg_read(TRX_CTRL_2) & 0x3f) != 0x0c)
- // {
- // chb_reg_read_mod_write(TRX_CTRL_2, 0x0c, 0x3f);
- // }
- //}
- //else
- //{
- // // Channels 1-10 are for US frequencies of 915 MHz
- // if ((chb_reg_read(TRX_CTRL_2) & 0x3f) != 0x0c)
- // {
- // chb_reg_read_mod_write(TRX_CTRL_2, 0x0c, 0x3f);
- // }
- //}
-
- chb_reg_read_mod_write(PHY_CC_CCA, channel, 0x1f);
-#endif
-
- // add a delay to allow the PLL to lock if in active mode.
- state = chb_get_state();
- if ((state == RX_ON) || (state == PLL_ON))
- {
- chb_delay_us(TIME_PLL_LOCK_TIME);
- }
-
- return ((chb_reg_read(PHY_CC_CCA) & 0x1f) == channel) ? RADIO_SUCCESS : RADIO_TIMED_OUT;
-}
-
-/**************************************************************************/
-/*!
- Set the power level
-*/
-/**************************************************************************/
-void chb_set_pwr(U8 val)
-{
- chb_reg_write(PHY_TX_PWR, val);
-}
-
-/**************************************************************************/
-/*!
- Set the TX/RX state machine state. Some manual manipulation is required
- for certain operations. Check the datasheet for more details on the state
- machine and manipulations.
-*/
-/**************************************************************************/
-U8 chb_set_state(U8 state)
-{
- U8 curr_state, delay;
-
- // if we're sleeping then don't allow transition
- if (gpioGetValue(CHB_SLPTRPORT, CHB_SLPTRPIN))
- {
- return RADIO_WRONG_STATE;
- }
-
- // if we're in a transition state, wait for the state to become stable
- curr_state = chb_get_state();
- if ((curr_state == BUSY_TX_ARET) || (curr_state == BUSY_RX_AACK) || (curr_state == BUSY_RX) || (curr_state == BUSY_TX))
- {
- while (chb_get_state() == curr_state);
- }
-
- // At this point it is clear that the requested new_state is:
- // TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON or TX_ARET_ON.
- // we need to handle some special cases before we transition to the new state
- switch (state)
- {
- case TRX_OFF:
- /* Go to TRX_OFF from any state. */
- CHB_SLPTR_DISABLE();
- chb_reg_read_mod_write(TRX_STATE, CMD_FORCE_TRX_OFF, 0x1f);
- chb_delay_us(TIME_ALL_STATES_TRX_OFF);
- break;
-
- case TX_ARET_ON:
- if (curr_state == RX_AACK_ON)
- {
- /* First do intermediate state transition to PLL_ON, then to TX_ARET_ON. */
- chb_reg_read_mod_write(TRX_STATE, CMD_PLL_ON, 0x1f);
- chb_delay_us(TIME_RX_ON_PLL_ON);
- }
- break;
-
- case RX_AACK_ON:
- if (curr_state == TX_ARET_ON)
- {
- /* First do intermediate state transition to RX_ON, then to RX_AACK_ON. */
- chb_reg_read_mod_write(TRX_STATE, CMD_PLL_ON, 0x1f);
- chb_delay_us(TIME_RX_ON_PLL_ON);
- }
- break;
- }
-
- /* Now we're okay to transition to any new state. */
- chb_reg_read_mod_write(TRX_STATE, state, 0x1f);
-
- /* When the PLL is active most states can be reached in 1us. However, from */
- /* TRX_OFF the PLL needs time to activate. */
- delay = (curr_state == TRX_OFF) ? TIME_TRX_OFF_PLL_ON : TIME_RX_ON_PLL_ON;
- chb_delay_us(delay);
-
- if (chb_get_state() == state)
- {
- return RADIO_SUCCESS;
- }
- return RADIO_TIMED_OUT;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_set_ieee_addr(U8 *addr)
-{
- chb_eeprom_write(CFG_EEPROM_CHIBI_IEEEADDR, addr, 8);
- chb_reg_write64(IEEE_ADDR_0, addr);
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_get_ieee_addr(U8 *addr)
-{
- chb_eeprom_read(CFG_EEPROM_CHIBI_IEEEADDR, addr, 8);
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_set_short_addr(U16 addr)
-{
- U8 *addr_ptr = (U8 *)&addr;
- chb_pcb_t *pcb = chb_get_pcb();
-
- chb_eeprom_write(CFG_EEPROM_CHIBI_SHORTADDR, addr_ptr, 2);
- chb_reg_write16(SHORT_ADDR_0, addr);
- pcb->src_addr = addr;
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-U16 chb_get_short_addr()
-{
- int16_t addr;
-
- chb_eeprom_read(CFG_EEPROM_CHIBI_SHORTADDR, (uint8_t*)&addr, 2);
- return addr;
-}
-/**************************************************************************/
-/*!
- Set the high gain mode pin for the CC1190
-*/
-/**************************************************************************/
-#if (CHB_CC1190_PRESENT)
-void chb_set_hgm(U8 enb)
-{
- if (enb)
- {
- gpioSetValue(CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 1);
- }
- else
- {
- gpioSetValue(CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 0);
- }
-}
-#endif
-
-/**************************************************************************/
-/*!
- Load the data into the fifo, initiate a transmission attempt,
- and return the status of the transmission attempt.
-*/
-/**************************************************************************/
-U8 chb_tx(U8 *hdr, U8 *data, U8 len)
-{
- U8 state = chb_get_state();
- chb_pcb_t *pcb = chb_get_pcb();
-
- if ((state == BUSY_TX) || (state == BUSY_TX_ARET))
- {
- return RADIO_WRONG_STATE;
- }
-
- // TODO: check why we need to transition to the off state before we go to tx_aret_on
- chb_set_state(TRX_OFF);
- chb_set_state(TX_ARET_ON);
-
- // TODO: try and start the frame transmission by writing TX_START command instead of toggling
- // sleep pin...i just feel like it's kind of weird...
-
- // write frame to buffer. first write header into buffer (add 1 for len byte), then data.
- chb_frame_write(hdr, CHB_HDR_SZ + 1, data, len);
-
- //Do frame transmission
- chb_reg_read_mod_write(TRX_STATE, CMD_TX_START, 0x1F);
-
- // wait for the transmission to end, signalled by the TRX END flag
- while (!pcb->tx_end);
- pcb->tx_end = false;
-
- // check the status of the transmission
- return chb_get_status();
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-static void chb_radio_init()
-{
- U8 ieee_addr[8];
-
- // reset chip
- chb_reset();
-
- // disable intps while we config the radio
- chb_reg_write(IRQ_MASK, 0);
-
- // force transceiver off while we configure the intps
- chb_reg_read_mod_write(TRX_STATE, CMD_FORCE_TRX_OFF, 0x1F);
-
- // make sure the transceiver is in the off state before proceeding
- while ((chb_reg_read(TRX_STATUS) & 0x1f) != TRX_OFF);
-
- // set radio cfg parameters
- // **note** uncomment if these will be set to something other than default
- //chb_reg_read_mod_write(XAH_CTRL_0, CHB_MAX_FRAME_RETRIES << CHB_MAX_FRAME_RETRIES_POS, 0xF << CHB_MAX_FRAME_RETRIES_POS);
- //chb_reg_read_mod_write(XAH_CTRL_0, CHB_MAX_CSMA_RETRIES << CHB_MAX_CSMA_RETIRES_POS, 0x7 << CHB_MAX_CSMA_RETIRES_POS);
- //chb_reg_read_mod_write(CSMA_SEED_1, CHB_CSMA_SEED1 << CHB_CSMA_SEED1_POS, 0x7 << CHB_CSMA_SEED1_POS);
- //chb_ret_write(CSMA_SEED0, CHB_CSMA_SEED0);
- //chb_reg_read_mod_write(PHY_CC_CCA, CHB_CCA_MODE << CHB_CCA_MODE_POS,0x3 << CHB_CCA_MODE_POS);
- //chb_reg_write(CCA_THRES, CHB_CCA_ED_THRES);
-
- // set frame version that we'll accept
- chb_reg_read_mod_write(CSMA_SEED_1, CHB_FRM_VER << CHB_FVN_POS, 3 << CHB_FVN_POS);
-
- // set interrupt mask
- // re-enable intps while we config the radio
- chb_reg_write(IRQ_MASK, (1<<IRQ_RX_START) | (1<<IRQ_TRX_END));
-
- #if (CFG_CHIBI_PROMISCUOUS == 0)
- // set autocrc mode
- chb_reg_read_mod_write(TRX_CTRL_1, 1 << CHB_AUTO_CRC_POS, 1 << CHB_AUTO_CRC_POS);
- #endif
- // set up default phy modulation, data rate and power (Ex. OQPSK, 100 kbps, 868 MHz, 3dBm)
- chb_set_mode(CFG_CHIBI_MODE); // Defined in projectconfig.h
- chb_set_pwr(CFG_CHIBI_POWER); // Defined in projectconfig.h
- chb_set_channel(CFG_CHIBI_CHANNEL); // Defined in projectconfig.h
-
- // set fsm state
- // put trx in rx auto ack mode
- chb_set_state(RX_STATE);
-
- // set pan ID
- chb_reg_write16(PAN_ID_0, CFG_CHIBI_PANID); // Defined in projectconfig.h
-
- // set short addr
- // NOTE: Possibly get this from EEPROM
- chb_reg_write16(SHORT_ADDR_0, chb_get_short_addr());
-
- // set long addr
- // NOTE: Possibly get this from EEPROM
- chb_get_ieee_addr(ieee_addr);
- chb_reg_write64(IEEE_ADDR_0, ieee_addr);
-
-#if (CHB_CC1190_PRESENT)
- // set high gain mode pin to output and init to zero
- gpioSetDir (CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 1);
- gpioSetPullup (&CHB_CC1190_HGM_IOCONREG, gpioPullupMode_Inactive);
- gpioSetValue (CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 0);
-
- // set external power amp on AT86RF212
- chb_reg_read_mod_write(TRX_CTRL_1, 1<<CHB_PA_EXT_EN_POS, 1<<CHB_PA_EXT_EN_POS);
-
- // set power to lowest level possible
- chb_set_pwr(0xd); // set to -11 dBm
-#endif
-
- // set interrupt/gpio pin to input
- gpioSetDir (CHB_EINTPORT, CHB_EINTPIN, 0);
-
- // set internal resistor on EINT pin to inactive
- gpioSetPullup (&CHB_EINTPIN_IOCONREG, gpioPullupMode_Inactive);
-
- // configure pin for interrupt
- gpioSetInterrupt (CHB_EINTPORT,
- CHB_EINTPIN,
- gpioInterruptSense_Edge, // Edge-sensitive
- gpioInterruptEdge_Single, // Single edge
- gpioInterruptEvent_ActiveLow); // High triggers interrupt
-
- // enable interrupt
- gpioIntEnable (CHB_EINTPORT,
- CHB_EINTPIN);
-
- if (chb_get_state() != RX_STATE)
- {
- // ERROR occurred initializing the radio. Print out error message.
- printf(chb_err_init);
- }
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_drvr_init()
-{
- // ToDo: Make sure gpioInit has been called
- // ToDo: Make sure CT32B0 has been initialised and enabled
-
- // config SPI for at86rf230 access
- chb_spi_init();
-
- // Setup 16-bit timer 0 (used for us delays)
- timer16Init(0, 0xFFFF);
- timer16Enable(0);
-
- // Set sleep and reset as output
- gpioSetDir(CHB_SLPTRPORT, CHB_SLPTRPIN, 1);
- gpioSetDir(CHB_RSTPORT, CHB_RSTPIN, 1);
-
- // configure IOs
- gpioSetValue(CHB_SLPTRPORT, CHB_SLPTRPIN, 1); // Set sleep high
- gpioSetValue(CHB_RSTPORT, CHB_RSTPIN, 1); // Set reset high
-
- // Set internal resistors
- gpioSetPullup (&CHB_SLPTRPIN_IOCONREG, gpioPullupMode_Inactive);
- gpioSetPullup (&CHB_RSTPIN_IOCONREG, gpioPullupMode_Inactive);
-
- // config radio
- chb_radio_init();
-}
-
-/**************************************************************************/
-/*!
- Enable or disable the radio's sleep mode.
-*/
-/**************************************************************************/
-void chb_sleep(U8 enb)
-{
- if (enb)
- {
- // first we need to go to TRX OFF state
- chb_set_state(TRX_OFF);
-
- // set the SLPTR pin
- // CHB_SLPTR_PORT |= _BV(CHB_SLPTR_PIN);
- CHB_SLPTR_ENABLE();
- }
- else
- {
- // make sure the SLPTR pin is low first
- // CHB_SLPTR_PORT &= ~(_BV(CHB_SLPTR_PIN));
- CHB_SLPTR_DISABLE();
-
- // we need to allow some time for the PLL to lock
- chb_delay_us(TIME_SLEEP_TO_TRX_OFF);
-
- // Turn the transceiver back on
- chb_set_state(RX_STATE);
- }
-}
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_ISR_Handler (void)
-{
- // U8 dummy, state, intp_src = 0;
- U8 state, intp_src = 0;
- chb_pcb_t *pcb = chb_get_pcb();
-
- CHB_ENTER_CRIT();
-
- /*Read Interrupt source.*/
- CHB_SPI_ENABLE();
-
- /*Send Register address and read register content.*/
- // dummy = chb_xfer_byte(IRQ_STATUS | CHB_SPI_CMD_RR);
- chb_xfer_byte(IRQ_STATUS | CHB_SPI_CMD_RR);
- intp_src = chb_xfer_byte(0);
-
- CHB_SPI_DISABLE();
-
- while (intp_src)
- {
- /*Handle the incomming interrupt. Prioritized.*/
- if ((intp_src & CHB_IRQ_RX_START_MASK))
- {
- intp_src &= ~CHB_IRQ_RX_START_MASK;
- }
- else if (intp_src & CHB_IRQ_TRX_END_MASK)
- {
- state = chb_get_state();
-
- if ((state == RX_ON) || (state == RX_AACK_ON) || (state == BUSY_RX_AACK))
- {
- // get the ed measurement
- pcb->ed = chb_reg_read(PHY_ED_LEVEL);
-
- // get the crc
- pcb->crc = (chb_reg_read(PHY_RSSI) & (1<<7)) ? 1 : 0;
-
- // if the crc is not valid, then do not read the frame and set the rx flag
- if (pcb->crc)
- {
- // get the data
- chb_frame_read();
- pcb->rcvd_xfers++;
- pcb->data_rcv = true;
- }
- }
- else
- {
- pcb->tx_end = true;
- }
- intp_src &= ~CHB_IRQ_TRX_END_MASK;
- while (chb_set_state(RX_STATE) != RADIO_SUCCESS);
- }
- else if (intp_src & CHB_IRQ_TRX_UR_MASK)
- {
- intp_src &= ~CHB_IRQ_TRX_UR_MASK;
- pcb->underrun++;
- }
- else if (intp_src & CHB_IRQ_PLL_UNLOCK_MASK)
- {
- intp_src &= ~CHB_IRQ_PLL_UNLOCK_MASK;
- }
- else if (intp_src & CHB_IRQ_PLL_LOCK_MASK)
- {
- intp_src &= ~CHB_IRQ_PLL_LOCK_MASK;
- }
- else if (intp_src & CHB_IRQ_BAT_LOW_MASK)
- {
- intp_src &= ~CHB_IRQ_BAT_LOW_MASK;
- pcb->battlow++;
- }
- else
- {
- }
- }
- CHB_LEAVE_CRIT();
-}
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-#ifndef CHIBI_DRVR_H
-#define CHIBI_DRVR_H
-
-#include "types.h"
-#include "projectconfig.h"
-#include "core/gpio/gpio.h"
-
-#define CHB_CC1190_PRESENT 0 /// Set to 1 if CC1190 is being used
-#define CHB_CHINA 0
-#define CHB_EEPROM_IEEE_ADDR CFG_CHIBI_EEPROM_IEEEADDR
-#define CHB_EEPROM_SHORT_ADDR CFG_CHIBI_EEPROM_SHORTADDR
-#define CHB_AT86RF212_VER_NUM 0x01
-#define CHB_AT86RF212_PART_NUM 0x07
-// #define CHB_BPSK 0 // set to 1 if want to use BPSK rather than OQPSK
-
-#define CHB_SPI_CMD_RW 0xC0 /**< Register Write (short mode). */
-#define CHB_SPI_CMD_RR 0x80 /**< Register Read (short mode). */
-#define CHB_SPI_CMD_FW 0x60 /**< Frame Transmit Mode (long mode). */
-#define CHB_SPI_CMD_FR 0x20 /**< Frame Receive Mode (long mode). */
-#define CHB_SPI_CMD_SW 0x40 /**< SRAM Write. */
-#define CHB_SPI_CMD_SR 0x00 /**< SRAM Read. */
-#define CHB_SPI_CMD_RADDRM 0x7F /**< Register Address Mask. */
-
-#define CHB_IRQ_BAT_LOW_MASK 0x80 /**< Mask for the BAT_LOW interrupt. */
-#define CHB_IRQ_TRX_UR_MASK 0x40 /**< Mask for the TRX_UR interrupt. */
-#define CHB_IRQ_TRX_END_MASK 0x08 /**< Mask for the TRX_END interrupt. */
-#define CHB_IRQ_RX_START_MASK 0x04 /**< Mask for the RX_START interrupt. */
-#define CHB_IRQ_PLL_UNLOCK_MASK 0x02 /**< Mask for the PLL_UNLOCK interrupt. */
-#define CHB_IRQ_PLL_LOCK_MASK 0x01 /**< Mask for the PLL_LOCK interrupt. */
-
-#define CHB_EINTPORT 1
-#define CHB_EINTPIN 8
-#define CHB_EINTPIN_IOCONREG IOCON_PIO1_8
-#define CHB_RSTPORT 1
-#define CHB_RSTPIN 9
-#define CHB_RSTPIN_IOCONREG IOCON_PIO1_9
-#define CHB_SLPTRPORT 1
-#define CHB_SLPTRPIN 10
-#define CHB_SLPTRPIN_IOCONREG IOCON_PIO1_10
-
-// if CC1190 present, set up the ports and pins for high gain mode control
-#if (CHB_CC1190_PRESENT)
- #define CHB_CC1190_HGM_PORT 1
- #define CHB_CC1190_HGM_PIN 11
- #define CHB_CC1190_HGM_IOCONREG IOCON_PIO1_11
-#endif
-
-//#define CHB_DDR_SLPTR DDRF
-//#define CHB_DDR_RST DDRF
-//#define CHB_RADIO_IRQ INT6_vect
-//#define CHB_RADIO_IRQ_PIN INT6
-
-#define CHB_ENTER_CRIT() __disable_irq()
-#define CHB_LEAVE_CRIT() __enable_irq()
-#define CHB_RST_ENABLE() do {gpioSetValue(CHB_RSTPORT, CHB_RSTPIN, 0); } while (0)
-#define CHB_RST_DISABLE() do {gpioSetValue(CHB_RSTPORT, CHB_RSTPIN, 1); } while (0)
-#define CHB_SLPTR_ENABLE() do {gpioSetValue(CHB_SLPTRPORT, CHB_SLPTRPIN, 1); } while (0)
-#define CHB_SLPTR_DISABLE() do {gpioSetValue(CHB_SLPTRPORT, CHB_SLPTRPIN, 0); } while (0)
-
-// CCA constants
-enum
-{
- CCA_ED = 1, /**< Use energy detection above threshold mode. */
- CCA_CARRIER_SENSE = 2, /**< Use carrier sense mode. */
- CCA_CARRIER_SENSE_WITH_ED = 3 /**< Use a combination of both energy detection and carrier sense. */
-};
-
-// configuration parameters
-enum
-{
- CHB_CHANNEL = 1, // Replaced in projectconfig.h with CFG_CHIBI_CHANNEL
- CHB_PAN_ID = 0x1234, // Replaced in projectconfig.h with CFG_CHIBI_PANID
- CHB_TX_PWR = 0x0,
- CHB_SHORT_ADDR = 0x0,
- CHB_IEEE_ADDR = 0x0,
- CHB_MAX_FRAME_RETRIES = 3,
- CHB_MAX_CSMA_RETRIES = 4,
- CHB_CCA_MODE = CCA_ED,
- CHB_MIN_BE = 3,
- CHB_MAX_BE = 5,
- CHB_CCA_ED_THRES = 0x7,
- CHB_CSMA_SEED0 = 0,
- CHB_CSMA_SEED1 = 0,
- CHB_FRM_VER = 1 // accept 802.15.4 ver 0 or 1 frames
-};
-
-// register addresses
-enum
-{
- TRX_STATUS = 0x01,
- TRX_STATE = 0x02,
- TRX_CTRL_0 = 0x03,
- TRX_CTRL_1 = 0x04,
- PHY_TX_PWR = 0x05,
- PHY_RSSI = 0x06,
- PHY_ED_LEVEL = 0x07,
- PHY_CC_CCA = 0x08,
- CCA_THRES = 0x09,
- RX_CTRL = 0x0a,
- SFD_VALUE = 0x0b,
- TRX_CTRL_2 = 0x0c,
- ANT_DIV = 0x0d,
- IRQ_MASK = 0x0e,
- IRQ_STATUS = 0x0f,
- VREG_CTRL = 0x10,
- BATMON = 0x11,
- XOSC_CTRL = 0x12,
- CC_CTRL_0 = 0x13,
- CC_CTRL_1 = 0x14,
- RX_SYN = 0x15,
- RF_CTRL_0 = 0x16,
- XAH_CTRL_1 = 0x17,
- FTN_CTRL = 0x18,
- RF_CTRL_1 = 0x19,
- PLL_CF = 0x1a,
- PLL_DCU = 0x1b,
- PART_NUM = 0x1c,
- VERSION_NUM = 0x1d,
- MAN_ID_0 = 0x1e,
- MAN_ID_1 = 0x1f,
- SHORT_ADDR_0 = 0x20,
- SHORT_ADDR_1 = 0x21,
- PAN_ID_0 = 0x22,
- PAN_ID_1 = 0x23,
- IEEE_ADDR_0 = 0x24,
- IEEE_ADDR_1 = 0x25,
- IEEE_ADDR_2 = 0x26,
- IEEE_ADDR_3 = 0x27,
- IEEE_ADDR_4 = 0x28,
- IEEE_ADDR_5 = 0x29,
- IEEE_ADDR_6 = 0x2a,
- IEEE_ADDR_7 = 0x2b,
- XAH_CTRL_0 = 0x2c,
- CSMA_SEED_0 = 0x2d,
- CSMA_SEED_1 = 0x2e,
- CSMA_BE = 0x2f
-};
-
-// random defines
-enum
-{
- CHB_MAX_FRAME_RETRIES_POS = 4,
- CHB_MAX_CSMA_RETIRES_POS = 1,
- CHB_CSMA_SEED1_POS = 0,
- CHB_CCA_MODE_POS = 5,
- CHB_AUTO_CRC_POS = 5,
- CHB_TRX_END_POS = 3,
- CHB_TRAC_STATUS_POS = 5,
- CHB_FVN_POS = 6,
- CHB_OQPSK_TX_OFFSET = 2,
- CHB_BPSK_TX_OFFSET = 3,
- CHB_MIN_FRAME_LENGTH = 3,
- CHB_MAX_FRAME_LENGTH = 0x7f,
- CHB_PA_EXT_EN_POS = 7
-};
-
-// transceiver timing
-enum{
- TIME_RST_PULSE_WIDTH = 1,
- TIME_P_ON_TO_CLKM_AVAIL = 380,
- TIME_SLEEP_TO_TRX_OFF = 240,
- TIME_TRX_OFF_TO_SLEEP = 35,
- TIME_PLL_ON_TRX_OFF = 1,
- TIME_TRX_OFF_RX_ON = 110,
- TIME_RX_ON_TRX_OFF = 1,
- TIME_PLL_ON_RX_ON = 1,
- TIME_RX_ON_PLL_ON = 1,
- TIME_PLL_LOCK_TIME = 110,
- TIME_BUSY_TX_PLL_ON = 32,
- TIME_ALL_STATES_TRX_OFF = 1,
- TIME_RESET_TRX_OFF = 26,
- TIME_TRX_IRQ_DELAY = 9,
- TIME_TRX_OFF_PLL_ON = 110,
- TIME_IRQ_PROCESSING_DLY = 32
-};
-
-// trac status
-enum{
- TRAC_SUCCESS = 0,
- TRAC_SUCCESS_DATA_PENDING = 1,
- TRAC_WAIT_FOR_ACK = 2,
- TRAC_CHANNEL_ACCESS_FAIL = 3,
- TRAC_NO_ACK = 5,
- TRAC_INVALID = 7
-};
-
-// radio statuses
-enum{
- RADIO_SUCCESS = 0x40, /**< The requested service was performed successfully. */
- RADIO_UNSUPPORTED_DEVICE, /**< The connected device is not an Atmel AT86RF212. */
- RADIO_INVALID_ARGUMENT, /**< One or more of the supplied function arguments are invalid. */
- RADIO_TIMED_OUT, /**< The requested service timed out. */
- RADIO_WRONG_STATE, /**< The end-user tried to do an invalid state transition. */
- RADIO_BUSY_STATE, /**< The radio transceiver is busy receiving or transmitting. */
- RADIO_STATE_TRANSITION_FAILED, /**< The requested state transition could not be completed. */
- RADIO_CCA_IDLE, /**< Channel is clear, available to transmit a new frame. */
- RADIO_CCA_BUSY, /**< Channel busy. */
- RADIO_TRX_BUSY, /**< Transceiver is busy receiving or transmitting data. */
- RADIO_BAT_LOW, /**< Measured battery voltage is lower than voltage threshold. */
- RADIO_BAT_OK, /**< Measured battery voltage is above the voltage threshold. */
- RADIO_CRC_FAILED, /**< The CRC failed for the actual frame. */
- RADIO_CHANNEL_ACCESS_FAILURE, /**< The channel access failed during the auto mode. */
- RADIO_NO_ACK, /**< No acknowledge frame was received. */
-};
-
-// transceiver commands
-enum
-{
- CMD_NOP = 0,
- CMD_TX_START = 2,
- CMD_FORCE_TRX_OFF = 3,
- CMD_FORCE_PLL_ON = 4,
- CMD_RX_ON = 6,
- CMD_TRX_OFF = 8,
- CMD_PLL_ON = 9,
- CMD_RX_AACK_ON = 22,
- CMD_TX_ARET_ON = 25
-};
-
-// transceiver states
-enum
-{
- P_ON = 0,
- BUSY_RX = 1,
- BUSY_TX = 2,
- RX_ON = 6,
- TRX_OFF = 8,
- PLL_ON = 9,
- SLEEP = 15,
- BUSY_RX_AACK = 17,
- BUSY_TX_ARET = 18,
- RX_AACK_ON = 22,
- TX_ARET_ON = 25,
- RX_ON_NOCLK = 28,
- RX_AACK_ON_NOCLK = 29,
- BUSY_RX_AACK_NOCLK = 30,
- TRANS_IN_PROG = 31
-};
-
-// transceiver interrupt register
-enum
-{
- IRQ_PLL_LOCK = 0,
- IRQ_PLL_UNLOCK = 1,
- IRQ_RX_START = 2,
- IRQ_TRX_END = 3,
- IRQ_CCA_ED_READY = 4,
- IRQ_AMI = 5,
- IRQ_TRX_UR = 6,
- IRQ_BAT_LOW = 7
-};
-
-// transceiver modes
-enum
-{
- OQPSK_868MHZ = 0,
- OQPSK_915MHZ = 1,
- OQPSK_780MHZ = 2,
- BPSK40_915MHZ = 3,
- BPSK20_868MHZ = 4
-};
-
-// See Table 7-15 for details
-enum
-{
- CHB_PWR_EU1_2DBM = 0x63, // EU (868MHz) Linearized PA mode
- CHB_PWR_EU1_1DBM = 0x64, // Note: BPSK 20kbit/s only!
- CHB_PWR_EU1_0DBM = 0x65,
- CHB_PWR_EU2_5DBM = 0xE7, // EU (868MHz) Boost mode (but > supply current)
- CHB_PWR_EU2_4DBM = 0xE8, // 4-5dBM BPSK 20 kbit/s only!
- CHB_PWR_EU2_3DBM = 0xE9, // 0-3dBM O-QPSK 100/200/400 kbit/s or BPSK
- CHB_PWR_EU2_2DBM = 0xEA,
- CHB_PWR_EU2_1DBM = 0xCB,
- CHB_PWR_EU2_0DBM = 0xAB,
- CHB_PWR_NA_10DBM = 0xC0, // North America (915MHz)
- CHB_PWR_NA_9DBM = 0xA1,
- CHB_PWR_NA_8DBM = 0x81,
- CHB_PWR_NA_7DBM = 0x82,
- CHB_PWR_NA_6DBM = 0x83,
- CHB_PWR_NA_5DBM = 0x60,
- CHB_PWR_NA_4DBM = 0x61,
- CHB_PWR_NA_3DBM = 0x41,
- CHB_PWR_NA_2DBM = 0x42,
- CHB_PWR_NA_1DBM = 0x22,
- CHB_PWR_NA_0DBM = 0x23,
- CHB_PWR_CHINA_5DBM = 0xE7, // China (780MHz)
- CHB_PWR_CHINA_4DBM = 0xE8,
- CHB_PWR_CHINA_3DBM = 0xE9,
- CHB_PWR_CHINA_2DBM = 0xEA,
- CHB_PWR_CHINA_1DBM = 0xCA,
- CHB_PWR_CHINA_0DBM = 0xAA
-};
-
-// define receive state based on promiscuous mode setting
-#if (CFG_CHIBI_PROMISCUOUS == 1)
- #define RX_STATE RX_ON
-#else
- #define RX_STATE RX_AACK_ON
-#endif
-// init
-void chb_drvr_init();
-
-// data access
-U8 chb_reg_read(U8 addr);
-U16 chb_reg_read16(U8 addr);
-void chb_reg_write(U8 addr, U8 val);
-void chb_reg_write16(U8 addr, U16 val);
-void chb_reg_write64(U8 addr, U8 *val);
-void chb_reg_read_mod_write(U8 addr, U8 val, U8 mask);
-void chb_frame_write(U8 *hdr, U8 hdr_len, U8 *data, U8 data_len);
-
-// general configuration
-void chb_set_mode(U8 mode);
-U8 chb_set_channel(U8 channel);
-void chb_set_pwr(U8 val);
-void chb_set_ieee_addr(U8 *addr);
-void chb_get_ieee_addr(U8 *addr);
-void chb_set_short_addr(U16 addr);
-U16 chb_get_short_addr();
-U8 chb_set_state(U8 state);
-
-// Power management
-void chb_sleep(U8 enb);
-
-// data transmit
-U8 chb_tx(U8 *hdr, U8 *data, U8 len);
-
-#if (CHB_CC1190_PRESENT)
- void chb_set_hgm(U8 enb);
-#endif
-
-#ifdef CHB_DEBUG
-// sram access
-void chb_sram_read(U8 addr, U8 len, U8 *data);
-void chb_sram_write(U8 addr, U8 len, U8 *data);
-#endif
-
-void chb_ISR_Handler (void);
-
-#endif
-
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-/*!
- \file
- \ingroup
-
-
-*/
-/**************************************************************************/
-#include "chb_eeprom.h"
-#include "drivers/eeprom/eeprom.h"
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_eeprom_write(uint16_t addr, uint8_t *buf, uint16_t size)
-{
- // Write the address one byte at a time
- uint16_t a = 0;
- while (a < size)
- {
- eepromWriteU8(addr + a, buf[a]);
- a++;
- }
-}
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_eeprom_read(uint16_t addr, uint8_t *buf, uint16_t size)
-{
- // Read the contents at address
- eepromReadBuffer(addr, buf, size);
-}
-
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-/*!
- \file
- \ingroup
-
-
-*/
-/**************************************************************************/
-#ifndef CHB_EEPROM_H
-#define CHB_EEPROM_H
-
-#include "projectconfig.h"
-#include "types.h"
-
-void chb_eeprom_write(U16 addr, U8 *buf, U16 size);
-void chb_eeprom_read(U16 addr, U8 *buf, U16 size);
-
-#endif
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-/*!
- \file
- \ingroup
-
-
-*/
-/**************************************************************************/
-#include "chb.h"
-#include "chb_spi.h"
-#include "core/ssp/ssp.h"
-
-/**************************************************************************/
-/*!
-
-*/
-/**************************************************************************/
-void chb_spi_init()
-{
- // initialise spi, high between frames and transition on trailing edge
- sspInit(0, sspClockPolarity_High, sspClockPhase_FallingEdge);
-
- // set the slave select to idle
- CHB_SPI_DISABLE();
-}
-
-/**************************************************************************/
-/*!
- This function both reads and writes data. For write operations, include data
- to be written as argument. For read ops, use dummy data as arg. Returned
- data is read byte val.
-*/
-/**************************************************************************/
-U8 chb_xfer_byte(U8 data)
-{
- /* Move on only if NOT busy and TX FIFO not full */
- while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_MASK | SSP_SSP0SR_BSY_MASK)) != SSP_SSP0SR_TNF_NOTFULL);
- SSP_SSP0DR = data;
-
- /* Wait until the busy bit is cleared and receive buffer is not empty */
- while ((SSP_SSP0SR & (SSP_SSP0SR_BSY_MASK | SSP_SSP0SR_RNE_MASK)) != SSP_SSP0SR_RNE_NOTEMPTY);
-
- // Read the queue
- return SSP_SSP0DR;
-}
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-
-*******************************************************************/
-/*!
- \file
- \ingroup
-
-
-*/
-/**************************************************************************/
-
-#ifndef CHB_SPI_H
-#define CHB_SPI_H
-
-#include "projectconfig.h"
-#include "core/gpio/gpio.h"
-
-#define CHB_SSPORT (0) // P0.2 = SSEL
-#define CHB_SSPIN (2)
-
-#define CHB_SPI_ENABLE() do {gpioSetValue(CHB_SSPORT, CHB_SSPIN, 0);} while (0) // Drive SSEL low
-#define CHB_SPI_DISABLE() do {gpioSetValue(CHB_SSPORT, CHB_SSPIN, 1);} while (0) // Drive SSEL high
-
-#define CHB_SPIPORT 0
-#define CHB_SCK 1 // PB.1 - Output: SPI Serial Clock (SCLK)
-#define CHB_MOSI 2 // PB.2 - Output: SPI Master out - slave in (MOSI)
-#define CHB_MISO 3 // PB.3 - Input: SPI Master in - slave out (MISO)
-
-void chb_spi_init();
-U8 chb_xfer_byte(U8 data);
-
-#endif
+++ /dev/null
-/*******************************************************************
- Copyright (C) 2009 FreakLabs
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- Originally written by Christopher Wang aka Akiba.
- Please post support questions to the FreakLabs forum.
-*******************************************************************/
-/*!
- \file types.h
- \ingroup usb
-*/
-/*******************************************************************/
-#ifndef TYPES_H
-#define TYPES_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-// Standard data types
-typedef uint8_t U8; /// Generic 8 bit unsigned data type
-typedef uint16_t U16; /// Generic 16 bit unsigned data type
-typedef uint32_t U32; /// Generic 32 bit unsigned data type
-typedef uint64_t U64; /// Generic 64 bit unsigned data type
-
-typedef int8_t S8; /// Generic 8 bit signed data type
-typedef int16_t S16; /// Generic 16 bit signed data type
-typedef int32_t S32; /// Generic 32 bit signed data type
-
-#endif
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "chb.h"
+#include "chb_drvr.h"
+#include "chb_buf.h"
+
+static chb_pcb_t pcb;
+// these are for the duplicate checking and rejection
+static U8 prev_seq = 0xFF;
+static U16 prev_src_addr = 0xFFFE;
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_init()
+{
+ memset(&pcb, 0, sizeof(chb_pcb_t));
+ pcb.src_addr = chb_get_short_addr();
+ chb_drvr_init();
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+chb_pcb_t *chb_get_pcb()
+{
+ return &pcb;
+}
+
+/**************************************************************************/
+/*!
+ Requires the dest addr, location to store data, and len of payload.
+ Returns the length of the hdr.
+*/
+/**************************************************************************/
+static U8 chb_gen_hdr(U8 *hdr, U16 addr, U8 len)
+{
+ U8 *hdr_ptr = hdr;
+
+ // calc frame size and put in 0 position of array
+ // frame size = hdr sz + payload len + fcs len
+ *hdr_ptr++ = CHB_HDR_SZ + len + CHB_FCS_LEN;
+
+ // use default fcf byte 0 val but test for ack request. we won't request
+ // ack if broadcast. all other cases we will.
+ *hdr_ptr++ = CHB_FCF_BYTE_0 | ((addr != 0xFFFF) << CHB_ACK_REQ_POS);
+ *hdr_ptr++ = CHB_FCF_BYTE_1;
+
+ *hdr_ptr++ = pcb.seq++;
+
+ // fill out dest pan ID, dest addr, src addr
+ *(U16 *)hdr_ptr = CFG_CHIBI_PANID;
+ hdr_ptr += sizeof(U16);
+ *(U16 *)hdr_ptr = addr;
+ hdr_ptr += sizeof(U16);
+ *(U16 *)hdr_ptr = pcb.src_addr;
+ hdr_ptr += sizeof(U16);
+
+ // return the len of the header
+ return hdr_ptr - hdr;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U8 chb_write(U16 addr, U8 *data, U8 len)
+{
+ // U8 status, frm_len, hdr_len, hdr[CHB_HDR_SZ + 1];
+ U8 status, frm_len, hdr[CHB_HDR_SZ + 1];
+
+ while (len > 0)
+ {
+ // calculate which frame len to use. if greater than max payload, split
+ // up operation.
+ frm_len = (len > CHB_MAX_PAYLOAD) ? CHB_MAX_PAYLOAD : len;
+
+ // gen frame header
+ // hdr_len = chb_gen_hdr(hdr, addr, frm_len);
+ chb_gen_hdr(hdr, addr, frm_len);
+
+ // send data to chip
+ status = chb_tx(hdr, data, frm_len);
+
+ if (status != CHB_SUCCESS)
+ {
+ switch (status)
+ {
+ case RADIO_SUCCESS:
+ // fall through
+ case CHB_SUCCESS_DATA_PENDING:
+ pcb.txd_success++;
+ break;
+
+ case CHB_NO_ACK:
+ pcb.txd_noack++;
+ break;
+
+ case CHB_CHANNEL_ACCESS_FAILURE:
+ pcb.txd_channel_fail++;
+ break;
+
+ default:
+ break;
+ }
+ return status;
+ }
+
+ // adjust len and restart
+ len = len - frm_len;
+ }
+ return CHB_SUCCESS;
+}
+
+/**************************************************************************/
+/*!
+ Read data from the buffer. Need to pass in a buffer of at leasts max frame
+ size and two 16-bit containers for the src and dest addresses.
+
+ The read function will automatically populate the addresses and the data with
+ the frm payload. It will then return the len of the payload.
+*/
+/**************************************************************************/
+U8 chb_read(chb_rx_data_t *rx)
+{
+ U8 i, len, seq, *data_ptr;
+
+ data_ptr = rx->data;
+
+ // first byte is always len. check it to make sure
+ // we have a valid len byte.
+ if ((len = chb_buf_read()) > CHB_MAX_FRAME_LENGTH)
+ {
+ return 0;
+ }
+ *data_ptr++ = len;
+
+ // load the rest of the data into buffer
+ for (i=0; i<len; i++)
+ {
+ *data_ptr++ = chb_buf_read();
+ }
+
+ // we're using the buffer that's fed in as an argument as a temp
+ // buffer as well to save resources.
+ // we'll use it as temp storage to parse the frame. then move the frame
+ // down so that only the payload will be in the buffer.
+
+ // extract the sequence number
+ data_ptr = rx->data + 3; // location of sequence number
+ seq = *data_ptr;
+
+ // parse the buffer and extract the dest and src addresses
+ data_ptr = rx->data + 6; // location of dest addr
+ rx->dest_addr = *(U16 *)data_ptr;
+ data_ptr += sizeof(U16);
+ rx->src_addr = *(U16 *)data_ptr;
+ data_ptr += sizeof(U16);
+
+ // if the data in the rx buf is 0, then clear the rx_flag. otherwise, keep it raised
+ if (!chb_buf_get_len())
+ {
+ pcb.data_rcv = false;
+ }
+
+#if (CFG_CHIBI_PROMISCUOUS == 1)
+ // if we're in promiscuous mode, we don't want to do any duplicate rejection and we don't want to move the payload
+ // to the front of the buffer. We want to capture the full frame so just keep the frame intact and return the length.
+ return len;
+#else
+ // duplicate frame check (dupe check). we want to remove frames that have been already been received since they
+ // are just retries.
+ // note: this dupe check only removes duplicate frames from the previous transfer. if another frame from a different
+ // node comes in between the dupes, then the dupe will show up as a received frame.
+ if ((seq == prev_seq) && (rx->src_addr == prev_src_addr))
+ {
+ // this is a duplicate frame from a retry. the remote node thinks we didn't receive
+ // it properly. discard.
+ return 0;
+ }
+ else
+ {
+ prev_seq = seq;
+ prev_src_addr = rx->src_addr;
+ }
+
+ // move the payload down to the beginning of the data buffer
+ memmove(rx->data, data_ptr, len - CHB_HDR_SZ);
+ // finally, return the len of the payload
+ return len - CHB_HDR_SZ - CHB_FCS_LEN;
+#endif
+}
+
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+#ifndef CHIBI_H
+#define CHIBI_H
+
+#include "types.h"
+
+#define CHB_HDR_SZ 9 // FCF + seq + pan_id + dest_addr + src_addr (2 + 1 + 2 + 2 + 2)
+#define CHB_FCS_LEN 2
+#define CHB_MAX_PAYLOAD 100
+
+
+// frame_type = data
+// security enabled = false
+// frame pending = false
+// ack request = false
+// pan ID compression = true
+#define CHB_FCF_BYTE_0 0x41
+
+// dest addr = 16-bit
+// frame version = 802.15.4 (not 2003)
+// src addr = 16-bit
+#define CHB_FCF_BYTE_1 0x98
+
+#define CHB_ACK_REQ_POS 5
+
+enum
+{
+ CHB_SUCCESS = 0,
+ CHB_SUCCESS_DATA_PENDING = 1,
+ CHB_CHANNEL_ACCESS_FAILURE = 3,
+ CHB_NO_ACK = 5,
+ CHB_INVALID = 7
+};
+
+// Chibi Protocol control block
+typedef struct
+{
+ U16 src_addr;
+ U8 seq;
+ volatile bool data_rcv;
+ volatile bool tx_end;
+
+ // stats
+ U16 rcvd_xfers;
+ U16 txd_success;
+ U16 txd_noack;
+ U16 txd_channel_fail;
+ U16 overflow;
+ U16 underrun;
+ U8 battlow;
+ U8 ed;
+ U8 crc;
+} chb_pcb_t;
+
+typedef struct
+{
+ U8 len;
+ U16 src_addr;
+ U16 dest_addr;
+ U8 data[CHB_MAX_PAYLOAD];
+} chb_rx_data_t;
+
+void chb_init();
+chb_pcb_t *chb_get_pcb();
+U8 chb_write(U16 addr, U8 *data, U8 len);
+U8 chb_read(chb_rx_data_t *rx);
+
+#endif
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+#include <stdio.h>
+#include "chb_buf.h"
+#include "projectconfig.h"
+
+static U8 chb_buf[CFG_CHIBI_BUFFERSIZE];
+static volatile U32 rd_ptr, wr_ptr;
+static volatile U32 len;
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_buf_init()
+{
+ rd_ptr = 0;
+ wr_ptr = 0;
+ len = 0;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_buf_write(U8 data)
+{
+ chb_buf[wr_ptr] = data;
+ wr_ptr = (wr_ptr + 1) % CFG_CHIBI_BUFFERSIZE;
+ len++;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U8 chb_buf_read()
+{
+ U8 data;
+
+ data = chb_buf[rd_ptr];
+ rd_ptr = (rd_ptr + 1) % CFG_CHIBI_BUFFERSIZE;
+ len--;
+ return data;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U32 chb_buf_get_len()
+{
+ return len;
+}
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+#ifndef CHB_BUF_H
+#define CHB_BUF_H
+
+#include "types.h"
+
+void chb_buf_init();
+void chb_buf_write(U8 data);
+U8 chb_buf_read();
+U32 chb_buf_get_len();
+
+#endif
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+#include <stdio.h>
+#include "chb.h"
+#include "chb_drvr.h"
+#include "chb_buf.h"
+#include "chb_spi.h"
+#include "chb_eeprom.h"
+
+#include "core/systick/systick.h"
+#include "core/timer16/timer16.h"
+
+// store string messages in flash rather than RAM
+const char chb_err_overflow[] = "BUFFER FULL. TOSSING INCOMING DATA\r\n";
+const char chb_err_init[] = "RADIO NOT INITIALIZED PROPERLY\r\n";
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+static U8 chb_get_state()
+{
+ return chb_reg_read(TRX_STATUS) & 0x1f;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+static U8 chb_get_status()
+{
+ return chb_reg_read(TRX_STATE) >> CHB_TRAC_STATUS_POS;
+}
+
+/**************************************************************************/
+/*!
+ Cause a blocking delay for x microseconds
+*/
+/**************************************************************************/
+static void chb_delay_us(U16 usec)
+{
+ // Determine maximum delay using a 16 bit timer
+ // ToDo: Move this to a macro or fixed value!
+ uint32_t maxus = 0xFFFF / (CFG_CPU_CCLK / 1000000);
+
+ // Check if delay can be done in one operation
+ if (usec <= maxus)
+ {
+ timer16DelayUS(0, usec);
+ return;
+ }
+
+ // Split delay into several steps (to stay within limit of 16-bit timer)
+ do
+ {
+ if (usec >= maxus)
+ {
+ timer16DelayUS(0, maxus);
+ usec -= maxus;
+ }
+ else
+ {
+ timer16DelayUS(0, usec);
+ usec = 0;
+ }
+ } while (usec > 0);
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_reset()
+{
+ CHB_RST_DISABLE();
+ CHB_SLPTR_DISABLE();
+
+ // wait a bit while transceiver wakes up
+ chb_delay_us(TIME_P_ON_TO_CLKM_AVAIL);
+
+ // reset the device
+ CHB_RST_ENABLE();
+ chb_delay_us(TIME_RST_PULSE_WIDTH);
+ CHB_RST_DISABLE();
+
+ // check that we have the part number that we're expecting
+ while (1)
+ {
+ // if you're stuck in this loop, that means that you're not reading
+ // the version and part number register correctly. possible that version number
+ // changes. if so, update version num in header file
+ if ((chb_reg_read(VERSION_NUM) == CHB_AT86RF212_VER_NUM) && (chb_reg_read(PART_NUM) == CHB_AT86RF212_PART_NUM))
+ {
+ break;
+ }
+ }
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U8 chb_reg_read(U8 addr)
+{
+ U8 val = 0;
+
+ /* Add the register read command to the register address. */
+ addr |= 0x80;
+
+ CHB_ENTER_CRIT();
+ CHB_SPI_ENABLE();
+
+ /*Send Register address and read register content.*/
+ val = chb_xfer_byte(addr);
+ val = chb_xfer_byte(val);
+
+ CHB_SPI_DISABLE();
+ CHB_LEAVE_CRIT();
+
+ return val;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U16 chb_reg_read16(U8 addr)
+{
+ U8 i;
+ U16 val = 0;
+
+ for (i=0; i<2; i++)
+ {
+ addr |= chb_reg_read(addr + i) << (8 * i);
+ }
+ return val;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_reg_write(U8 addr, U8 val)
+{
+ // U8 dummy;
+
+ /* Add the Register Write command to the address. */
+ addr |= 0xC0;
+
+ CHB_ENTER_CRIT();
+ CHB_SPI_ENABLE();
+
+ /*Send Register address and write register content.*/
+ // dummy = chb_xfer_byte(addr);
+ // dummy = chb_xfer_byte(val);
+ chb_xfer_byte(addr);
+ chb_xfer_byte(val);
+
+ CHB_SPI_DISABLE();
+ CHB_LEAVE_CRIT();
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_reg_write16(U8 addr, U16 val)
+{
+ U8 i;
+
+ for (i=0; i<2; i++)
+ {
+ chb_reg_write(addr + i, val >> (8 * i));
+ }
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_reg_write64(U8 addr, U8 *val)
+{
+ U8 i;
+
+ for (i=0; i<8; i++)
+ {
+ chb_reg_write(addr + i, *(val + i));
+ }
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_reg_read_mod_write(U8 addr, U8 val, U8 mask)
+{
+ U8 tmp;
+
+ tmp = chb_reg_read(addr);
+ val &= mask; // mask off stray bits from val
+ tmp &= ~mask; // mask off bits in reg val
+ tmp |= val; // copy val into reg val
+ chb_reg_write(addr, tmp); // write back to reg
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_frame_write(U8 *hdr, U8 hdr_len, U8 *data, U8 data_len)
+{
+ //U8 i, dummy;
+ U8 i;
+
+ // dont allow transmission longer than max frame size
+ if ((hdr_len + data_len) > 127)
+ {
+ return;
+ }
+
+ // initiate spi transaction
+ CHB_ENTER_CRIT();
+ CHB_SPI_ENABLE();
+
+ // send fifo write command
+ // dummy = chb_xfer_byte(CHB_SPI_CMD_FW);
+ chb_xfer_byte(CHB_SPI_CMD_FW);
+
+ // write hdr contents to fifo
+ for (i=0; i<hdr_len; i++)
+ {
+ // dummy = chb_xfer_byte(*hdr++);
+ chb_xfer_byte(*hdr++);
+ }
+
+ // write data contents to fifo
+ for (i=0; i<data_len; i++)
+ {
+ // dummy = chb_xfer_byte(*data++);
+ chb_xfer_byte(*data++);
+ }
+
+ // terminate spi transaction
+ CHB_SPI_DISABLE();
+ CHB_LEAVE_CRIT();
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+static void chb_frame_read()
+{
+ U8 i, len, data;
+
+ // CHB_ENTER_CRIT();
+ CHB_SPI_ENABLE();
+
+ /*Send frame read command and read the length.*/
+ chb_xfer_byte(CHB_SPI_CMD_FR);
+ len = chb_xfer_byte(0);
+
+ /*Check for correct frame length.*/
+ if ((len >= CHB_MIN_FRAME_LENGTH) && (len <= CHB_MAX_FRAME_LENGTH))
+ {
+ // check to see if there is room to write the frame in the buffer. if not, then drop it
+ if (len < (CFG_CHIBI_BUFFERSIZE - chb_buf_get_len()))
+ {
+ chb_buf_write(len);
+
+ for (i=0; i<len; i++)
+ {
+ data = chb_xfer_byte(0);
+ chb_buf_write(data);
+ }
+ }
+ else
+ {
+ // we've overflowed the buffer. toss the data and do some housekeeping
+ chb_pcb_t *pcb = chb_get_pcb();
+
+ // read out the data and throw it away
+ for (i=0; i<len; i++)
+ {
+ data = chb_xfer_byte(0);
+ }
+
+ // Increment the overflow stat
+ pcb->overflow++;
+
+ // print the error message
+ printf(chb_err_overflow);
+ }
+ }
+
+ CHB_SPI_DISABLE();
+ CHB_LEAVE_CRIT();
+}
+
+/**************************************************************************/
+/*!
+ Read directly from the SRAM on the radio. This is only used for debugging
+ purposes.
+*/
+/**************************************************************************/
+#ifdef CHB_DEBUG
+void chb_sram_read(U8 addr, U8 len, U8 *data)
+{
+ U8 i, dummy;
+
+ CHB_ENTER_CRIT();
+ CHB_SPI_ENABLE();
+
+ /*Send SRAM read command.*/
+ dummy = chb_xfer_byte(CHB_SPI_CMD_SR);
+
+ /*Send address where to start reading.*/
+ dummy = chb_xfer_byte(addr);
+
+ for (i=0; i<len; i++)
+ {
+ *data++ = chb_xfer_byte(0);
+ }
+
+ CHB_SPI_DISABLE();
+ CHB_LEAVE_CRIT();
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_sram_write(U8 addr, U8 len, U8 *data)
+{
+ U8 i, dummy;
+
+ CHB_ENTER_CRIT();
+ CHB_SPI_ENABLE();
+
+ /*Send SRAM write command.*/
+ dummy = chb_xfer_byte(CHB_SPI_CMD_SW);
+
+ /*Send address where to start writing to.*/
+ dummy = chb_xfer_byte(addr);
+
+ for (i=0; i<len; i++)
+ {
+ dummy = chb_xfer_byte(*data++);
+ }
+
+ CHB_SPI_DISABLE();
+ CHB_LEAVE_CRIT();
+}
+#endif
+
+/**************************************************************************/
+/*!
+ Set the channel mode, BPSK, OQPSK, etc...
+*/
+/**************************************************************************/
+void chb_set_mode(U8 mode)
+{
+ switch (mode)
+ {
+ case OQPSK_868MHZ:
+ chb_reg_read_mod_write(TRX_CTRL_2, 0x08, 0x3f); // 802.15.4-2006, channel page 2, channel 0 (868 MHz, Europe)
+ chb_reg_read_mod_write(RF_CTRL_0, CHB_OQPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
+ break;
+ case OQPSK_915MHZ:
+ chb_reg_read_mod_write(TRX_CTRL_2, 0x0c, 0x3f); // 802.15.4-2006, channel page 2, channels 1-10 (915 MHz, US)
+ chb_reg_read_mod_write(RF_CTRL_0, CHB_OQPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
+ break;
+ case OQPSK_780MHZ:
+ chb_reg_read_mod_write(TRX_CTRL_2, 0x1c, 0x3f); // 802.15.4-2006, channel page 5, channel 0-3 (780 MHz, China)
+ chb_reg_read_mod_write(RF_CTRL_0, CHB_OQPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
+ break;
+ case BPSK40_915MHZ:
+ chb_reg_read_mod_write(TRX_CTRL_2, 0x00, 0x3f); // 802.15.4-2006, BPSK, 40 kbps
+ chb_reg_read_mod_write(RF_CTRL_0, CHB_BPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
+ break;
+ case BPSK20_868MHZ:
+ chb_reg_read_mod_write(TRX_CTRL_2, 0x00, 0x3f); // 802.15.4-2006, BPSK, 20 kbps
+ chb_reg_read_mod_write(RF_CTRL_0, CHB_BPSK_TX_OFFSET, 0x3); // this is according to table 7-16 in at86rf212 datasheet
+ break;
+ }
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U8 chb_set_channel(U8 channel)
+{
+ U8 state;
+
+#if (CHB_CHINA == 1)
+
+ // this if for China only which uses a 780 MHz frequency band
+ if ((chb_reg_read(TRX_CTRL2) & 0x3f) != 0x1c)
+ {
+ chb_reg_read_mod_write(TRX_CTRL2, 0x1c, 0x3f);
+ }
+
+ if (channel > 3)
+ {
+ channel = 0;
+ }
+
+ channel = (channel << 1) + 11;
+
+ chb_reg_read_mod_write(CC_CTRL_1, 0x4, 0x7); // set 769 MHz base frequency for China
+ chb_reg_write(CC_CTRL_0, channel); // set the center frequency for the channel
+
+#else
+ //if (channel == 0)
+ //{
+ // // Channel 0 is for European use only. make sure we are using channel page 2,
+ // // channel 0 settings for 100 kbps
+ // if ((chb_reg_read(TRX_CTRL_2) & 0x3f) != 0x08)
+ // {
+ // chb_reg_read_mod_write(TRX_CTRL_2, 0x08, 0x3f);
+ // }
+ //}
+ //else if (channel > 10)
+ //{
+ // // if the channel is out of bounds for page 2, then default to channel 1 and
+ // // assume we're on the US frequency of 915 MHz
+ // channel = 1;
+ // if ((chb_reg_read(TRX_CTRL_2) & 0x3f) != 0x0c)
+ // {
+ // chb_reg_read_mod_write(TRX_CTRL_2, 0x0c, 0x3f);
+ // }
+ //}
+ //else
+ //{
+ // // Channels 1-10 are for US frequencies of 915 MHz
+ // if ((chb_reg_read(TRX_CTRL_2) & 0x3f) != 0x0c)
+ // {
+ // chb_reg_read_mod_write(TRX_CTRL_2, 0x0c, 0x3f);
+ // }
+ //}
+
+ chb_reg_read_mod_write(PHY_CC_CCA, channel, 0x1f);
+#endif
+
+ // add a delay to allow the PLL to lock if in active mode.
+ state = chb_get_state();
+ if ((state == RX_ON) || (state == PLL_ON))
+ {
+ chb_delay_us(TIME_PLL_LOCK_TIME);
+ }
+
+ return ((chb_reg_read(PHY_CC_CCA) & 0x1f) == channel) ? RADIO_SUCCESS : RADIO_TIMED_OUT;
+}
+
+/**************************************************************************/
+/*!
+ Set the power level
+*/
+/**************************************************************************/
+void chb_set_pwr(U8 val)
+{
+ chb_reg_write(PHY_TX_PWR, val);
+}
+
+/**************************************************************************/
+/*!
+ Set the TX/RX state machine state. Some manual manipulation is required
+ for certain operations. Check the datasheet for more details on the state
+ machine and manipulations.
+*/
+/**************************************************************************/
+U8 chb_set_state(U8 state)
+{
+ U8 curr_state, delay;
+
+ // if we're sleeping then don't allow transition
+ if (gpioGetValue(CHB_SLPTRPORT, CHB_SLPTRPIN))
+ {
+ return RADIO_WRONG_STATE;
+ }
+
+ // if we're in a transition state, wait for the state to become stable
+ curr_state = chb_get_state();
+ if ((curr_state == BUSY_TX_ARET) || (curr_state == BUSY_RX_AACK) || (curr_state == BUSY_RX) || (curr_state == BUSY_TX))
+ {
+ while (chb_get_state() == curr_state);
+ }
+
+ // At this point it is clear that the requested new_state is:
+ // TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON or TX_ARET_ON.
+ // we need to handle some special cases before we transition to the new state
+ switch (state)
+ {
+ case TRX_OFF:
+ /* Go to TRX_OFF from any state. */
+ CHB_SLPTR_DISABLE();
+ chb_reg_read_mod_write(TRX_STATE, CMD_FORCE_TRX_OFF, 0x1f);
+ chb_delay_us(TIME_ALL_STATES_TRX_OFF);
+ break;
+
+ case TX_ARET_ON:
+ if (curr_state == RX_AACK_ON)
+ {
+ /* First do intermediate state transition to PLL_ON, then to TX_ARET_ON. */
+ chb_reg_read_mod_write(TRX_STATE, CMD_PLL_ON, 0x1f);
+ chb_delay_us(TIME_RX_ON_PLL_ON);
+ }
+ break;
+
+ case RX_AACK_ON:
+ if (curr_state == TX_ARET_ON)
+ {
+ /* First do intermediate state transition to RX_ON, then to RX_AACK_ON. */
+ chb_reg_read_mod_write(TRX_STATE, CMD_PLL_ON, 0x1f);
+ chb_delay_us(TIME_RX_ON_PLL_ON);
+ }
+ break;
+ }
+
+ /* Now we're okay to transition to any new state. */
+ chb_reg_read_mod_write(TRX_STATE, state, 0x1f);
+
+ /* When the PLL is active most states can be reached in 1us. However, from */
+ /* TRX_OFF the PLL needs time to activate. */
+ delay = (curr_state == TRX_OFF) ? TIME_TRX_OFF_PLL_ON : TIME_RX_ON_PLL_ON;
+ chb_delay_us(delay);
+
+ if (chb_get_state() == state)
+ {
+ return RADIO_SUCCESS;
+ }
+ return RADIO_TIMED_OUT;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_set_ieee_addr(U8 *addr)
+{
+ chb_eeprom_write(CFG_EEPROM_CHIBI_IEEEADDR, addr, 8);
+ chb_reg_write64(IEEE_ADDR_0, addr);
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_get_ieee_addr(U8 *addr)
+{
+ chb_eeprom_read(CFG_EEPROM_CHIBI_IEEEADDR, addr, 8);
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_set_short_addr(U16 addr)
+{
+ U8 *addr_ptr = (U8 *)&addr;
+ chb_pcb_t *pcb = chb_get_pcb();
+
+ chb_eeprom_write(CFG_EEPROM_CHIBI_SHORTADDR, addr_ptr, 2);
+ chb_reg_write16(SHORT_ADDR_0, addr);
+ pcb->src_addr = addr;
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+U16 chb_get_short_addr()
+{
+ int16_t addr;
+
+ chb_eeprom_read(CFG_EEPROM_CHIBI_SHORTADDR, (uint8_t*)&addr, 2);
+ return addr;
+}
+/**************************************************************************/
+/*!
+ Set the high gain mode pin for the CC1190
+*/
+/**************************************************************************/
+#if (CHB_CC1190_PRESENT)
+void chb_set_hgm(U8 enb)
+{
+ if (enb)
+ {
+ gpioSetValue(CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 1);
+ }
+ else
+ {
+ gpioSetValue(CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 0);
+ }
+}
+#endif
+
+/**************************************************************************/
+/*!
+ Load the data into the fifo, initiate a transmission attempt,
+ and return the status of the transmission attempt.
+*/
+/**************************************************************************/
+U8 chb_tx(U8 *hdr, U8 *data, U8 len)
+{
+ U8 state = chb_get_state();
+ chb_pcb_t *pcb = chb_get_pcb();
+
+ if ((state == BUSY_TX) || (state == BUSY_TX_ARET))
+ {
+ return RADIO_WRONG_STATE;
+ }
+
+ // TODO: check why we need to transition to the off state before we go to tx_aret_on
+ chb_set_state(TRX_OFF);
+ chb_set_state(TX_ARET_ON);
+
+ // TODO: try and start the frame transmission by writing TX_START command instead of toggling
+ // sleep pin...i just feel like it's kind of weird...
+
+ // write frame to buffer. first write header into buffer (add 1 for len byte), then data.
+ chb_frame_write(hdr, CHB_HDR_SZ + 1, data, len);
+
+ //Do frame transmission
+ chb_reg_read_mod_write(TRX_STATE, CMD_TX_START, 0x1F);
+
+ // wait for the transmission to end, signalled by the TRX END flag
+ while (!pcb->tx_end);
+ pcb->tx_end = false;
+
+ // check the status of the transmission
+ return chb_get_status();
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+static void chb_radio_init()
+{
+ U8 ieee_addr[8];
+
+ // reset chip
+ chb_reset();
+
+ // disable intps while we config the radio
+ chb_reg_write(IRQ_MASK, 0);
+
+ // force transceiver off while we configure the intps
+ chb_reg_read_mod_write(TRX_STATE, CMD_FORCE_TRX_OFF, 0x1F);
+
+ // make sure the transceiver is in the off state before proceeding
+ while ((chb_reg_read(TRX_STATUS) & 0x1f) != TRX_OFF);
+
+ // set radio cfg parameters
+ // **note** uncomment if these will be set to something other than default
+ //chb_reg_read_mod_write(XAH_CTRL_0, CHB_MAX_FRAME_RETRIES << CHB_MAX_FRAME_RETRIES_POS, 0xF << CHB_MAX_FRAME_RETRIES_POS);
+ //chb_reg_read_mod_write(XAH_CTRL_0, CHB_MAX_CSMA_RETRIES << CHB_MAX_CSMA_RETIRES_POS, 0x7 << CHB_MAX_CSMA_RETIRES_POS);
+ //chb_reg_read_mod_write(CSMA_SEED_1, CHB_CSMA_SEED1 << CHB_CSMA_SEED1_POS, 0x7 << CHB_CSMA_SEED1_POS);
+ //chb_ret_write(CSMA_SEED0, CHB_CSMA_SEED0);
+ //chb_reg_read_mod_write(PHY_CC_CCA, CHB_CCA_MODE << CHB_CCA_MODE_POS,0x3 << CHB_CCA_MODE_POS);
+ //chb_reg_write(CCA_THRES, CHB_CCA_ED_THRES);
+
+ // set frame version that we'll accept
+ chb_reg_read_mod_write(CSMA_SEED_1, CHB_FRM_VER << CHB_FVN_POS, 3 << CHB_FVN_POS);
+
+ // set interrupt mask
+ // re-enable intps while we config the radio
+ chb_reg_write(IRQ_MASK, (1<<IRQ_RX_START) | (1<<IRQ_TRX_END));
+
+ #if (CFG_CHIBI_PROMISCUOUS == 0)
+ // set autocrc mode
+ chb_reg_read_mod_write(TRX_CTRL_1, 1 << CHB_AUTO_CRC_POS, 1 << CHB_AUTO_CRC_POS);
+ #endif
+ // set up default phy modulation, data rate and power (Ex. OQPSK, 100 kbps, 868 MHz, 3dBm)
+ chb_set_mode(CFG_CHIBI_MODE); // Defined in projectconfig.h
+ chb_set_pwr(CFG_CHIBI_POWER); // Defined in projectconfig.h
+ chb_set_channel(CFG_CHIBI_CHANNEL); // Defined in projectconfig.h
+
+ // set fsm state
+ // put trx in rx auto ack mode
+ chb_set_state(RX_STATE);
+
+ // set pan ID
+ chb_reg_write16(PAN_ID_0, CFG_CHIBI_PANID); // Defined in projectconfig.h
+
+ // set short addr
+ // NOTE: Possibly get this from EEPROM
+ chb_reg_write16(SHORT_ADDR_0, chb_get_short_addr());
+
+ // set long addr
+ // NOTE: Possibly get this from EEPROM
+ chb_get_ieee_addr(ieee_addr);
+ chb_reg_write64(IEEE_ADDR_0, ieee_addr);
+
+#if (CHB_CC1190_PRESENT)
+ // set high gain mode pin to output and init to zero
+ gpioSetDir (CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 1);
+ gpioSetPullup (&CHB_CC1190_HGM_IOCONREG, gpioPullupMode_Inactive);
+ gpioSetValue (CHB_CC1190_HGM_PORT, CHB_CC1190_HGM_PIN, 0);
+
+ // set external power amp on AT86RF212
+ chb_reg_read_mod_write(TRX_CTRL_1, 1<<CHB_PA_EXT_EN_POS, 1<<CHB_PA_EXT_EN_POS);
+
+ // set power to lowest level possible
+ chb_set_pwr(0xd); // set to -11 dBm
+#endif
+
+ // set interrupt/gpio pin to input
+ gpioSetDir (CHB_EINTPORT, CHB_EINTPIN, 0);
+
+ // set internal resistor on EINT pin to inactive
+ gpioSetPullup (&CHB_EINTPIN_IOCONREG, gpioPullupMode_Inactive);
+
+ // configure pin for interrupt
+ gpioSetInterrupt (CHB_EINTPORT,
+ CHB_EINTPIN,
+ gpioInterruptSense_Edge, // Edge-sensitive
+ gpioInterruptEdge_Single, // Single edge
+ gpioInterruptEvent_ActiveLow); // High triggers interrupt
+
+ // enable interrupt
+ gpioIntEnable (CHB_EINTPORT,
+ CHB_EINTPIN);
+
+ if (chb_get_state() != RX_STATE)
+ {
+ // ERROR occurred initializing the radio. Print out error message.
+ printf(chb_err_init);
+ }
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_drvr_init()
+{
+ // ToDo: Make sure gpioInit has been called
+ // ToDo: Make sure CT32B0 has been initialised and enabled
+
+ // config SPI for at86rf230 access
+ chb_spi_init();
+
+ // Setup 16-bit timer 0 (used for us delays)
+ timer16Init(0, 0xFFFF);
+ timer16Enable(0);
+
+ // Set sleep and reset as output
+ gpioSetDir(CHB_SLPTRPORT, CHB_SLPTRPIN, 1);
+ gpioSetDir(CHB_RSTPORT, CHB_RSTPIN, 1);
+
+ // configure IOs
+ gpioSetValue(CHB_SLPTRPORT, CHB_SLPTRPIN, 1); // Set sleep high
+ gpioSetValue(CHB_RSTPORT, CHB_RSTPIN, 1); // Set reset high
+
+ // Set internal resistors
+ gpioSetPullup (&CHB_SLPTRPIN_IOCONREG, gpioPullupMode_Inactive);
+ gpioSetPullup (&CHB_RSTPIN_IOCONREG, gpioPullupMode_Inactive);
+
+ // config radio
+ chb_radio_init();
+}
+
+/**************************************************************************/
+/*!
+ Enable or disable the radio's sleep mode.
+*/
+/**************************************************************************/
+void chb_sleep(U8 enb)
+{
+ if (enb)
+ {
+ // first we need to go to TRX OFF state
+ chb_set_state(TRX_OFF);
+
+ // set the SLPTR pin
+ // CHB_SLPTR_PORT |= _BV(CHB_SLPTR_PIN);
+ CHB_SLPTR_ENABLE();
+ }
+ else
+ {
+ // make sure the SLPTR pin is low first
+ // CHB_SLPTR_PORT &= ~(_BV(CHB_SLPTR_PIN));
+ CHB_SLPTR_DISABLE();
+
+ // we need to allow some time for the PLL to lock
+ chb_delay_us(TIME_SLEEP_TO_TRX_OFF);
+
+ // Turn the transceiver back on
+ chb_set_state(RX_STATE);
+ }
+}
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_ISR_Handler (void)
+{
+ // U8 dummy, state, intp_src = 0;
+ U8 state, intp_src = 0;
+ chb_pcb_t *pcb = chb_get_pcb();
+
+ CHB_ENTER_CRIT();
+
+ /*Read Interrupt source.*/
+ CHB_SPI_ENABLE();
+
+ /*Send Register address and read register content.*/
+ // dummy = chb_xfer_byte(IRQ_STATUS | CHB_SPI_CMD_RR);
+ chb_xfer_byte(IRQ_STATUS | CHB_SPI_CMD_RR);
+ intp_src = chb_xfer_byte(0);
+
+ CHB_SPI_DISABLE();
+
+ while (intp_src)
+ {
+ /*Handle the incomming interrupt. Prioritized.*/
+ if ((intp_src & CHB_IRQ_RX_START_MASK))
+ {
+ intp_src &= ~CHB_IRQ_RX_START_MASK;
+ }
+ else if (intp_src & CHB_IRQ_TRX_END_MASK)
+ {
+ state = chb_get_state();
+
+ if ((state == RX_ON) || (state == RX_AACK_ON) || (state == BUSY_RX_AACK))
+ {
+ // get the ed measurement
+ pcb->ed = chb_reg_read(PHY_ED_LEVEL);
+
+ // get the crc
+ pcb->crc = (chb_reg_read(PHY_RSSI) & (1<<7)) ? 1 : 0;
+
+ // if the crc is not valid, then do not read the frame and set the rx flag
+ if (pcb->crc)
+ {
+ // get the data
+ chb_frame_read();
+ pcb->rcvd_xfers++;
+ pcb->data_rcv = true;
+ }
+ }
+ else
+ {
+ pcb->tx_end = true;
+ }
+ intp_src &= ~CHB_IRQ_TRX_END_MASK;
+ while (chb_set_state(RX_STATE) != RADIO_SUCCESS);
+ }
+ else if (intp_src & CHB_IRQ_TRX_UR_MASK)
+ {
+ intp_src &= ~CHB_IRQ_TRX_UR_MASK;
+ pcb->underrun++;
+ }
+ else if (intp_src & CHB_IRQ_PLL_UNLOCK_MASK)
+ {
+ intp_src &= ~CHB_IRQ_PLL_UNLOCK_MASK;
+ }
+ else if (intp_src & CHB_IRQ_PLL_LOCK_MASK)
+ {
+ intp_src &= ~CHB_IRQ_PLL_LOCK_MASK;
+ }
+ else if (intp_src & CHB_IRQ_BAT_LOW_MASK)
+ {
+ intp_src &= ~CHB_IRQ_BAT_LOW_MASK;
+ pcb->battlow++;
+ }
+ else
+ {
+ }
+ }
+ CHB_LEAVE_CRIT();
+}
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+#ifndef CHIBI_DRVR_H
+#define CHIBI_DRVR_H
+
+#include "types.h"
+#include "projectconfig.h"
+#include "core/gpio/gpio.h"
+
+#define CHB_CC1190_PRESENT 0 /// Set to 1 if CC1190 is being used
+#define CHB_CHINA 0
+#define CHB_EEPROM_IEEE_ADDR CFG_CHIBI_EEPROM_IEEEADDR
+#define CHB_EEPROM_SHORT_ADDR CFG_CHIBI_EEPROM_SHORTADDR
+#define CHB_AT86RF212_VER_NUM 0x01
+#define CHB_AT86RF212_PART_NUM 0x07
+// #define CHB_BPSK 0 // set to 1 if want to use BPSK rather than OQPSK
+
+#define CHB_SPI_CMD_RW 0xC0 /**< Register Write (short mode). */
+#define CHB_SPI_CMD_RR 0x80 /**< Register Read (short mode). */
+#define CHB_SPI_CMD_FW 0x60 /**< Frame Transmit Mode (long mode). */
+#define CHB_SPI_CMD_FR 0x20 /**< Frame Receive Mode (long mode). */
+#define CHB_SPI_CMD_SW 0x40 /**< SRAM Write. */
+#define CHB_SPI_CMD_SR 0x00 /**< SRAM Read. */
+#define CHB_SPI_CMD_RADDRM 0x7F /**< Register Address Mask. */
+
+#define CHB_IRQ_BAT_LOW_MASK 0x80 /**< Mask for the BAT_LOW interrupt. */
+#define CHB_IRQ_TRX_UR_MASK 0x40 /**< Mask for the TRX_UR interrupt. */
+#define CHB_IRQ_TRX_END_MASK 0x08 /**< Mask for the TRX_END interrupt. */
+#define CHB_IRQ_RX_START_MASK 0x04 /**< Mask for the RX_START interrupt. */
+#define CHB_IRQ_PLL_UNLOCK_MASK 0x02 /**< Mask for the PLL_UNLOCK interrupt. */
+#define CHB_IRQ_PLL_LOCK_MASK 0x01 /**< Mask for the PLL_LOCK interrupt. */
+
+#define CHB_EINTPORT 1
+#define CHB_EINTPIN 8
+#define CHB_EINTPIN_IOCONREG IOCON_PIO1_8
+#define CHB_RSTPORT 1
+#define CHB_RSTPIN 9
+#define CHB_RSTPIN_IOCONREG IOCON_PIO1_9
+#define CHB_SLPTRPORT 1
+#define CHB_SLPTRPIN 10
+#define CHB_SLPTRPIN_IOCONREG IOCON_PIO1_10
+
+// if CC1190 present, set up the ports and pins for high gain mode control
+#if (CHB_CC1190_PRESENT)
+ #define CHB_CC1190_HGM_PORT 1
+ #define CHB_CC1190_HGM_PIN 11
+ #define CHB_CC1190_HGM_IOCONREG IOCON_PIO1_11
+#endif
+
+//#define CHB_DDR_SLPTR DDRF
+//#define CHB_DDR_RST DDRF
+//#define CHB_RADIO_IRQ INT6_vect
+//#define CHB_RADIO_IRQ_PIN INT6
+
+#define CHB_ENTER_CRIT() __disable_irq()
+#define CHB_LEAVE_CRIT() __enable_irq()
+#define CHB_RST_ENABLE() do {gpioSetValue(CHB_RSTPORT, CHB_RSTPIN, 0); } while (0)
+#define CHB_RST_DISABLE() do {gpioSetValue(CHB_RSTPORT, CHB_RSTPIN, 1); } while (0)
+#define CHB_SLPTR_ENABLE() do {gpioSetValue(CHB_SLPTRPORT, CHB_SLPTRPIN, 1); } while (0)
+#define CHB_SLPTR_DISABLE() do {gpioSetValue(CHB_SLPTRPORT, CHB_SLPTRPIN, 0); } while (0)
+
+// CCA constants
+enum
+{
+ CCA_ED = 1, /**< Use energy detection above threshold mode. */
+ CCA_CARRIER_SENSE = 2, /**< Use carrier sense mode. */
+ CCA_CARRIER_SENSE_WITH_ED = 3 /**< Use a combination of both energy detection and carrier sense. */
+};
+
+// configuration parameters
+enum
+{
+ CHB_CHANNEL = 1, // Replaced in projectconfig.h with CFG_CHIBI_CHANNEL
+ CHB_PAN_ID = 0x1234, // Replaced in projectconfig.h with CFG_CHIBI_PANID
+ CHB_TX_PWR = 0x0,
+ CHB_SHORT_ADDR = 0x0,
+ CHB_IEEE_ADDR = 0x0,
+ CHB_MAX_FRAME_RETRIES = 3,
+ CHB_MAX_CSMA_RETRIES = 4,
+ CHB_CCA_MODE = CCA_ED,
+ CHB_MIN_BE = 3,
+ CHB_MAX_BE = 5,
+ CHB_CCA_ED_THRES = 0x7,
+ CHB_CSMA_SEED0 = 0,
+ CHB_CSMA_SEED1 = 0,
+ CHB_FRM_VER = 1 // accept 802.15.4 ver 0 or 1 frames
+};
+
+// register addresses
+enum
+{
+ TRX_STATUS = 0x01,
+ TRX_STATE = 0x02,
+ TRX_CTRL_0 = 0x03,
+ TRX_CTRL_1 = 0x04,
+ PHY_TX_PWR = 0x05,
+ PHY_RSSI = 0x06,
+ PHY_ED_LEVEL = 0x07,
+ PHY_CC_CCA = 0x08,
+ CCA_THRES = 0x09,
+ RX_CTRL = 0x0a,
+ SFD_VALUE = 0x0b,
+ TRX_CTRL_2 = 0x0c,
+ ANT_DIV = 0x0d,
+ IRQ_MASK = 0x0e,
+ IRQ_STATUS = 0x0f,
+ VREG_CTRL = 0x10,
+ BATMON = 0x11,
+ XOSC_CTRL = 0x12,
+ CC_CTRL_0 = 0x13,
+ CC_CTRL_1 = 0x14,
+ RX_SYN = 0x15,
+ RF_CTRL_0 = 0x16,
+ XAH_CTRL_1 = 0x17,
+ FTN_CTRL = 0x18,
+ RF_CTRL_1 = 0x19,
+ PLL_CF = 0x1a,
+ PLL_DCU = 0x1b,
+ PART_NUM = 0x1c,
+ VERSION_NUM = 0x1d,
+ MAN_ID_0 = 0x1e,
+ MAN_ID_1 = 0x1f,
+ SHORT_ADDR_0 = 0x20,
+ SHORT_ADDR_1 = 0x21,
+ PAN_ID_0 = 0x22,
+ PAN_ID_1 = 0x23,
+ IEEE_ADDR_0 = 0x24,
+ IEEE_ADDR_1 = 0x25,
+ IEEE_ADDR_2 = 0x26,
+ IEEE_ADDR_3 = 0x27,
+ IEEE_ADDR_4 = 0x28,
+ IEEE_ADDR_5 = 0x29,
+ IEEE_ADDR_6 = 0x2a,
+ IEEE_ADDR_7 = 0x2b,
+ XAH_CTRL_0 = 0x2c,
+ CSMA_SEED_0 = 0x2d,
+ CSMA_SEED_1 = 0x2e,
+ CSMA_BE = 0x2f
+};
+
+// random defines
+enum
+{
+ CHB_MAX_FRAME_RETRIES_POS = 4,
+ CHB_MAX_CSMA_RETIRES_POS = 1,
+ CHB_CSMA_SEED1_POS = 0,
+ CHB_CCA_MODE_POS = 5,
+ CHB_AUTO_CRC_POS = 5,
+ CHB_TRX_END_POS = 3,
+ CHB_TRAC_STATUS_POS = 5,
+ CHB_FVN_POS = 6,
+ CHB_OQPSK_TX_OFFSET = 2,
+ CHB_BPSK_TX_OFFSET = 3,
+ CHB_MIN_FRAME_LENGTH = 3,
+ CHB_MAX_FRAME_LENGTH = 0x7f,
+ CHB_PA_EXT_EN_POS = 7
+};
+
+// transceiver timing
+enum{
+ TIME_RST_PULSE_WIDTH = 1,
+ TIME_P_ON_TO_CLKM_AVAIL = 380,
+ TIME_SLEEP_TO_TRX_OFF = 240,
+ TIME_TRX_OFF_TO_SLEEP = 35,
+ TIME_PLL_ON_TRX_OFF = 1,
+ TIME_TRX_OFF_RX_ON = 110,
+ TIME_RX_ON_TRX_OFF = 1,
+ TIME_PLL_ON_RX_ON = 1,
+ TIME_RX_ON_PLL_ON = 1,
+ TIME_PLL_LOCK_TIME = 110,
+ TIME_BUSY_TX_PLL_ON = 32,
+ TIME_ALL_STATES_TRX_OFF = 1,
+ TIME_RESET_TRX_OFF = 26,
+ TIME_TRX_IRQ_DELAY = 9,
+ TIME_TRX_OFF_PLL_ON = 110,
+ TIME_IRQ_PROCESSING_DLY = 32
+};
+
+// trac status
+enum{
+ TRAC_SUCCESS = 0,
+ TRAC_SUCCESS_DATA_PENDING = 1,
+ TRAC_WAIT_FOR_ACK = 2,
+ TRAC_CHANNEL_ACCESS_FAIL = 3,
+ TRAC_NO_ACK = 5,
+ TRAC_INVALID = 7
+};
+
+// radio statuses
+enum{
+ RADIO_SUCCESS = 0x40, /**< The requested service was performed successfully. */
+ RADIO_UNSUPPORTED_DEVICE, /**< The connected device is not an Atmel AT86RF212. */
+ RADIO_INVALID_ARGUMENT, /**< One or more of the supplied function arguments are invalid. */
+ RADIO_TIMED_OUT, /**< The requested service timed out. */
+ RADIO_WRONG_STATE, /**< The end-user tried to do an invalid state transition. */
+ RADIO_BUSY_STATE, /**< The radio transceiver is busy receiving or transmitting. */
+ RADIO_STATE_TRANSITION_FAILED, /**< The requested state transition could not be completed. */
+ RADIO_CCA_IDLE, /**< Channel is clear, available to transmit a new frame. */
+ RADIO_CCA_BUSY, /**< Channel busy. */
+ RADIO_TRX_BUSY, /**< Transceiver is busy receiving or transmitting data. */
+ RADIO_BAT_LOW, /**< Measured battery voltage is lower than voltage threshold. */
+ RADIO_BAT_OK, /**< Measured battery voltage is above the voltage threshold. */
+ RADIO_CRC_FAILED, /**< The CRC failed for the actual frame. */
+ RADIO_CHANNEL_ACCESS_FAILURE, /**< The channel access failed during the auto mode. */
+ RADIO_NO_ACK, /**< No acknowledge frame was received. */
+};
+
+// transceiver commands
+enum
+{
+ CMD_NOP = 0,
+ CMD_TX_START = 2,
+ CMD_FORCE_TRX_OFF = 3,
+ CMD_FORCE_PLL_ON = 4,
+ CMD_RX_ON = 6,
+ CMD_TRX_OFF = 8,
+ CMD_PLL_ON = 9,
+ CMD_RX_AACK_ON = 22,
+ CMD_TX_ARET_ON = 25
+};
+
+// transceiver states
+enum
+{
+ P_ON = 0,
+ BUSY_RX = 1,
+ BUSY_TX = 2,
+ RX_ON = 6,
+ TRX_OFF = 8,
+ PLL_ON = 9,
+ SLEEP = 15,
+ BUSY_RX_AACK = 17,
+ BUSY_TX_ARET = 18,
+ RX_AACK_ON = 22,
+ TX_ARET_ON = 25,
+ RX_ON_NOCLK = 28,
+ RX_AACK_ON_NOCLK = 29,
+ BUSY_RX_AACK_NOCLK = 30,
+ TRANS_IN_PROG = 31
+};
+
+// transceiver interrupt register
+enum
+{
+ IRQ_PLL_LOCK = 0,
+ IRQ_PLL_UNLOCK = 1,
+ IRQ_RX_START = 2,
+ IRQ_TRX_END = 3,
+ IRQ_CCA_ED_READY = 4,
+ IRQ_AMI = 5,
+ IRQ_TRX_UR = 6,
+ IRQ_BAT_LOW = 7
+};
+
+// transceiver modes
+enum
+{
+ OQPSK_868MHZ = 0,
+ OQPSK_915MHZ = 1,
+ OQPSK_780MHZ = 2,
+ BPSK40_915MHZ = 3,
+ BPSK20_868MHZ = 4
+};
+
+// See Table 7-15 for details
+enum
+{
+ CHB_PWR_EU1_2DBM = 0x63, // EU (868MHz) Linearized PA mode
+ CHB_PWR_EU1_1DBM = 0x64, // Note: BPSK 20kbit/s only!
+ CHB_PWR_EU1_0DBM = 0x65,
+ CHB_PWR_EU2_5DBM = 0xE7, // EU (868MHz) Boost mode (but > supply current)
+ CHB_PWR_EU2_4DBM = 0xE8, // 4-5dBM BPSK 20 kbit/s only!
+ CHB_PWR_EU2_3DBM = 0xE9, // 0-3dBM O-QPSK 100/200/400 kbit/s or BPSK
+ CHB_PWR_EU2_2DBM = 0xEA,
+ CHB_PWR_EU2_1DBM = 0xCB,
+ CHB_PWR_EU2_0DBM = 0xAB,
+ CHB_PWR_NA_10DBM = 0xC0, // North America (915MHz)
+ CHB_PWR_NA_9DBM = 0xA1,
+ CHB_PWR_NA_8DBM = 0x81,
+ CHB_PWR_NA_7DBM = 0x82,
+ CHB_PWR_NA_6DBM = 0x83,
+ CHB_PWR_NA_5DBM = 0x60,
+ CHB_PWR_NA_4DBM = 0x61,
+ CHB_PWR_NA_3DBM = 0x41,
+ CHB_PWR_NA_2DBM = 0x42,
+ CHB_PWR_NA_1DBM = 0x22,
+ CHB_PWR_NA_0DBM = 0x23,
+ CHB_PWR_CHINA_5DBM = 0xE7, // China (780MHz)
+ CHB_PWR_CHINA_4DBM = 0xE8,
+ CHB_PWR_CHINA_3DBM = 0xE9,
+ CHB_PWR_CHINA_2DBM = 0xEA,
+ CHB_PWR_CHINA_1DBM = 0xCA,
+ CHB_PWR_CHINA_0DBM = 0xAA
+};
+
+// define receive state based on promiscuous mode setting
+#if (CFG_CHIBI_PROMISCUOUS == 1)
+ #define RX_STATE RX_ON
+#else
+ #define RX_STATE RX_AACK_ON
+#endif
+// init
+void chb_drvr_init();
+
+// data access
+U8 chb_reg_read(U8 addr);
+U16 chb_reg_read16(U8 addr);
+void chb_reg_write(U8 addr, U8 val);
+void chb_reg_write16(U8 addr, U16 val);
+void chb_reg_write64(U8 addr, U8 *val);
+void chb_reg_read_mod_write(U8 addr, U8 val, U8 mask);
+void chb_frame_write(U8 *hdr, U8 hdr_len, U8 *data, U8 data_len);
+
+// general configuration
+void chb_set_mode(U8 mode);
+U8 chb_set_channel(U8 channel);
+void chb_set_pwr(U8 val);
+void chb_set_ieee_addr(U8 *addr);
+void chb_get_ieee_addr(U8 *addr);
+void chb_set_short_addr(U16 addr);
+U16 chb_get_short_addr();
+U8 chb_set_state(U8 state);
+
+// Power management
+void chb_sleep(U8 enb);
+
+// data transmit
+U8 chb_tx(U8 *hdr, U8 *data, U8 len);
+
+#if (CHB_CC1190_PRESENT)
+ void chb_set_hgm(U8 enb);
+#endif
+
+#ifdef CHB_DEBUG
+// sram access
+void chb_sram_read(U8 addr, U8 len, U8 *data);
+void chb_sram_write(U8 addr, U8 len, U8 *data);
+#endif
+
+void chb_ISR_Handler (void);
+
+#endif
+
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+/*!
+ \file
+ \ingroup
+
+
+*/
+/**************************************************************************/
+#include "chb_eeprom.h"
+#include "drivers/storage/eeprom/eeprom.h"
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_eeprom_write(uint16_t addr, uint8_t *buf, uint16_t size)
+{
+ // Write the address one byte at a time
+ uint16_t a = 0;
+ while (a < size)
+ {
+ eepromWriteU8(addr + a, buf[a]);
+ a++;
+ }
+}
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_eeprom_read(uint16_t addr, uint8_t *buf, uint16_t size)
+{
+ // Read the contents at address
+ eepromReadBuffer(addr, buf, size);
+}
+
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+/*!
+ \file
+ \ingroup
+
+
+*/
+/**************************************************************************/
+#ifndef CHB_EEPROM_H
+#define CHB_EEPROM_H
+
+#include "projectconfig.h"
+#include "types.h"
+
+void chb_eeprom_write(U16 addr, U8 *buf, U16 size);
+void chb_eeprom_read(U16 addr, U8 *buf, U16 size);
+
+#endif
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+/*!
+ \file
+ \ingroup
+
+
+*/
+/**************************************************************************/
+#include "chb.h"
+#include "chb_spi.h"
+#include "core/ssp/ssp.h"
+
+/**************************************************************************/
+/*!
+
+*/
+/**************************************************************************/
+void chb_spi_init()
+{
+ // initialise spi, high between frames and transition on trailing edge
+ sspInit(0, sspClockPolarity_High, sspClockPhase_FallingEdge);
+
+ // set the slave select to idle
+ CHB_SPI_DISABLE();
+}
+
+/**************************************************************************/
+/*!
+ This function both reads and writes data. For write operations, include data
+ to be written as argument. For read ops, use dummy data as arg. Returned
+ data is read byte val.
+*/
+/**************************************************************************/
+U8 chb_xfer_byte(U8 data)
+{
+ /* Move on only if NOT busy and TX FIFO not full */
+ while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_MASK | SSP_SSP0SR_BSY_MASK)) != SSP_SSP0SR_TNF_NOTFULL);
+ SSP_SSP0DR = data;
+
+ /* Wait until the busy bit is cleared and receive buffer is not empty */
+ while ((SSP_SSP0SR & (SSP_SSP0SR_BSY_MASK | SSP_SSP0SR_RNE_MASK)) != SSP_SSP0SR_RNE_NOTEMPTY);
+
+ // Read the queue
+ return SSP_SSP0DR;
+}
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+
+*******************************************************************/
+/*!
+ \file
+ \ingroup
+
+
+*/
+/**************************************************************************/
+
+#ifndef CHB_SPI_H
+#define CHB_SPI_H
+
+#include "projectconfig.h"
+#include "core/gpio/gpio.h"
+
+#define CHB_SSPORT (0) // P0.2 = SSEL
+#define CHB_SSPIN (2)
+
+#define CHB_SPI_ENABLE() do {gpioSetValue(CHB_SSPORT, CHB_SSPIN, 0);} while (0) // Drive SSEL low
+#define CHB_SPI_DISABLE() do {gpioSetValue(CHB_SSPORT, CHB_SSPIN, 1);} while (0) // Drive SSEL high
+
+#define CHB_SPIPORT 0
+#define CHB_SCK 1 // PB.1 - Output: SPI Serial Clock (SCLK)
+#define CHB_MOSI 2 // PB.2 - Output: SPI Master out - slave in (MOSI)
+#define CHB_MISO 3 // PB.3 - Input: SPI Master in - slave out (MISO)
+
+void chb_spi_init();
+U8 chb_xfer_byte(U8 data);
+
+#endif
--- /dev/null
+/*******************************************************************
+ Copyright (C) 2009 FreakLabs
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Originally written by Christopher Wang aka Akiba.
+ Please post support questions to the FreakLabs forum.
+*******************************************************************/
+/*!
+ \file types.h
+ \ingroup usb
+*/
+/*******************************************************************/
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// Standard data types
+typedef uint8_t U8; /// Generic 8 bit unsigned data type
+typedef uint16_t U16; /// Generic 16 bit unsigned data type
+typedef uint32_t U32; /// Generic 32 bit unsigned data type
+typedef uint64_t U64; /// Generic 64 bit unsigned data type
+
+typedef int8_t S8; /// Generic 8 bit signed data type
+typedef int16_t S16; /// Generic 16 bit signed data type
+typedef int32_t S32; /// Generic 32 bit signed data type
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_MIFARE_H__
+#define __PN532_MIFARE_H__
+
+#include "projectconfig.h"
+
+// These may need to be enlarged for multi card support
+#define PN532_RESPONSELEN_INLISTPASSIVETARGET (64)
+#define PN532_RESPONSELEN_INDATAEXCHANGE (64)
+
+typedef enum pn532_mifare_cmd_e
+{
+ PN532_MIFARE_CMD_AUTH_A = 0x60,
+ PN532_MIFARE_CMD_AUTH_B = 0x61,
+ PN532_MIFARE_CMD_READ = 0x30,
+ PN532_MIFARE_CMD_WRITE = 0xA0,
+ PN532_MIFARE_CMD_TRANSFER = 0xB0,
+ PN532_MIFARE_CMD_DECREMENT = 0xC0,
+ PN532_MIFARE_CMD_INCREMENT = 0xC1,
+ PN532_MIFARE_CMD_STORE = 0xC2
+}
+pn532_mifare_cmd_t;
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_classic.c
+*/
+/**************************************************************************/
+
+/* MIFARE CLASSIC DESCRIPTION
+ ==========================
+
+ MIFARE Classic cards come in 1K and 4K varieties. While several
+ varieties of chips exist, the two main chipsets used are described
+ in the following publicly accessible documents:
+
+ MF1S503x Mifare Classic 1K data sheet:
+ http://www.nxp.com/documents/data_sheet/MF1S503x.pdf
+
+ MF1S70yyX MIFARE Classic 4K data sheet:
+ http://www.nxp.com/documents/data_sheet/MF1S70YYX.pdf
+
+ Mifare Classic cards typically have a a 4-byte NUID, though you may
+ find cards with 7 byte IDs as well
+
+ EEPROM MEMORY
+ =============
+ Mifare Classic cards have either 1K or 4K of EEPROM memory. Each
+ memory block can be configured with different access conditions,
+ with two seperate authentication keys present in each block.
+
+ The two main Mifare Classic card types are organised as follows:
+
+ 1K Cards: 16 sectors of 4 blocks (0..15)
+ 4K Cards: 32 sectors of 4 blocks (0..31) and
+ 8 sectors of 16 blocks (32..39)
+
+ 4 block sectors
+ ===============
+ Sector Block Bytes Description
+ ------ ----- ----- -----------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+
+ 1 3 [-------KEY A-------] [Access Bits] [-------KEY A-------] Sector Trailer 1
+ 2 [ Data ] Data
+ 1 [ Data ] Data
+ 0 [ Data ] Data
+
+ 0 3 [-------KEY A-------] [Access Bits] [-------KEY A-------] Sector Trailer 1
+ 2 [ Data ] Data
+ 1 [ Data ] Data
+ 0 [ Manufacturer Data ] Manufacturer Block
+
+ Sector Trailer (Block 3)
+ ------------------------
+ The sector trailer block contains the two secret keys (Key A and Key B), as well
+ as the access conditions for the four blocks. It has the following structure:
+
+ Sector Trailer Bytes
+ --------------------------------------------------------------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ [ Key A ] [Access Bits] [ Key B ]
+
+ For more information in using Keys to access the clock contents, see
+ Accessing Data Blocks further below.
+
+ Data Blocks (Blocks 0..2)
+ -------------------------
+ Data blocks are 16 bytes wide and, depending on the permissions set in the
+ access bits, can be read from and written to. You are free to use the 16 data
+ bytes in any way you wish. You can easily store text input, store four 32-bit
+ integer values, a 16 character uri, etc.
+
+ Data Blocks as "Value Blocks"
+ -----------------------------
+ An alternative to storing random data in the 16 byte-wide blocks is to
+ configure them as "Value Blocks". Value blocks allow performing electronic
+ purse functions (valid commands are: read, write, increment, decrement,
+ restore, transfer).
+
+ Each Value block contains a single signed 32-bit value, and this value is
+ stored 3 times for data integrity and security reasons. It is stored twice
+ non-inverted, and once inverted. The last 4 bytes are used for a 1-byte
+ address, which is stored 4 times (twice non-inverted, and twice inverted).
+
+ Data blocks configured as "Value Blocks" have the following structure:
+
+ Value Block Bytes
+ --------------------------------------------------------------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ [ Value ] [ ~Value ] [ Value ] [A ~A A ~A]
+
+ Manufacturer Block (Sector 0, Block 0)
+ --------------------------------------
+ Sector 0 is special since it contains the Manufacturer Block. This block
+ contains the manufacturer data, and is read-only. It should be avoided
+ unless you know what you are doing.
+
+ 16 block sectors
+ ================
+ 16 block sectors are identical to 4 block sectors, but with more data blocks. The same
+ structure described in the 4 block sectors above applies.
+
+ Sector Block Bytes Description
+ ------ ----- ----- ----------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+
+ 32 15 [-------KEY A-------] [Access Bits] [-------KEY B-------] Sector Trailer 32
+ 14 [ Data ] Data
+ 13 [ Data ] Data
+ ...
+ 2 [ Data ] Data
+ 1 [ Data ] Data
+ 0 [ Data ] Data
+
+ ACCESSING DATA BLOCKS
+ =====================
+
+ Before you can access the cards, you must following two steps:
+
+ 1.) You must retrieve the 7 byte UID or the 4-byte NUID of the card.
+ This can be done using pn532_mifareclassic_WaitForPassiveTarget()
+ below, which will return the appropriate ID.
+
+ 2.) You must authenticate the sector you wish to access according to the
+ access rules defined in the Sector Trailer block for that sector.
+ This can be done using pn532_mifareclassic_AuthenticateBlock(),
+ passing in the appropriate key value.
+
+ Most new cards have a default Key A of 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF,
+ but some common values worth trying are:
+
+ 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
+ 0XD3 0XF7 0XD3 0XF7 0XD3 0XF7
+ 0XA0 0XA1 0XA2 0XA3 0XA4 0XA5
+ 0XB0 0XB1 0XB2 0XB3 0XB4 0XB5
+ 0X4D 0X3A 0X99 0XC3 0X51 0XDD
+ 0X1A 0X98 0X2C 0X7E 0X45 0X9A
+ 0XAA 0XBB 0XCC 0XDD 0XEE 0XFF
+ 0X00 0X00 0X00 0X00 0X00 0X00
+ 0XAB 0XCD 0XEF 0X12 0X34 0X56
+
+ 3.) Once authenication has succeeded, and depending on the sector
+ permissions, you can then read/write/increment/decrement the
+ contents of the specific block, using one of the helper functions
+ included in this module.
+
+*/
+
+#include <string.h>
+
+#include "../pn532.h"
+#include "../pn532_bus.h"
+#include "pn532_mifare.h"
+#include "pn532_mifare_classic.h"
+
+#include "core/systick/systick.h"
+
+/**************************************************************************/
+/*!
+ Indicates whether the specified block number is the first block
+ in the sector (block 0 relative to the current sector)
+*/
+/**************************************************************************/
+bool is_first_block (uint32_t uiBlock)
+{
+ // Test if we are in the small or big sectors
+ if (uiBlock < 128)
+ return ((uiBlock) % 4 == 0);
+ else
+ return ((uiBlock) % 16 == 0);
+}
+
+/**************************************************************************/
+/*!
+ Indicates whether the specified block number is the sector trailer
+*/
+/**************************************************************************/
+bool is_trailer_block (uint32_t uiBlock)
+{
+ // Test if we are in the small or big sectors
+ if (uiBlock < 128)
+ return ((uiBlock + 1) % 4 == 0);
+ else
+ return ((uiBlock + 1) % 16 == 0);
+}
+
+/**************************************************************************/
+/*!
+ Tries to detect MIFARE targets in passive mode. This needs to be done
+ before anything useful can be accomplished with a tag since you need
+ the tag's unique UID to communicate with it.
+
+ @param pbtCUID Pointer to the byte array where the card's UID
+ will be stored once a card is detected
+ @param pszUIDLen Pointer to the size of the card UID in bytes
+
+ Response for a valid ISO14443A 106KBPS (Mifare Classic, etc.)
+ should be in the following format. See UM0701-02 section
+ 7.3.5 for more information
+
+ byte Description
+ ------------- ------------------------------------------
+ b0..6 Frame header and preamble
+ b7 Tags Found
+ b8 Tag Number (only one used in this example)
+ b9..10 SENS_RES
+ b11 SEL_RES
+ b12 NFCID Length
+ b13..NFCIDLen NFCID
+
+ SENS_RES SEL_RES Manufacturer/Card Type NFCID Len
+ -------- ------- ----------------------- ---------
+ 00 04 08 NXP Mifare Classic 1K 4 bytes
+ 00 02 18 NXP Mifare Classic 4K 4 bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_WRONGCARDTYPE
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen)
+{
+ byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET];
+ pn532_error_t error;
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Try to initialise a single ISO14443A tag at 106KBPS */
+ /* Note: To wait for a card with a known UID, append the four byte */
+ /* UID to the end of the command. */
+ byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS};
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ return error;
+
+ /* Wait until we get a valid response or a timeout */
+ do
+ {
+ systickDelay(25);
+ error = pn532Read(abtResponse, &szLen);
+ } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ return error;
+
+ /* Check SENSE_RES to make sure this is a Mifare Classic card */
+ /* Classic 1K = 00 04 */
+ /* Classic 4K = 00 02 */
+ /* Classic Emulated = 00 08 */
+ if ((abtResponse[10] == 0x02) ||
+ (abtResponse[10] == 0x04) ||
+ (abtResponse[10] == 0x08))
+ {
+ /* Card appears to be Mifare Classic */
+ *szCUIDLen = abtResponse[12];
+ uint8_t i;
+ for (i=0; i < *szCUIDLen; i++)
+ {
+ pbtCUID[i] = abtResponse[13+i];
+ }
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA: ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID: ");
+ pn532PrintHex(pbtCUID, *szCUIDLen);
+ #endif
+ }
+ else
+ {
+ /* Card is ISO14443A but doesn't appear to be Mifare Classic */
+ /* Mifare Ultralight = 0x0044 */
+ /* Mifare DESFire = 0x0344 */
+ /* Innovision Jewel = 0x0C00 */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Wrong Card Type (Expected ATQA 00 02, 00 04 or 00 08) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA : ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID : ");
+ size_t pos;
+ for (pos=0; pos < abtResponse[12]; pos++)
+ {
+ printf("%02x ", abtResponse[13 + pos]);
+ }
+ printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_WRONGCARDTYPE;
+ }
+
+ return PN532_ERROR_NONE;
+}
+
+
+/**************************************************************************/
+/*!
+ Tries to authenticate a block of memory on a MIFARE card using the
+ INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
+ for more information on sending MIFARE and other commands.
+
+ @param pbtCUID Pointer to a byte array containing the card UID
+ @param szCUIDLen The length (in bytes) of the card's UID (Should
+ be 4 for MIFARE Classic)
+ @param uiBlockNumber The block number to authenticate. (0..63 for
+ 1KB cards, and 0..255 for 4KB cards).
+ @param uiKeyType Which key type to use during authentication
+ (PN532_MIFARE_CMD_AUTH_A or PN532_MIFARE_CMD_AUTH_B)
+ @param pbtKeys Pointer to a byte array containing the 6 byte
+ key value
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys)
+{
+ pn532_error_t error;
+ byte_t abtCommand[17];
+ byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Trying to authenticate card ");
+ pn532PrintHex(pbtCUID, szCUIDLen);
+ #endif
+
+ /* Prepare the authentication command */
+ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
+ abtCommand[1] = 1; /* Max card numbers */
+ abtCommand[2] = (uiKeyType) ? PN532_MIFARE_CMD_AUTH_A : PN532_MIFARE_CMD_AUTH_B;
+ abtCommand[3] = uiBlockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
+ memcpy (abtCommand+4, pbtKeys, 6);
+ uint8_t i;
+ for (i = 0; i < szCUIDLen; i++)
+ {
+ abtCommand[10+i] = pbtCUID[i]; /* 4 byte card ID */
+ }
+
+ /* Send the command */
+ error = pn532Write(abtCommand, 10+szCUIDLen);
+ if (error)
+ {
+ /* Problem with the serial bus, etc. */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Read the authentication response */
+ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
+ do
+ {
+ systickDelay(25);
+ error = pn532Read(abtResponse, &szLen);
+ }
+ while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ // ToDo: How to check if authentification really worked (bad key, etc.)?
+
+ /* Output the authentification data */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Authenticated block %d %s", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ #endif
+
+ // Return OK signal
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ Tries to read an entire 16-byte data block at the specified block
+ address.
+
+ @param uiBlockNumber The block number to authenticate. (0..63 for
+ 1KB cards, and 0..255 for 4KB cards).
+ @param pbtData Pointer to the byte array that will hold the
+ retrieved data (if any)
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_BLOCKREADFAILED
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareclassic_ReadDataBlock (uint8_t uiBlockNumber, byte_t * pbtData)
+{
+ pn532_error_t error;
+ byte_t abtCommand[4];
+ byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Reading 16 bytes at block %03d%s", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Prepare the command */
+ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE;
+ abtCommand[1] = 1; /* Card number */
+ abtCommand[2] = PN532_MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
+ abtCommand[3] = uiBlockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
+
+ /* Send the commands */
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ {
+ /* Bus error, etc. */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Read the response */
+ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
+ do
+ {
+ systickDelay(50);
+ error = pn532Read(abtResponse, &szLen);
+ }
+ while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Make sure we have a valid response (should be 26 bytes long) */
+ if (szLen == 26)
+ {
+ /* Copy the 16 data bytes to the output buffer */
+ /* Block content starts at byte 9 of a valid response */
+ memcpy (pbtData, abtResponse+8, 16);
+ }
+ else
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Unexpected response reading block %d. Bad key?%s", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_BLOCKREADFAILED;
+ }
+
+ /* Display data for debug if requested */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Block %03d: ", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ pn532PrintHexVerbose(pbtData, 16);
+ #endif
+
+ // Return OK signal
+ return PN532_ERROR_NONE;
+}
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_classic.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_MIFARE_CLASSIC_H__
+#define __PN532_MIFARE_CLASSIC_H__
+
+#include "projectconfig.h"
+#include "pn532_mifare.h"
+
+pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen);
+pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys);
+pn532_error_t pn532_mifareclassic_ReadDataBlock (uint8_t uiBlockNumber, byte_t * pbtData);
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_ultralight.c
+*/
+/**************************************************************************/
+
+/* MIFARE ULTRALIGHT DESCRIPTION
+ =============================
+
+ MIFARE Ultralight cards typically contain 512 bits (64 bytes) of
+ memory, including 4 bytes (32-bits) of OTP (One Time Programmable)
+ memory where the individual bits can be written but not erased.
+
+ MF0ICU1 Mifare Ultralight Functional Specification:
+ http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
+
+
+ Mifare Ultralight cards have a 7-byte UID
+
+ EEPROM MEMORY
+ =============
+ Mifare Ultralight cards have 512 bits (64 bytes) of EEPROM memory,
+ including 4 byte (32 bits) of OTP memory. Unlike Mifare Classic cards,
+ there is no authentication on a per block level, although the blocks
+ can be set to "read-only" mode using Lock Bytes (described below).
+
+ EEPROM memory is organised into 16 pages of four bytes eachs, in
+ the following order
+
+ Page Description
+ ---- ------------
+ 0 Serial Number (4 bytes)
+ 1 Serial Number (4 bytes)
+ 2 Byte 0: Serial Number
+ Byte 1: Internal Memory
+ Byte 2..3: lock bytes
+ 3 One-time programmable memory (4 bytes)
+ 4..15 User memory (4 bytes)
+
+ Lock Bytes (Page 2)
+ -------------------
+ Bytes 2 and 3 of page 2 are referred to as "Lock Bytes". Each
+ page from 0x03 and higher can individually locked by setting the
+ corresponding locking bit to "1" to prevent further write access,
+ effectively making the memory read only.
+
+ For information on the lock byte mechanism, refer to section 8.5.2 of
+ the datasheet (referenced above).
+
+ OTP Bytes (Page 3)
+ ------------------
+ Page 3 is the OTP memory, and by default all bits on this page are
+ set to 0. These bits can be bitwise modified using the Mifare WRITE
+ command, and individual bits can be set to 1, but can not be changed
+ back to 0.
+
+ Data Pages (Pages 4..15)
+ ------------------------
+ Pages 4 to 15 are can be freely read from and written to,
+ provided there is no conflict with the Lock Bytes described above.
+
+ After production, the bytes have the following default values:
+
+ Page Byte Values
+ ---- ----------------------
+ 0 1 2 3
+ 4 0xFF 0xFF 0xFF 0xFF
+ 5..15 0x00 0x00 0x00 0x00
+
+ ACCESSING DATA BLOCKS
+ =====================
+
+ Before you can access the cards, you must following two steps:
+
+ 1.) 'Connect' to a Mifare Ultralight card and retrieve the 7 byte
+ UID of the card.
+
+ 2.) Memory can be read and written directly once a passive mode
+ connection has been made. No authentication is required for
+ Mifare Ultralight cards.
+
+*/
+
+#include <string.h>
+
+#include "../pn532.h"
+#include "../pn532_bus.h"
+#include "pn532_mifare_ultralight.h"
+
+#include "core/systick/systick.h"
+
+/**************************************************************************/
+/*!
+ Tries to detect MIFARE targets in passive mode.
+
+ @param pbtCUID Pointer to the byte array where the card's 7 byte
+ UID will be stored once a card is detected
+ @param pszUIDLen Pointer to the size of the card UID in bytes
+
+ Response for a valid ISO14443A 106KBPS (Mifare Ultralight, etc.)
+ should be in the following format. See UM0701-02 section
+ 7.3.5 for more information
+
+ byte Description
+ ------------- ------------------------------------------
+ b0..6 Frame header and preamble
+ b7 Tags Found
+ b8 Tag Number (only one used in this example)
+ b9..10 SENS_RES
+ b11 SEL_RES
+ b12 NFCID Length
+ b13..NFCIDLen NFCID
+
+ SENS_RES SEL_RES Manufacturer/Card Type NFCID Len
+ -------- ------- ----------------------- ---------
+ 00 44 00 NXP Mifare Ultralight 7 bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_WRONGCARDTYPE
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareultralight_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen)
+{
+ byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET];
+ pn532_error_t error;
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Try to initialise a single ISO14443A tag at 106KBPS */
+ /* Note: To wait for a card with a known UID, append the four byte */
+ /* UID to the end of the command. */
+ byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS};
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ return error;
+
+ /* Wait until we get a valid response or a timeout */
+ do
+ {
+ systickDelay(25);
+ error = pn532Read(abtResponse, &szLen);
+ } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ return error;
+
+ /* Check SENS_RES to make sure this is a Mifare Ultralight card */
+ /* Mifare Ultralight = 00 44 */
+ if (abtResponse[10] == 0x44)
+ {
+ /* Card appears to be Mifare Ultralight */
+ *szCUIDLen = abtResponse[12];
+ uint8_t i;
+ for (i=0; i < *szCUIDLen; i++)
+ {
+ pbtCUID[i] = abtResponse[13+i];
+ }
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA: ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID: ");
+ pn532PrintHex(pbtCUID, *szCUIDLen);
+ #endif
+ }
+ else
+ {
+ /* Card is ISO14443A but doesn't appear to be Mifare Ultralight */
+ /* Mifare Classic = 0x0002, 0x0004, 0x0008 */
+ /* Mifare DESFire = 0x0344 */
+ /* Innovision Jewel = 0x0C00 */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Wrong Card Type (Expected ATQA 00 44) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA : ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID : ");
+ size_t pos;
+ for (pos=0; pos < abtResponse[12]; pos++)
+ {
+ printf("%02x ", abtResponse[13 + pos]);
+ }
+ printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_WRONGCARDTYPE;
+ }
+
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ Tries to read an entire 4-byte page at the specified address.
+
+ @param page The page number (0..63 in most cases)
+ @param pbtBuffer Pointer to the byte array that will hold the
+ retrieved data (if any)
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_ADDRESSOUTOFRANGE
+ - PN532_ERROR_BLOCKREADFAILED
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareultralight_ReadPage (uint8_t page, byte_t * pbtBuffer)
+{
+ pn532_error_t error;
+ byte_t abtCommand[4];
+ byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
+ size_t szLen;
+
+ if (page >= 64)
+ {
+ return PN532_ERROR_ADDRESSOUTOFRANGE;
+ }
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Reading page %03d%s", page, CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Prepare the command */
+ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE;
+ abtCommand[1] = 1; /* Card number */
+ abtCommand[2] = PN532_MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
+ abtCommand[3] = page; /* Page Number (0..63 in most cases) */
+
+ /* Send the commands */
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ {
+ /* Bus error, etc. */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Read the response */
+ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
+ do
+ {
+ systickDelay(50);
+ error = pn532Read(abtResponse, &szLen);
+ }
+ while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Make sure we have a valid response (should be 26 bytes long) */
+ if (szLen == 26)
+ {
+ /* Copy the 4 data bytes to the output buffer */
+ /* Block content starts at byte 9 of a valid response */
+ /* Note that the command actually reads 16 byte or 4 */
+ /* pages at a time ... we simply discard the last 12 */
+ /* bytes */
+ memcpy (pbtBuffer, abtResponse+8, 4);
+ }
+ else
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Unexpected response reading block %d. Bad key?%s", page, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_BLOCKREADFAILED;
+ }
+
+ /* Display data for debug if requested */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Page %02d: ", page, CFG_PRINTF_NEWLINE);
+ pn532PrintHexVerbose(pbtBuffer, 4);
+ #endif
+
+ // Return OK signal
+ return PN532_ERROR_NONE;
+}
+
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_ultralight.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_MIFARE_ULTRALIGHT_H__
+#define __PN532_MIFARE_ULTRALIGHT_H__
+
+#include "projectconfig.h"
+#include "pn532_mifare.h"
+
+pn532_error_t pn532_mifareultralight_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen);
+pn532_error_t pn532_mifareultralight_ReadPage (uint8_t page, byte_t * pbtBuffer);
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532.c
+*/
+/**************************************************************************/
+#include <string.h>
+
+#include "pn532.h"
+#include "pn532_bus.h"
+#include "core/systick/systick.h"
+#include "core/uart/uart.h"
+
+static pn532_pcb_t pcb;
+
+/**************************************************************************/
+/*!
+ @brief Prints a hexadecimal value in plain characters
+
+ @param pbtData Pointer to the byte data
+ @param szBytes Data length in bytes
+*/
+/**************************************************************************/
+void pn532PrintHex(const byte_t * pbtData, const size_t szBytes)
+{
+ size_t szPos;
+ for (szPos=0; szPos < szBytes; szPos++)
+ {
+ printf("%02x ", pbtData[szPos]);
+ }
+ printf(CFG_PRINTF_NEWLINE);
+}
+
+/**************************************************************************/
+/*!
+ @brief Prints a hexadecimal value in plain characters, along with
+ the char equivalents in the following format
+
+ AA BB CC DD EE FF ......
+
+ @param pbtData Pointer to the byte data
+ @param szBytes Data length in bytes
+*/
+/**************************************************************************/
+void pn532PrintHexChar(const byte_t * pbtData, const size_t szBytes)
+{
+ size_t szPos;
+ for (szPos=0; szPos < szBytes; szPos++)
+ {
+ printf("%02x", pbtData[szPos]);
+ }
+ printf(" ");
+ for (szPos=0; szPos < szBytes; szPos++)
+ {
+ printf("%c", pbtData[szPos] <= 0x1F ? '.' : pbtData[szPos]);
+ }
+ printf(CFG_PRINTF_NEWLINE);
+}
+
+/**************************************************************************/
+/*!
+ @brief Gets a reference to the PN532 peripheral control block,
+ which can be used to determine that state of the PN532
+ IC, buffers, etc.
+*/
+/**************************************************************************/
+pn532_pcb_t * pn532GetPCB()
+{
+ return &pcb;
+}
+
+/**************************************************************************/
+/*!
+ @brief Initialises the appropriate serial bus (UART, etc.),and
+ sets up any buffers or peripherals required by the PN532.
+*/
+/**************************************************************************/
+void pn532Init(void)
+{
+ // Clear protocol control blocks
+ memset(&pcb, 0, sizeof(pn532_pcb_t));
+
+ // Initialise the underlying HW
+ pn532_bus_HWInit();
+
+ // Set the PCB flags to an appropriate state
+ pcb.initialised = TRUE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads the response buffer from the PN532
+
+ @param pbtResponse
+ The byte array that will hold the response data
+ @param pszLen
+ Pointer to the number of bytes in pbtCommand
+*/
+/**************************************************************************/
+pn532_error_t pn532Read(byte_t * pbtResponse, size_t * pszLen)
+{
+ if (!pcb.initialised) pn532Init();
+
+ // Try to wake the device up if it's in sleep mode
+ if (pcb.state == PN532_STATE_SLEEP)
+ {
+ pn532_error_t wakeupError = pn532_bus_Wakeup();
+ if (wakeupError)
+ return wakeupError;
+ }
+
+ // Read the response if the device is in an appropriate state
+ if (pcb.state == PN532_STATE_READY)
+ {
+ return pn532_bus_ReadResponse(pbtResponse, pszLen);
+ }
+ else
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Init Failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_UNABLETOINIT;
+ }
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends a byte array of command and parameter data to the
+ PN532, starting with the command byte. The frame's
+ preamble, checksums, postamble and frame identifier (0xD4)
+ will all be automatically added.
+
+ @param abtCommand
+ The byte array containg the command and any
+ optional parameters
+ @param szLen
+ The number of bytes in abtCommand
+*/
+/**************************************************************************/
+pn532_error_t pn532Write(byte_t * abtCommand, size_t szLen)
+{
+ if (!pcb.initialised) pn532Init();
+
+ // Try to wake the device up if it's in sleep mode
+ if (pcb.state == PN532_STATE_SLEEP)
+ {
+ pn532_error_t wakeupError = pn532_bus_Wakeup();
+ if (wakeupError)
+ return wakeupError;
+ }
+
+ // Send the command if the device is in an appropriate state
+ if (pcb.state == PN532_STATE_READY)
+ {
+ return pn532_bus_SendCommand(abtCommand, szLen);
+ }
+ else
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Init Failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_UNABLETOINIT;
+ }
+}
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_H__
+#define __PN532_H__
+
+#include "projectconfig.h"
+
+// Comment out this line to disable debug output
+// #define PN532_DEBUGMODE
+#define PN532_DEBUG(fmt, args...) printf(fmt, ##args)
+
+/* Error messages generated by the stack */
+/* Not to be confused with app level errors from the PN532 */
+/* These are the errors that are returned by the PN532 driver */
+typedef enum pn532_error_e
+{
+ PN532_ERROR_NONE = 0x00,
+ PN532_ERROR_UNABLETOINIT = 0x01, // Unable to initialise or wakeup the device
+ PN532_ERROR_APPLEVELERROR = 0x02, // Application level error detected
+ PN532_ERROR_BUSY = 0x03, // Busy executing a previous command
+ PN532_ERROR_NOACK = 0x04, // No ack message received
+ PN532_ERROR_INVALIDACK = 0x05, // Ack != 00 00 FF 00 FF 00
+ PN532_ERROR_PREAMBLEMISMATCH = 0x06, // Frame preamble + start code mismatch
+ PN532_ERROR_EXTENDEDFRAME = 0x07, // Extended frames currently unsupported
+ PN532_ERROR_LENCHECKSUMMISMATCH = 0x08,
+ PN532_ERROR_RESPONSEBUFFEREMPTY = 0x09, // No response data received
+ PN532_ERROR_READYSTATUSTIMEOUT = 0x0A, // Timeout waiting for 'ready' status (SPI/I2C only)
+ PN532_ERROR_TIMEOUTWAITINGFORCARD = 0x0B, // No card detected in field with the specified timeout
+ PN532_ERROR_BLOCKREADFAILED = 0x0C, // Unexpected response to block read request
+ PN532_ERROR_WRONGCARDTYPE = 0x0D, // Card is not the expected format (based on SENS_RES/ATQA value)
+ PN532_ERROR_ADDRESSOUTOFRANGE = 0x0E, // Specified block and page is out of range
+ PN532_ERROR_I2C_NACK = 0x0F // I2C Bus - No ACK was received for master to slave data transfer
+} pn532_error_t;
+
+typedef enum pn532_modulation_e
+{
+ PN532_MODULATION_ISO14443A_106KBPS = 0x00,
+ PN532_MODULATION_FELICA_212KBPS = 0x01,
+ PN532_MODULATION_FELICA_424KBPS = 0x02,
+ PN532_MODULATION_ISO14443B_106KBPS = 0x03,
+ PN532_MODULATION_JEWEL_106KBPS = 0x04
+} pn532_modulation_t;
+
+/* HW Commands for the PN532. */
+/* See UM0701-02 - PN532 User Manual */
+enum
+{
+ PN532_COMMAND_DIAGNOSE = 0x00,
+ PN532_COMMAND_GETFIRMWAREVERSION = 0x02,
+ PN532_COMMAND_GETGENERALSTATUS = 0x04,
+ PN532_COMMAND_READREGISTER = 0x06,
+ PN532_COMMAND_WRITEREGISTER = 0x08,
+ PN532_COMMAND_READGPIO = 0x0C,
+ PN532_COMMAND_WRITEGPIO = 0x0E,
+ PN532_COMMAND_SETSERIALBAUDRATE = 0x10,
+ PN532_COMMAND_SETPARAMETERS = 0x12,
+ PN532_COMMAND_SAMCONFIGURATION = 0x14,
+ PN532_COMMAND_POWERDOWN = 0x16,
+ PN532_COMMAND_RFCONFIGURATION = 0x32,
+ PN532_COMMAND_RFREGULATIONTEST = 0x58,
+ PN532_COMMAND_INJUMPFORDEP = 0x56,
+ PN532_COMMAND_INJUMPFORPSL = 0x46,
+ PN532_COMMAND_INLISTPASSIVETARGET = 0x4A,
+ PN532_COMMAND_INATR = 0x50,
+ PN532_COMMAND_INPSL = 0x4E,
+ PN532_COMMAND_INDATAEXCHANGE = 0x40,
+ PN532_COMMAND_INCOMMUNICATETHRU = 0x42,
+ PN532_COMMAND_INDESELECT = 0x44,
+ PN532_COMMAND_INRELEASE = 0x52,
+ PN532_COMMAND_INSELECT = 0x54,
+ PN532_COMMAND_INAUTOPOLL = 0x60,
+ PN532_COMMAND_TGINITASTARGET = 0x8C,
+ PN532_COMMAND_TGSETGENERALBYTES = 0x92,
+ PN532_COMMAND_TGGETDATA = 0x86,
+ PN532_COMMAND_TGSETDATA = 0x8E,
+ PN532_COMMAND_TGSETMETADATA = 0x94,
+ PN532_COMMAND_TGGETINITIATORCOMMAND = 0x88,
+ PN532_COMMAND_TGRESPONSETOINITIATOR = 0x90,
+ PN532_COMMAND_TGGETTARGETSTATUS = 0x8A
+};
+
+/* Application level errors generated by the PN532 chip */
+/* See UM0701-02 - PN532 User Manual */
+enum
+{
+ PN532_APPERROR_NONE = 0x00,
+ PN532_APPERROR_TIMEOUT = 0x01,
+ PN532_APPERROR_CRCERROR = 0x02,
+ PN532_APPERROR_PARITYERROR = 0x04,
+ PN532_APPERROR_FRAMINGERROR = 0x05,
+ PN532_APPERROR_BITCOLLISION = 0x06,
+ PN532_APPERROR_INSUFFICIENTBUFFER = 0x07,
+ PN532_APPERROR_RFBUFFEROVERFLOW = 0x09,
+ PN532_APPERROR_RFFIELDTIMEOUT = 0x0A,
+ PN532_APPERROR_RFPROTOCOLERROR = 0x0B,
+ PN532_APPERROR_TEMPERROR = 0x0D,
+ PN532_APPERROR_INTERNBUFFEROVERFLOW = 0x0E,
+ PN532_APPERROR_INVALIDPARAMETER = 0x10,
+ PN532_APPERROR_DEP_UNSUPPORTEDCMD = 0x12,
+ PN532_APPERROR_DEP_INVALIDOFORMAT = 0x13,
+ PN532_APPERROR_AUTHENTERR = 0x14,
+ PN532_APPERROR_UIDCCHECKERROR = 0x23,
+ PN532_APPERROR_DEP_INVALIDDEVSTATE = 0x25,
+ PN532_APPERROR_OPERATIONNOTALLOWED = 0x26,
+ PN532_APPERROR_CMDNOTACCEPTABLE = 0x27,
+ PN532_APPERROR_TARGETRELEASED = 0x29,
+ PN532_APPERROR_IDMISMATCH = 0x2A,
+ PN532_APPERROR_CARDDISAPPEARED = 0x2B,
+ PN532_APPERROR_NFCID3MISMATCH = 0x2C,
+ PN532_APPERROR_OVERCURRENTEVENT = 0x2D,
+ PN532_APPERROR_NADMISSINGINDEP = 0x2E
+};
+
+/* Possible states for the PN532 SW Stack */
+typedef enum pn532_state_e
+{
+ PN532_STATE_SLEEP,
+ PN532_STATE_READY,
+ PN532_STATE_BUSY
+}
+pn532_state_t;
+
+/* PN532 Protocol control block */
+typedef struct
+{
+ BOOL initialised;
+ pn532_state_t state;
+ pn532_modulation_t modulation;
+ uint32_t lastCommand;
+ uint32_t appError;
+} pn532_pcb_t;
+
+void pn532PrintHex(const byte_t * pbtData, const size_t szBytes);
+void pn532PrintHexChar(const byte_t * pbtData, const size_t szBytes);
+pn532_pcb_t * pn532GetPCB();
+void pn532Init();
+pn532_error_t pn532Read(byte_t *pbtResponse, size_t * pszLen);
+pn532_error_t pn532Write(byte_t *abtCommand, size_t szLen);
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_bus.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_BUS_H__
+#define __PN532_BUS_H__
+
+#include "projectconfig.h"
+#include "pn532.h"
+
+// #define PN532_BUS_UART
+#define PN532_BUS_I2C
+
+#define PN532_RSTPD_PORT (3)
+#define PN532_RSTPD_PIN (1)
+#define PN532_I2C_IRQPORT (3)
+#define PN532_I2C_IRQPIN (2)
+
+#define PN532_NORMAL_FRAME__DATA_MAX_LEN (254)
+#define PN532_NORMAL_FRAME__OVERHEAD (8)
+#define PN532_EXTENDED_FRAME__DATA_MAX_LEN (264)
+#define PN532_EXTENDED_FRAME__OVERHEAD (11)
+#define PN532_BUFFER_LEN (PN532_EXTENDED_FRAME__DATA_MAX_LEN + PN532_EXTENDED_FRAME__OVERHEAD)
+
+#define PN532_UART_BAUDRATE (115200)
+
+#define PN532_I2C_ADDRESS (0x48)
+#define PN532_I2C_READBIT (0x01)
+#define PN532_I2C_READYTIMEOUT (20) // Max number of attempts to read Ready bit (see UM 5-Nov-2007 Section 6.2.4)
+
+// Generic interface for the different serial buses available on the PN532
+void pn532_bus_HWInit(void);
+pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData);
+pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen);
+pn532_error_t pn532_bus_Wakeup(void);
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_bus_i2c.c
+ @author K. Townsend (microBuilder.eu)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2012, microBuilder SARL
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+#include <string.h>
+
+#include "pn532.h"
+#include "pn532_bus.h"
+
+#ifdef PN532_BUS_I2C
+
+#include "core/systick/systick.h"
+#include "core/gpio/gpio.h"
+#include "core/i2c/i2c.h"
+
+extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
+extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
+extern volatile uint32_t I2CReadLength, I2CWriteLength;
+
+/* ======================================================================
+ PRIVATE FUNCTIONS
+ ====================================================================== */
+
+/**************************************************************************/
+/*!
+ @brief Writes an 8 bit value over I2C
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_I2C_NACK
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_i2c_WriteData (const byte_t * pbtData, const size_t szData)
+{
+ uint32_t i2cState;
+
+ // Clear write buffers
+ uint32_t i;
+ for ( i = 0; i < I2C_BUFSIZE; i++ )
+ {
+ I2CMasterBuffer[i] = 0x00;
+ }
+
+ // Send the specified bytes
+ I2CWriteLength = szData+1;
+ I2CReadLength = 0;
+ I2CMasterBuffer[0] = PN532_I2C_ADDRESS; // I2C device address
+ for ( i = 0; i < szData; i++ )
+ {
+ I2CMasterBuffer[i+1] = pbtData[i];
+ }
+ i2cState = i2cEngine();
+
+ // Check if we got an ACK
+ if ((i2cState == I2CSTATE_NACK) || (i2cState == I2CSTATE_SLA_NACK))
+ {
+ // I2C slave didn't acknowledge the master transfer
+ // The PN532 probably isn't connected properly or the
+ // bus select pins are in the wrong state
+ return PN532_ERROR_I2C_NACK;
+ }
+
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Checks the 'IRQ' pin to know if the PN532 is ready to send
+ a response or not
+
+ @note The IRQ bit may stay high intentionally, and this isn't
+ always an error condition. When PN532_COMMAND_INLISTPASSIVETARGET
+ is sent, for example, the PN532 will wait until a card
+ enters the magnetic field, and IRQ will remain high since
+ there is no response ready yet. The IRQ pin will go low
+ as soon as a card enters the magentic field and the data
+ has been retrieved from it.
+
+ @returns 1 if a response is ready, 0 if the PN532 is still busy or a
+ timeout occurred
+*/
+/**************************************************************************/
+uint8_t pn532_bus_i2c_WaitForReady(void)
+{
+ uint8_t busy = 1;
+ // uint8_t busyTimeout = 0;
+
+ while (busy)
+ {
+ // For now, we wait forever until a command is ready
+ // ToDo: Add user-specified timeout
+ busy = gpioGetValue(PN532_I2C_IRQPORT, PN532_I2C_IRQPIN);
+ systickDelay(1);
+ // busyTimeout++;
+ // if (busyTimeout == PN532_I2C_READYTIMEOUT)
+ // {
+ // return false;
+ // }
+ }
+
+ return true;
+}
+
+/**************************************************************************/
+/*!
+ @brief Builds a standard PN532 frame using the supplied data
+
+ @param pbtFrame Pointer to the field that will hold the frame data
+ @param pszFrame Pointer to the field that will hold the frame length
+ @param pbtData Pointer to the data to insert in a frame
+ @param swData Length of the data to insert in bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_EXTENDEDFRAME
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_i2c_BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
+{
+ if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
+ {
+ // Extended frames currently unsupported
+ return PN532_ERROR_EXTENDEDFRAME;
+ }
+
+ // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
+ pbtFrame[3] = szData + 1;
+ // LCS - Packet length checksum
+ pbtFrame[4] = 256 - (szData + 1);
+ // TFI
+ pbtFrame[5] = 0xD4;
+ // DATA - Copy the PN53X command into the packet buffer
+ memcpy (pbtFrame + 6, pbtData, szData);
+
+ // DCS - Calculate data payload checksum
+ byte_t btDCS = (256 - 0xD4);
+ size_t szPos;
+ for (szPos = 0; szPos < szData; szPos++)
+ {
+ btDCS -= pbtData[szPos];
+ }
+ pbtFrame[6 + szData] = btDCS;
+
+ // 0x00 - End of stream marker
+ pbtFrame[szData + 7] = 0x00;
+
+ (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
+
+ return PN532_ERROR_NONE;
+}
+
+/* ======================================================================
+ PUBLIC FUNCTIONS
+ ====================================================================== */
+
+/**************************************************************************/
+/*!
+ @brief Initialises I2C and configures the PN532 HW
+*/
+/**************************************************************************/
+void pn532_bus_HWInit(void)
+{
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Initialising I2C %s", CFG_PRINTF_NEWLINE);
+ #endif
+ i2cInit(I2CMASTER);
+
+ // Set IRQ pin to input
+ gpioSetDir(PN532_I2C_IRQPORT, PN532_I2C_IRQPIN, gpioDirection_Input);
+
+ // Set reset pin as output and reset device
+ gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Resetting the PN532...\r\n");
+ #endif
+ gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
+ systickDelay(400);
+ gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
+
+ // Wait for the PN532 to finish booting
+ systickDelay(100);
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends the specified command to the PN532, automatically
+ creating an appropriate frame for it
+
+ @param pdbData Pointer to the byte data to send
+ @param szData Length in bytes of the data to send
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_EXTENDEDFRAME // Extended frames not supported
+ - PN532_ERROR_BUSY // Already busy with a command
+ - PN532_ERROR_I2C_NACK // No ACK on I2C
+ - PN532_ERROR_READYSTATUSTIMEOUT // Timeout waiting for ready bit
+ - PN532_ERROR_INVALIDACK // No ACK frame received
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
+{
+ pn532_error_t error = PN532_ERROR_NONE;
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ // Check if we're busy
+ if (pn532->state == PN532_STATE_BUSY)
+ {
+ return PN532_ERROR_BUSY;
+ }
+
+ // Flag the stack as busy
+ pn532->state = PN532_STATE_BUSY;
+
+ // --------------------------------------------------------------------
+ // Send the command frame
+ // --------------------------------------------------------------------
+ byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
+ size_t szFrame = 0;
+
+ // Build the frame
+ pn532_bus_i2c_BuildFrame (abtFrame, &szFrame, pbtData, szData);
+
+ // Keep track of the last command that was sent
+ pn532->lastCommand = pbtData[0];
+
+ // Output the frame data for debugging if requested
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Sending (%02d): ", szFrame);
+ pn532PrintHex(abtFrame, szFrame);
+ #endif
+
+ // Send data to the PN532
+ error = pn532_bus_i2c_WriteData(abtFrame, szFrame);
+
+ if (error == PN532_ERROR_I2C_NACK)
+ {
+ // Most likely error is PN532_ERROR_I2C_NACK
+ // meaning no I2C ACK received from the PN532
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("No ACK received on I2C bus%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return error;
+ }
+
+ // --------------------------------------------------------------------
+ // Wait for the IRQ/Ready flag
+ // --------------------------------------------------------------------
+ if (!(pn532_bus_i2c_WaitForReady()))
+ {
+ pn532->state = PN532_STATE_READY;
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_READYSTATUSTIMEOUT;
+ }
+
+ // --------------------------------------------------------------------
+ // Read the ACK frame
+ // --------------------------------------------------------------------
+ uint32_t i;
+ // Clear buffer
+ for ( i = 0; i < I2C_BUFSIZE; i++ )
+ {
+ I2CMasterBuffer[i] = 0x00;
+ }
+ I2CWriteLength = 0;
+ I2CReadLength = 7; // ACK + Ready bit = 7
+ I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
+ i2cEngine();
+
+ // Make sure the received ACK matches the prototype
+ const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
+ byte_t abtRxBuf[6];
+ // memcpy(abtRxBuf, I2CSlaveBuffer+1, 6);
+ for ( i = 0; i < 6; i++ )
+ {
+ abtRxBuf[i] = I2CSlaveBuffer[i+1];
+ }
+ if (0 != (memcmp (abtRxBuf, abtAck, 6)))
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Invalid ACK: ");
+ pn532PrintHex(abtRxBuf, 6);
+ PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_INVALIDACK;
+ }
+
+ // --------------------------------------------------------------------
+ // Wait for the post-ACK IRQ/Ready flag
+ // --------------------------------------------------------------------
+ if (!(pn532_bus_i2c_WaitForReady()))
+ {
+ pn532->state = PN532_STATE_READY;
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_READYSTATUSTIMEOUT;
+ }
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads a response from the PN532
+
+ @note Possible error message are:
+
+ - PN532_ERROR_BUSY
+ - PN532_ERROR_RESPONSEBUFFEREMPTY
+ - PN532_ERROR_PREAMBLEMISMATCH
+ - PN532_ERROR_APPLEVELERROR
+ - PN532_ERROR_EXTENDEDFRAME
+ - PN532_ERROR_LENCHECKSUMMISMATCH
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
+{
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ // Check if we're busy
+ if (pn532->state == PN532_STATE_BUSY)
+ {
+ return PN532_ERROR_BUSY;
+ }
+
+ // Flag the stack as busy
+ pn532->state = PN532_STATE_BUSY;
+
+ // Reset the app error flag
+ pn532->appError = PN532_APPERROR_NONE;
+
+ uint32_t i;
+ for ( i = 0; i < I2C_BUFSIZE; i++ )
+ {
+ I2CMasterBuffer[i] = 0x00;
+ }
+ I2CWriteLength = 0;
+ I2CReadLength = I2C_BUFSIZE;
+ I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
+ i2cEngine();
+
+ // Display the raw response data for debugging if requested
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Received (%02d): ", I2C_BUFSIZE-1);
+ pn532PrintHex(pbtResponse, I2C_BUFSIZE-1);
+ #endif
+
+ // Use the full I2C buffer size for now (until we're sure we have a good frame)
+ *pszRxLen = I2C_BUFSIZE - 1;
+
+ // Fill the response buffer from I2C (skipping the leading 'ready' bit when using I2C)
+ // memcpy(pbtResponse, I2CSlaveBuffer+1, I2C_BUFSIZE-1);
+ for ( i = 0; i < I2C_BUFSIZE-1; i++ )
+ {
+ pbtResponse[i] = I2CSlaveBuffer[i+1];
+ }
+
+ // Check the frame type
+ if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
+ {
+ // Error frame
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
+ #endif
+ // Set application error message ID
+ pn532->appError = pbtResponse[5];
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_APPLEVELERROR;
+ }
+ else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
+ {
+ // Extended frame
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_EXTENDEDFRAME;
+ }
+ else
+ {
+ // Normal frame
+ if (256 != (pbtResponse[3] + pbtResponse[4]))
+ {
+ // TODO: Retry
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_LENCHECKSUMMISMATCH;
+ }
+ }
+
+ // Figure out how large the response really is
+ // Response Frame Len = pbtResponse[3] + 7 (00 00 FF LEN LCS TFI [DATA] DCS)
+ *pszRxLen = pbtResponse[3] + 7;
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends the wakeup sequence to the PN532.
+
+ @note Possible error message are:
+
+ - PN532_ERROR_BUSY
+ - PN532_ERROR_I2C_NACK // No I2C ACK
+ - PN532_ERROR_READYSTATUSTIMEOUT // Timed out waiting for ready bit
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_Wakeup(void)
+{
+ pn532_error_t error = PN532_ERROR_NONE;
+ byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
+ uint32_t i;
+
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
+ #endif
+ error = pn532_bus_i2c_WriteData(abtWakeUp,sizeof(abtWakeUp));
+ systickDelay(100);
+
+ // Wait for the IRQ/Ready flag to indicate a response is ready
+ if (!(pn532_bus_i2c_WaitForReady()))
+ {
+ error = PN532_ERROR_READYSTATUSTIMEOUT;
+ }
+
+ // Read and discard the ACK frame
+ for ( i = 0; i < I2C_BUFSIZE; i++ )
+ {
+ I2CMasterBuffer[i] = 0x00;
+ }
+ I2CWriteLength = 0;
+ I2CReadLength = 7; // ACK + Ready bit = 7
+ I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
+ i2cEngine();
+ systickDelay(1);
+
+ // Wait for the IRQ/Ready flag to indicate a response is ready
+ if (!(pn532_bus_i2c_WaitForReady()))
+ {
+ error = PN532_ERROR_READYSTATUSTIMEOUT;
+ }
+
+ pn532->state = PN532_STATE_READY;
+ return error;
+}
+
+#endif // #ifdef PN532_BUS_I2C
\ No newline at end of file
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_bus_uart.c
+*/
+/**************************************************************************/
+#include <string.h>
+
+#include "pn532.h"
+#include "pn532_bus.h"
+
+#ifdef PN532_BUS_UART
+
+#include "core/systick/systick.h"
+#include "core/gpio/gpio.h"
+#include "core/uart/uart.h"
+
+/**************************************************************************/
+/*!
+ @brief Builds a standard PN532 frame using the supplied data
+
+ @param pbtFrame Pointer to the field that will hold the frame data
+ @param pszFrame Pointer to the field that will hold the frame length
+ @param pbtData Pointer to the data to insert in a frame
+ @param swData Length of the data to insert in bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_EXTENDEDFRAME
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
+{
+ if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
+ {
+ // Extended frames currently unsupported
+ return PN532_ERROR_EXTENDEDFRAME;
+ }
+
+ // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
+ pbtFrame[3] = szData + 1;
+ // LCS - Packet length checksum
+ pbtFrame[4] = 256 - (szData + 1);
+ // TFI
+ pbtFrame[5] = 0xD4;
+ // DATA - Copy the PN53X command into the packet buffer
+ memcpy (pbtFrame + 6, pbtData, szData);
+
+ // DCS - Calculate data payload checksum
+ byte_t btDCS = (256 - 0xD4);
+ size_t szPos;
+ for (szPos = 0; szPos < szData; szPos++)
+ {
+ btDCS -= pbtData[szPos];
+ }
+ pbtFrame[6 + szData] = btDCS;
+
+ // 0x00 - End of stream marker
+ pbtFrame[szData + 7] = 0x00;
+
+ (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
+
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Initialises UART and configures the PN532
+*/
+/**************************************************************************/
+void pn532_bus_HWInit(void)
+{
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Initialising UART (%d)%s", PN532_UART_BAUDRATE, CFG_PRINTF_NEWLINE);
+ #endif
+ uartInit(PN532_UART_BAUDRATE);
+
+ // Set reset pin as output and reset device
+ gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Resetting the PN532...\r\n");
+ #endif
+ gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
+ systickDelay(400);
+ gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
+
+ // Wait for the PN532 to finish booting
+ systickDelay(100);
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends the specified command to the PN532, automatically
+ creating an appropriate frame for it
+
+ @param pdbData Pointer to the byte data to send
+ @param szData Length in bytes of the data to send
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_BUSY
+ - PN532_ERROR_NOACK
+ - PN532_ERROR_INVALIDACK
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
+{
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ // Check if we're busy
+ if (pn532->state == PN532_STATE_BUSY)
+ {
+ return PN532_ERROR_BUSY;
+ }
+
+ // Flag the stack as busy
+ pn532->state = PN532_STATE_BUSY;
+
+ // Every packet must start with "00 00 ff"
+ byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
+ size_t szFrame = 0;
+
+ // Build the frame
+ pn532_bus_BuildFrame (abtFrame, &szFrame, pbtData, szData);
+
+ // Keep track of the last command that was sent
+ pn532->lastCommand = pbtData[0];
+
+ // Output the frame data for debugging if requested
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Sending (%02d): ", szFrame);
+ pn532PrintHex(abtFrame, szFrame);
+ #endif
+
+ // Send data to the PN532
+ uartSend (abtFrame, szFrame);
+
+ // Wait for ACK
+ byte_t abtRxBuf[6];
+ uart_pcb_t *uart = uartGetPCB();
+ systickDelay(10); // FIXME: How long should we wait for ACK?
+ if (uart->rxfifo.len < 6)
+ {
+ // Unable to read ACK
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NOACK;
+ }
+
+ // Read ACK ... this will also remove it from the buffer
+ const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
+ abtRxBuf[0] = uartRxBufferRead();
+ abtRxBuf[1] = uartRxBufferRead();
+ abtRxBuf[2] = uartRxBufferRead();
+ abtRxBuf[3] = uartRxBufferRead();
+ abtRxBuf[4] = uartRxBufferRead();
+ abtRxBuf[5] = uartRxBufferRead();
+
+ // Make sure the received ACK matches the prototype
+ if (0 != (memcmp (abtRxBuf, abtAck, 6)))
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Invalid ACK: ");
+ pn532PrintHex(abtRxBuf, 6);
+ PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_INVALIDACK;
+ }
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads a response from the PN532
+
+ @note Possible error message are:
+
+ - PN532_ERROR_BUSY
+ - PN532_ERROR_RESPONSEBUFFEREMPTY
+ - PN532_ERROR_PREAMBLEMISMATCH
+ - PN532_ERROR_APPLEVELERROR
+ - PN532_ERROR_EXTENDEDFRAME
+ - PN532_ERROR_LENCHECKSUMMISMATCH
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
+{
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ // Check if we're busy
+ if (pn532->state == PN532_STATE_BUSY)
+ {
+ return PN532_ERROR_BUSY;
+ }
+
+ // Flag the stack as busy
+ pn532->state = PN532_STATE_BUSY;
+
+ // Reset the app error flag
+ pn532->appError = PN532_APPERROR_NONE;
+
+ // Read response from uart
+ if (!uartRxBufferReadArray(pbtResponse, pszRxLen))
+ {
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_RESPONSEBUFFEREMPTY;
+ }
+
+ // Display the raw response data for debugging if requested
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Received (%02d): ", *pszRxLen);
+ pn532PrintHex(pbtResponse, *pszRxLen);
+ #endif
+
+ // Check preamble
+ const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
+ if (0 != (memcmp (pbtResponse, pn53x_preamble, 3)))
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_PREAMBLEMISMATCH;
+ }
+
+ // Check the frame type
+ if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
+ {
+ // Error frame
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
+ #endif
+ // Set application error message ID
+ pn532->appError = pbtResponse[5];
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_APPLEVELERROR;
+ }
+ else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
+ {
+ // Extended frame
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_EXTENDEDFRAME;
+ }
+ else
+ {
+ // Normal frame
+ if (256 != (pbtResponse[3] + pbtResponse[4]))
+ {
+ // TODO: Retry
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_LENCHECKSUMMISMATCH;
+ }
+ // size_t szPayloadLen = abtRx[3] - 2;
+ }
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends the wakeup sequence to the PN532.
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_Wakeup(void)
+{
+ size_t szLen;
+ byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
+
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
+ #endif
+ uartSend(abtWakeUp,sizeof(abtWakeUp));
+ systickDelay(100);
+
+ byte_t response[32];
+ pn532_bus_ReadResponse(response, &szLen);
+
+ // Todo: Check for error ... currently throws a checksum error
+ // that isn't really an error
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+#endif // #ifdef PN532_BUS_UART
\ No newline at end of file
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_mifare.h
-*/
-/**************************************************************************/
-
-#ifndef __PN532_MIFARE_H__
-#define __PN532_MIFARE_H__
-
-#include "projectconfig.h"
-
-// These may need to be enlarged for multi card support
-#define PN532_RESPONSELEN_INLISTPASSIVETARGET (64)
-#define PN532_RESPONSELEN_INDATAEXCHANGE (64)
-
-typedef enum pn532_mifare_cmd_e
-{
- PN532_MIFARE_CMD_AUTH_A = 0x60,
- PN532_MIFARE_CMD_AUTH_B = 0x61,
- PN532_MIFARE_CMD_READ = 0x30,
- PN532_MIFARE_CMD_WRITE = 0xA0,
- PN532_MIFARE_CMD_TRANSFER = 0xB0,
- PN532_MIFARE_CMD_DECREMENT = 0xC0,
- PN532_MIFARE_CMD_INCREMENT = 0xC1,
- PN532_MIFARE_CMD_STORE = 0xC2
-}
-pn532_mifare_cmd_t;
-
-#endif
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_mifare_classic.c
-*/
-/**************************************************************************/
-
-/* MIFARE CLASSIC DESCRIPTION
- ==========================
-
- MIFARE Classic cards come in 1K and 4K varieties. While several
- varieties of chips exist, the two main chipsets used are described
- in the following publicly accessible documents:
-
- MF1S503x Mifare Classic 1K data sheet:
- http://www.nxp.com/documents/data_sheet/MF1S503x.pdf
-
- MF1S70yyX MIFARE Classic 4K data sheet:
- http://www.nxp.com/documents/data_sheet/MF1S70YYX.pdf
-
- Mifare Classic cards typically have a a 4-byte NUID, though you may
- find cards with 7 byte IDs as well
-
- EEPROM MEMORY
- =============
- Mifare Classic cards have either 1K or 4K of EEPROM memory. Each
- memory block can be configured with different access conditions,
- with two seperate authentication keys present in each block.
-
- The two main Mifare Classic card types are organised as follows:
-
- 1K Cards: 16 sectors of 4 blocks (0..15)
- 4K Cards: 32 sectors of 4 blocks (0..31) and
- 8 sectors of 16 blocks (32..39)
-
- 4 block sectors
- ===============
- Sector Block Bytes Description
- ------ ----- ----- -----------
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
-
- 1 3 [-------KEY A-------] [Access Bits] [-------KEY A-------] Sector Trailer 1
- 2 [ Data ] Data
- 1 [ Data ] Data
- 0 [ Data ] Data
-
- 0 3 [-------KEY A-------] [Access Bits] [-------KEY A-------] Sector Trailer 1
- 2 [ Data ] Data
- 1 [ Data ] Data
- 0 [ Manufacturer Data ] Manufacturer Block
-
- Sector Trailer (Block 3)
- ------------------------
- The sector trailer block contains the two secret keys (Key A and Key B), as well
- as the access conditions for the four blocks. It has the following structure:
-
- Sector Trailer Bytes
- --------------------------------------------------------------
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- [ Key A ] [Access Bits] [ Key B ]
-
- For more information in using Keys to access the clock contents, see
- Accessing Data Blocks further below.
-
- Data Blocks (Blocks 0..2)
- -------------------------
- Data blocks are 16 bytes wide and, depending on the permissions set in the
- access bits, can be read from and written to. You are free to use the 16 data
- bytes in any way you wish. You can easily store text input, store four 32-bit
- integer values, a 16 character uri, etc.
-
- Data Blocks as "Value Blocks"
- -----------------------------
- An alternative to storing random data in the 16 byte-wide blocks is to
- configure them as "Value Blocks". Value blocks allow performing electronic
- purse functions (valid commands are: read, write, increment, decrement,
- restore, transfer).
-
- Each Value block contains a single signed 32-bit value, and this value is
- stored 3 times for data integrity and security reasons. It is stored twice
- non-inverted, and once inverted. The last 4 bytes are used for a 1-byte
- address, which is stored 4 times (twice non-inverted, and twice inverted).
-
- Data blocks configured as "Value Blocks" have the following structure:
-
- Value Block Bytes
- --------------------------------------------------------------
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- [ Value ] [ ~Value ] [ Value ] [A ~A A ~A]
-
- Manufacturer Block (Sector 0, Block 0)
- --------------------------------------
- Sector 0 is special since it contains the Manufacturer Block. This block
- contains the manufacturer data, and is read-only. It should be avoided
- unless you know what you are doing.
-
- 16 block sectors
- ================
- 16 block sectors are identical to 4 block sectors, but with more data blocks. The same
- structure described in the 4 block sectors above applies.
-
- Sector Block Bytes Description
- ------ ----- ----- ----------
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
-
- 32 15 [-------KEY A-------] [Access Bits] [-------KEY B-------] Sector Trailer 32
- 14 [ Data ] Data
- 13 [ Data ] Data
- ...
- 2 [ Data ] Data
- 1 [ Data ] Data
- 0 [ Data ] Data
-
- ACCESSING DATA BLOCKS
- =====================
-
- Before you can access the cards, you must following two steps:
-
- 1.) You must retrieve the 7 byte UID or the 4-byte NUID of the card.
- This can be done using pn532_mifareclassic_WaitForPassiveTarget()
- below, which will return the appropriate ID.
-
- 2.) You must authenticate the sector you wish to access according to the
- access rules defined in the Sector Trailer block for that sector.
- This can be done using pn532_mifareclassic_AuthenticateBlock(),
- passing in the appropriate key value.
-
- Most new cards have a default Key A of 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF,
- but some common values worth trying are:
-
- 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
- 0XD3 0XF7 0XD3 0XF7 0XD3 0XF7
- 0XA0 0XA1 0XA2 0XA3 0XA4 0XA5
- 0XB0 0XB1 0XB2 0XB3 0XB4 0XB5
- 0X4D 0X3A 0X99 0XC3 0X51 0XDD
- 0X1A 0X98 0X2C 0X7E 0X45 0X9A
- 0XAA 0XBB 0XCC 0XDD 0XEE 0XFF
- 0X00 0X00 0X00 0X00 0X00 0X00
- 0XAB 0XCD 0XEF 0X12 0X34 0X56
-
- 3.) Once authenication has succeeded, and depending on the sector
- permissions, you can then read/write/increment/decrement the
- contents of the specific block, using one of the helper functions
- included in this module.
-
-*/
-
-#include <string.h>
-
-#include "../pn532.h"
-#include "../pn532_bus.h"
-#include "pn532_mifare.h"
-#include "pn532_mifare_classic.h"
-
-#include "core/systick/systick.h"
-
-/**************************************************************************/
-/*!
- Indicates whether the specified block number is the first block
- in the sector (block 0 relative to the current sector)
-*/
-/**************************************************************************/
-bool is_first_block (uint32_t uiBlock)
-{
- // Test if we are in the small or big sectors
- if (uiBlock < 128)
- return ((uiBlock) % 4 == 0);
- else
- return ((uiBlock) % 16 == 0);
-}
-
-/**************************************************************************/
-/*!
- Indicates whether the specified block number is the sector trailer
-*/
-/**************************************************************************/
-bool is_trailer_block (uint32_t uiBlock)
-{
- // Test if we are in the small or big sectors
- if (uiBlock < 128)
- return ((uiBlock + 1) % 4 == 0);
- else
- return ((uiBlock + 1) % 16 == 0);
-}
-
-/**************************************************************************/
-/*!
- Tries to detect MIFARE targets in passive mode. This needs to be done
- before anything useful can be accomplished with a tag since you need
- the tag's unique UID to communicate with it.
-
- @param pbtCUID Pointer to the byte array where the card's UID
- will be stored once a card is detected
- @param pszUIDLen Pointer to the size of the card UID in bytes
-
- Response for a valid ISO14443A 106KBPS (Mifare Classic, etc.)
- should be in the following format. See UM0701-02 section
- 7.3.5 for more information
-
- byte Description
- ------------- ------------------------------------------
- b0..6 Frame header and preamble
- b7 Tags Found
- b8 Tag Number (only one used in this example)
- b9..10 SENS_RES
- b11 SEL_RES
- b12 NFCID Length
- b13..NFCIDLen NFCID
-
- SENS_RES SEL_RES Manufacturer/Card Type NFCID Len
- -------- ------- ----------------------- ---------
- 00 04 08 NXP Mifare Classic 1K 4 bytes
- 00 02 18 NXP Mifare Classic 4K 4 bytes
-
- @note Possible error messages are:
-
- - PN532_ERROR_WRONGCARDTYPE
-*/
-/**************************************************************************/
-pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen)
-{
- byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET];
- pn532_error_t error;
- size_t szLen;
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE);
- #endif
-
- /* Try to initialise a single ISO14443A tag at 106KBPS */
- /* Note: To wait for a card with a known UID, append the four byte */
- /* UID to the end of the command. */
- byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS};
- error = pn532Write(abtCommand, sizeof(abtCommand));
- if (error)
- return error;
-
- /* Wait until we get a valid response or a timeout */
- do
- {
- systickDelay(25);
- error = pn532Read(abtResponse, &szLen);
- } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
- if (error)
- return error;
-
- /* Check SENSE_RES to make sure this is a Mifare Classic card */
- /* Classic 1K = 00 04 */
- /* Classic 4K = 00 02 */
- /* Classic Emulated = 00 08 */
- if ((abtResponse[10] == 0x02) ||
- (abtResponse[10] == 0x04) ||
- (abtResponse[10] == 0x08))
- {
- /* Card appears to be Mifare Classic */
- *szCUIDLen = abtResponse[12];
- uint8_t i;
- for (i=0; i < *szCUIDLen; i++)
- {
- pbtCUID[i] = abtResponse[13+i];
- }
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" ATQA: ");
- pn532PrintHex(abtResponse+9, 2);
- PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" UID: ");
- pn532PrintHex(pbtCUID, *szCUIDLen);
- #endif
- }
- else
- {
- /* Card is ISO14443A but doesn't appear to be Mifare Classic */
- /* Mifare Ultralight = 0x0044 */
- /* Mifare DESFire = 0x0344 */
- /* Innovision Jewel = 0x0C00 */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Wrong Card Type (Expected ATQA 00 02, 00 04 or 00 08) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" ATQA : ");
- pn532PrintHex(abtResponse+9, 2);
- PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" UID : ");
- size_t pos;
- for (pos=0; pos < abtResponse[12]; pos++)
- {
- printf("%02x ", abtResponse[13 + pos]);
- }
- printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_WRONGCARDTYPE;
- }
-
- return PN532_ERROR_NONE;
-}
-
-
-/**************************************************************************/
-/*!
- Tries to authenticate a block of memory on a MIFARE card using the
- INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
- for more information on sending MIFARE and other commands.
-
- @param pbtCUID Pointer to a byte array containing the card UID
- @param szCUIDLen The length (in bytes) of the card's UID (Should
- be 4 for MIFARE Classic)
- @param uiBlockNumber The block number to authenticate. (0..63 for
- 1KB cards, and 0..255 for 4KB cards).
- @param uiKeyType Which key type to use during authentication
- (PN532_MIFARE_CMD_AUTH_A or PN532_MIFARE_CMD_AUTH_B)
- @param pbtKeys Pointer to a byte array containing the 6 byte
- key value
-*/
-/**************************************************************************/
-pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys)
-{
- pn532_error_t error;
- byte_t abtCommand[17];
- byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
- size_t szLen;
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Trying to authenticate card ");
- pn532PrintHex(pbtCUID, szCUIDLen);
- #endif
-
- /* Prepare the authentication command */
- abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
- abtCommand[1] = 1; /* Max card numbers */
- abtCommand[2] = (uiKeyType) ? PN532_MIFARE_CMD_AUTH_A : PN532_MIFARE_CMD_AUTH_B;
- abtCommand[3] = uiBlockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
- memcpy (abtCommand+4, pbtKeys, 6);
- uint8_t i;
- for (i = 0; i < szCUIDLen; i++)
- {
- abtCommand[10+i] = pbtCUID[i]; /* 4 byte card ID */
- }
-
- /* Send the command */
- error = pn532Write(abtCommand, 10+szCUIDLen);
- if (error)
- {
- /* Problem with the serial bus, etc. */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return error;
- }
-
- /* Read the authentication response */
- memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
- do
- {
- systickDelay(25);
- error = pn532Read(abtResponse, &szLen);
- }
- while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
- if (error)
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return error;
- }
-
- // ToDo: How to check if authentification really worked (bad key, etc.)?
-
- /* Output the authentification data */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Authenticated block %d %s", uiBlockNumber, CFG_PRINTF_NEWLINE);
- #endif
-
- // Return OK signal
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- Tries to read an entire 16-byte data block at the specified block
- address.
-
- @param uiBlockNumber The block number to authenticate. (0..63 for
- 1KB cards, and 0..255 for 4KB cards).
- @param pbtData Pointer to the byte array that will hold the
- retrieved data (if any)
-
- @note Possible error messages are:
-
- - PN532_ERROR_BLOCKREADFAILED
-*/
-/**************************************************************************/
-pn532_error_t pn532_mifareclassic_ReadDataBlock (uint8_t uiBlockNumber, byte_t * pbtData)
-{
- pn532_error_t error;
- byte_t abtCommand[4];
- byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
- size_t szLen;
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Reading 16 bytes at block %03d%s", uiBlockNumber, CFG_PRINTF_NEWLINE);
- #endif
-
- /* Prepare the command */
- abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE;
- abtCommand[1] = 1; /* Card number */
- abtCommand[2] = PN532_MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
- abtCommand[3] = uiBlockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
-
- /* Send the commands */
- error = pn532Write(abtCommand, sizeof(abtCommand));
- if (error)
- {
- /* Bus error, etc. */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return error;
- }
-
- /* Read the response */
- memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
- do
- {
- systickDelay(50);
- error = pn532Read(abtResponse, &szLen);
- }
- while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
- if (error)
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return error;
- }
-
- /* Make sure we have a valid response (should be 26 bytes long) */
- if (szLen == 26)
- {
- /* Copy the 16 data bytes to the output buffer */
- /* Block content starts at byte 9 of a valid response */
- memcpy (pbtData, abtResponse+8, 16);
- }
- else
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Unexpected response reading block %d. Bad key?%s", uiBlockNumber, CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_BLOCKREADFAILED;
- }
-
- /* Display data for debug if requested */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Block %03d: ", uiBlockNumber, CFG_PRINTF_NEWLINE);
- pn532PrintHexVerbose(pbtData, 16);
- #endif
-
- // Return OK signal
- return PN532_ERROR_NONE;
-}
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_mifare_classic.h
-*/
-/**************************************************************************/
-
-#ifndef __PN532_MIFARE_CLASSIC_H__
-#define __PN532_MIFARE_CLASSIC_H__
-
-#include "projectconfig.h"
-#include "pn532_mifare.h"
-
-pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen);
-pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys);
-pn532_error_t pn532_mifareclassic_ReadDataBlock (uint8_t uiBlockNumber, byte_t * pbtData);
-
-#endif
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_mifare_ultralight.c
-*/
-/**************************************************************************/
-
-/* MIFARE ULTRALIGHT DESCRIPTION
- =============================
-
- MIFARE Ultralight cards typically contain 512 bits (64 bytes) of
- memory, including 4 bytes (32-bits) of OTP (One Time Programmable)
- memory where the individual bits can be written but not erased.
-
- MF0ICU1 Mifare Ultralight Functional Specification:
- http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
-
-
- Mifare Ultralight cards have a 7-byte UID
-
- EEPROM MEMORY
- =============
- Mifare Ultralight cards have 512 bits (64 bytes) of EEPROM memory,
- including 4 byte (32 bits) of OTP memory. Unlike Mifare Classic cards,
- there is no authentication on a per block level, although the blocks
- can be set to "read-only" mode using Lock Bytes (described below).
-
- EEPROM memory is organised into 16 pages of four bytes eachs, in
- the following order
-
- Page Description
- ---- ------------
- 0 Serial Number (4 bytes)
- 1 Serial Number (4 bytes)
- 2 Byte 0: Serial Number
- Byte 1: Internal Memory
- Byte 2..3: lock bytes
- 3 One-time programmable memory (4 bytes)
- 4..15 User memory (4 bytes)
-
- Lock Bytes (Page 2)
- -------------------
- Bytes 2 and 3 of page 2 are referred to as "Lock Bytes". Each
- page from 0x03 and higher can individually locked by setting the
- corresponding locking bit to "1" to prevent further write access,
- effectively making the memory read only.
-
- For information on the lock byte mechanism, refer to section 8.5.2 of
- the datasheet (referenced above).
-
- OTP Bytes (Page 3)
- ------------------
- Page 3 is the OTP memory, and by default all bits on this page are
- set to 0. These bits can be bitwise modified using the Mifare WRITE
- command, and individual bits can be set to 1, but can not be changed
- back to 0.
-
- Data Pages (Pages 4..15)
- ------------------------
- Pages 4 to 15 are can be freely read from and written to,
- provided there is no conflict with the Lock Bytes described above.
-
- After production, the bytes have the following default values:
-
- Page Byte Values
- ---- ----------------------
- 0 1 2 3
- 4 0xFF 0xFF 0xFF 0xFF
- 5..15 0x00 0x00 0x00 0x00
-
- ACCESSING DATA BLOCKS
- =====================
-
- Before you can access the cards, you must following two steps:
-
- 1.) 'Connect' to a Mifare Ultralight card and retrieve the 7 byte
- UID of the card.
-
- 2.) Memory can be read and written directly once a passive mode
- connection has been made. No authentication is required for
- Mifare Ultralight cards.
-
-*/
-
-#include <string.h>
-
-#include "../pn532.h"
-#include "../pn532_bus.h"
-#include "pn532_mifare_ultralight.h"
-
-#include "core/systick/systick.h"
-
-/**************************************************************************/
-/*!
- Tries to detect MIFARE targets in passive mode.
-
- @param pbtCUID Pointer to the byte array where the card's 7 byte
- UID will be stored once a card is detected
- @param pszUIDLen Pointer to the size of the card UID in bytes
-
- Response for a valid ISO14443A 106KBPS (Mifare Ultralight, etc.)
- should be in the following format. See UM0701-02 section
- 7.3.5 for more information
-
- byte Description
- ------------- ------------------------------------------
- b0..6 Frame header and preamble
- b7 Tags Found
- b8 Tag Number (only one used in this example)
- b9..10 SENS_RES
- b11 SEL_RES
- b12 NFCID Length
- b13..NFCIDLen NFCID
-
- SENS_RES SEL_RES Manufacturer/Card Type NFCID Len
- -------- ------- ----------------------- ---------
- 00 44 00 NXP Mifare Ultralight 7 bytes
-
- @note Possible error messages are:
-
- - PN532_ERROR_WRONGCARDTYPE
-*/
-/**************************************************************************/
-pn532_error_t pn532_mifareultralight_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen)
-{
- byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET];
- pn532_error_t error;
- size_t szLen;
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE);
- #endif
-
- /* Try to initialise a single ISO14443A tag at 106KBPS */
- /* Note: To wait for a card with a known UID, append the four byte */
- /* UID to the end of the command. */
- byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS};
- error = pn532Write(abtCommand, sizeof(abtCommand));
- if (error)
- return error;
-
- /* Wait until we get a valid response or a timeout */
- do
- {
- systickDelay(25);
- error = pn532Read(abtResponse, &szLen);
- } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
- if (error)
- return error;
-
- /* Check SENS_RES to make sure this is a Mifare Ultralight card */
- /* Mifare Ultralight = 00 44 */
- if (abtResponse[10] == 0x44)
- {
- /* Card appears to be Mifare Ultralight */
- *szCUIDLen = abtResponse[12];
- uint8_t i;
- for (i=0; i < *szCUIDLen; i++)
- {
- pbtCUID[i] = abtResponse[13+i];
- }
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" ATQA: ");
- pn532PrintHex(abtResponse+9, 2);
- PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" UID: ");
- pn532PrintHex(pbtCUID, *szCUIDLen);
- #endif
- }
- else
- {
- /* Card is ISO14443A but doesn't appear to be Mifare Ultralight */
- /* Mifare Classic = 0x0002, 0x0004, 0x0008 */
- /* Mifare DESFire = 0x0344 */
- /* Innovision Jewel = 0x0C00 */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Wrong Card Type (Expected ATQA 00 44) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" ATQA : ");
- pn532PrintHex(abtResponse+9, 2);
- PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE);
- PN532_DEBUG(" UID : ");
- size_t pos;
- for (pos=0; pos < abtResponse[12]; pos++)
- {
- printf("%02x ", abtResponse[13 + pos]);
- }
- printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_WRONGCARDTYPE;
- }
-
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- Tries to read an entire 4-byte page at the specified address.
-
- @param page The page number (0..63 in most cases)
- @param pbtBuffer Pointer to the byte array that will hold the
- retrieved data (if any)
-
- @note Possible error messages are:
-
- - PN532_ERROR_ADDRESSOUTOFRANGE
- - PN532_ERROR_BLOCKREADFAILED
-*/
-/**************************************************************************/
-pn532_error_t pn532_mifareultralight_ReadPage (uint8_t page, byte_t * pbtBuffer)
-{
- pn532_error_t error;
- byte_t abtCommand[4];
- byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
- size_t szLen;
-
- if (page >= 64)
- {
- return PN532_ERROR_ADDRESSOUTOFRANGE;
- }
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Reading page %03d%s", page, CFG_PRINTF_NEWLINE);
- #endif
-
- /* Prepare the command */
- abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE;
- abtCommand[1] = 1; /* Card number */
- abtCommand[2] = PN532_MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
- abtCommand[3] = page; /* Page Number (0..63 in most cases) */
-
- /* Send the commands */
- error = pn532Write(abtCommand, sizeof(abtCommand));
- if (error)
- {
- /* Bus error, etc. */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return error;
- }
-
- /* Read the response */
- memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
- do
- {
- systickDelay(50);
- error = pn532Read(abtResponse, &szLen);
- }
- while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
- if (error)
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return error;
- }
-
- /* Make sure we have a valid response (should be 26 bytes long) */
- if (szLen == 26)
- {
- /* Copy the 4 data bytes to the output buffer */
- /* Block content starts at byte 9 of a valid response */
- /* Note that the command actually reads 16 byte or 4 */
- /* pages at a time ... we simply discard the last 12 */
- /* bytes */
- memcpy (pbtBuffer, abtResponse+8, 4);
- }
- else
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Unexpected response reading block %d. Bad key?%s", page, CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_BLOCKREADFAILED;
- }
-
- /* Display data for debug if requested */
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Page %02d: ", page, CFG_PRINTF_NEWLINE);
- pn532PrintHexVerbose(pbtBuffer, 4);
- #endif
-
- // Return OK signal
- return PN532_ERROR_NONE;
-}
-
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_mifare_ultralight.h
-*/
-/**************************************************************************/
-
-#ifndef __PN532_MIFARE_ULTRALIGHT_H__
-#define __PN532_MIFARE_ULTRALIGHT_H__
-
-#include "projectconfig.h"
-#include "pn532_mifare.h"
-
-pn532_error_t pn532_mifareultralight_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen);
-pn532_error_t pn532_mifareultralight_ReadPage (uint8_t page, byte_t * pbtBuffer);
-
-#endif
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532.c
-*/
-/**************************************************************************/
-#include <string.h>
-
-#include "pn532.h"
-#include "pn532_bus.h"
-#include "core/systick/systick.h"
-#include "core/uart/uart.h"
-
-static pn532_pcb_t pcb;
-
-/**************************************************************************/
-/*!
- @brief Prints a hexadecimal value in plain characters
-
- @param pbtData Pointer to the byte data
- @param szBytes Data length in bytes
-*/
-/**************************************************************************/
-void pn532PrintHex(const byte_t * pbtData, const size_t szBytes)
-{
- size_t szPos;
- for (szPos=0; szPos < szBytes; szPos++)
- {
- printf("%02x ", pbtData[szPos]);
- }
- printf(CFG_PRINTF_NEWLINE);
-}
-
-/**************************************************************************/
-/*!
- @brief Prints a hexadecimal value in plain characters, along with
- the char equivalents in the following format
-
- AA BB CC DD EE FF ......
-
- @param pbtData Pointer to the byte data
- @param szBytes Data length in bytes
-*/
-/**************************************************************************/
-void pn532PrintHexChar(const byte_t * pbtData, const size_t szBytes)
-{
- size_t szPos;
- for (szPos=0; szPos < szBytes; szPos++)
- {
- printf("%02x", pbtData[szPos]);
- }
- printf(" ");
- for (szPos=0; szPos < szBytes; szPos++)
- {
- printf("%c", pbtData[szPos] <= 0x1F ? '.' : pbtData[szPos]);
- }
- printf(CFG_PRINTF_NEWLINE);
-}
-
-/**************************************************************************/
-/*!
- @brief Gets a reference to the PN532 peripheral control block,
- which can be used to determine that state of the PN532
- IC, buffers, etc.
-*/
-/**************************************************************************/
-pn532_pcb_t * pn532GetPCB()
-{
- return &pcb;
-}
-
-/**************************************************************************/
-/*!
- @brief Initialises the appropriate serial bus (UART, etc.),and
- sets up any buffers or peripherals required by the PN532.
-*/
-/**************************************************************************/
-void pn532Init(void)
-{
- // Clear protocol control blocks
- memset(&pcb, 0, sizeof(pn532_pcb_t));
-
- // Initialise the underlying HW
- pn532_bus_HWInit();
-
- // Set the PCB flags to an appropriate state
- pcb.initialised = TRUE;
-}
-
-/**************************************************************************/
-/*!
- @brief Reads the response buffer from the PN532
-
- @param pbtResponse
- The byte array that will hold the response data
- @param pszLen
- Pointer to the number of bytes in pbtCommand
-*/
-/**************************************************************************/
-pn532_error_t pn532Read(byte_t * pbtResponse, size_t * pszLen)
-{
- if (!pcb.initialised) pn532Init();
-
- // Try to wake the device up if it's in sleep mode
- if (pcb.state == PN532_STATE_SLEEP)
- {
- pn532_error_t wakeupError = pn532_bus_Wakeup();
- if (wakeupError)
- return wakeupError;
- }
-
- // Read the response if the device is in an appropriate state
- if (pcb.state == PN532_STATE_READY)
- {
- return pn532_bus_ReadResponse(pbtResponse, pszLen);
- }
- else
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Init Failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_UNABLETOINIT;
- }
-}
-
-/**************************************************************************/
-/*!
- @brief Sends a byte array of command and parameter data to the
- PN532, starting with the command byte. The frame's
- preamble, checksums, postamble and frame identifier (0xD4)
- will all be automatically added.
-
- @param abtCommand
- The byte array containg the command and any
- optional parameters
- @param szLen
- The number of bytes in abtCommand
-*/
-/**************************************************************************/
-pn532_error_t pn532Write(byte_t * abtCommand, size_t szLen)
-{
- if (!pcb.initialised) pn532Init();
-
- // Try to wake the device up if it's in sleep mode
- if (pcb.state == PN532_STATE_SLEEP)
- {
- pn532_error_t wakeupError = pn532_bus_Wakeup();
- if (wakeupError)
- return wakeupError;
- }
-
- // Send the command if the device is in an appropriate state
- if (pcb.state == PN532_STATE_READY)
- {
- return pn532_bus_SendCommand(abtCommand, szLen);
- }
- else
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Init Failed%s", CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_UNABLETOINIT;
- }
-}
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532.h
-*/
-/**************************************************************************/
-
-#ifndef __PN532_H__
-#define __PN532_H__
-
-#include "projectconfig.h"
-
-// Comment out this line to disable debug output
-// #define PN532_DEBUGMODE
-#define PN532_DEBUG(fmt, args...) printf(fmt, ##args)
-
-/* Error messages generated by the stack */
-/* Not to be confused with app level errors from the PN532 */
-/* These are the errors that are returned by the PN532 driver */
-typedef enum pn532_error_e
-{
- PN532_ERROR_NONE = 0x00,
- PN532_ERROR_UNABLETOINIT = 0x01, // Unable to initialise or wakeup the device
- PN532_ERROR_APPLEVELERROR = 0x02, // Application level error detected
- PN532_ERROR_BUSY = 0x03, // Busy executing a previous command
- PN532_ERROR_NOACK = 0x04, // No ack message received
- PN532_ERROR_INVALIDACK = 0x05, // Ack != 00 00 FF 00 FF 00
- PN532_ERROR_PREAMBLEMISMATCH = 0x06, // Frame preamble + start code mismatch
- PN532_ERROR_EXTENDEDFRAME = 0x07, // Extended frames currently unsupported
- PN532_ERROR_LENCHECKSUMMISMATCH = 0x08,
- PN532_ERROR_RESPONSEBUFFEREMPTY = 0x09, // No response data received
- PN532_ERROR_READYSTATUSTIMEOUT = 0x0A, // Timeout waiting for 'ready' status (SPI/I2C only)
- PN532_ERROR_TIMEOUTWAITINGFORCARD = 0x0B, // No card detected in field with the specified timeout
- PN532_ERROR_BLOCKREADFAILED = 0x0C, // Unexpected response to block read request
- PN532_ERROR_WRONGCARDTYPE = 0x0D, // Card is not the expected format (based on SENS_RES/ATQA value)
- PN532_ERROR_ADDRESSOUTOFRANGE = 0x0E, // Specified block and page is out of range
- PN532_ERROR_I2C_NACK = 0x0F // I2C Bus - No ACK was received for master to slave data transfer
-} pn532_error_t;
-
-typedef enum pn532_modulation_e
-{
- PN532_MODULATION_ISO14443A_106KBPS = 0x00,
- PN532_MODULATION_FELICA_212KBPS = 0x01,
- PN532_MODULATION_FELICA_424KBPS = 0x02,
- PN532_MODULATION_ISO14443B_106KBPS = 0x03,
- PN532_MODULATION_JEWEL_106KBPS = 0x04
-} pn532_modulation_t;
-
-/* HW Commands for the PN532. */
-/* See UM0701-02 - PN532 User Manual */
-enum
-{
- PN532_COMMAND_DIAGNOSE = 0x00,
- PN532_COMMAND_GETFIRMWAREVERSION = 0x02,
- PN532_COMMAND_GETGENERALSTATUS = 0x04,
- PN532_COMMAND_READREGISTER = 0x06,
- PN532_COMMAND_WRITEREGISTER = 0x08,
- PN532_COMMAND_READGPIO = 0x0C,
- PN532_COMMAND_WRITEGPIO = 0x0E,
- PN532_COMMAND_SETSERIALBAUDRATE = 0x10,
- PN532_COMMAND_SETPARAMETERS = 0x12,
- PN532_COMMAND_SAMCONFIGURATION = 0x14,
- PN532_COMMAND_POWERDOWN = 0x16,
- PN532_COMMAND_RFCONFIGURATION = 0x32,
- PN532_COMMAND_RFREGULATIONTEST = 0x58,
- PN532_COMMAND_INJUMPFORDEP = 0x56,
- PN532_COMMAND_INJUMPFORPSL = 0x46,
- PN532_COMMAND_INLISTPASSIVETARGET = 0x4A,
- PN532_COMMAND_INATR = 0x50,
- PN532_COMMAND_INPSL = 0x4E,
- PN532_COMMAND_INDATAEXCHANGE = 0x40,
- PN532_COMMAND_INCOMMUNICATETHRU = 0x42,
- PN532_COMMAND_INDESELECT = 0x44,
- PN532_COMMAND_INRELEASE = 0x52,
- PN532_COMMAND_INSELECT = 0x54,
- PN532_COMMAND_INAUTOPOLL = 0x60,
- PN532_COMMAND_TGINITASTARGET = 0x8C,
- PN532_COMMAND_TGSETGENERALBYTES = 0x92,
- PN532_COMMAND_TGGETDATA = 0x86,
- PN532_COMMAND_TGSETDATA = 0x8E,
- PN532_COMMAND_TGSETMETADATA = 0x94,
- PN532_COMMAND_TGGETINITIATORCOMMAND = 0x88,
- PN532_COMMAND_TGRESPONSETOINITIATOR = 0x90,
- PN532_COMMAND_TGGETTARGETSTATUS = 0x8A
-};
-
-/* Application level errors generated by the PN532 chip */
-/* See UM0701-02 - PN532 User Manual */
-enum
-{
- PN532_APPERROR_NONE = 0x00,
- PN532_APPERROR_TIMEOUT = 0x01,
- PN532_APPERROR_CRCERROR = 0x02,
- PN532_APPERROR_PARITYERROR = 0x04,
- PN532_APPERROR_FRAMINGERROR = 0x05,
- PN532_APPERROR_BITCOLLISION = 0x06,
- PN532_APPERROR_INSUFFICIENTBUFFER = 0x07,
- PN532_APPERROR_RFBUFFEROVERFLOW = 0x09,
- PN532_APPERROR_RFFIELDTIMEOUT = 0x0A,
- PN532_APPERROR_RFPROTOCOLERROR = 0x0B,
- PN532_APPERROR_TEMPERROR = 0x0D,
- PN532_APPERROR_INTERNBUFFEROVERFLOW = 0x0E,
- PN532_APPERROR_INVALIDPARAMETER = 0x10,
- PN532_APPERROR_DEP_UNSUPPORTEDCMD = 0x12,
- PN532_APPERROR_DEP_INVALIDOFORMAT = 0x13,
- PN532_APPERROR_AUTHENTERR = 0x14,
- PN532_APPERROR_UIDCCHECKERROR = 0x23,
- PN532_APPERROR_DEP_INVALIDDEVSTATE = 0x25,
- PN532_APPERROR_OPERATIONNOTALLOWED = 0x26,
- PN532_APPERROR_CMDNOTACCEPTABLE = 0x27,
- PN532_APPERROR_TARGETRELEASED = 0x29,
- PN532_APPERROR_IDMISMATCH = 0x2A,
- PN532_APPERROR_CARDDISAPPEARED = 0x2B,
- PN532_APPERROR_NFCID3MISMATCH = 0x2C,
- PN532_APPERROR_OVERCURRENTEVENT = 0x2D,
- PN532_APPERROR_NADMISSINGINDEP = 0x2E
-};
-
-/* Possible states for the PN532 SW Stack */
-typedef enum pn532_state_e
-{
- PN532_STATE_SLEEP,
- PN532_STATE_READY,
- PN532_STATE_BUSY
-}
-pn532_state_t;
-
-/* PN532 Protocol control block */
-typedef struct
-{
- BOOL initialised;
- pn532_state_t state;
- pn532_modulation_t modulation;
- uint32_t lastCommand;
- uint32_t appError;
-} pn532_pcb_t;
-
-void pn532PrintHex(const byte_t * pbtData, const size_t szBytes);
-void pn532PrintHexChar(const byte_t * pbtData, const size_t szBytes);
-pn532_pcb_t * pn532GetPCB();
-void pn532Init();
-pn532_error_t pn532Read(byte_t *pbtResponse, size_t * pszLen);
-pn532_error_t pn532Write(byte_t *abtCommand, size_t szLen);
-
-#endif
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_bus.h
-*/
-/**************************************************************************/
-
-#ifndef __PN532_BUS_H__
-#define __PN532_BUS_H__
-
-#include "projectconfig.h"
-#include "pn532.h"
-
-// #define PN532_BUS_UART
-#define PN532_BUS_I2C
-
-#define PN532_RSTPD_PORT (3)
-#define PN532_RSTPD_PIN (1)
-#define PN532_I2C_IRQPORT (3)
-#define PN532_I2C_IRQPIN (2)
-
-#define PN532_NORMAL_FRAME__DATA_MAX_LEN (254)
-#define PN532_NORMAL_FRAME__OVERHEAD (8)
-#define PN532_EXTENDED_FRAME__DATA_MAX_LEN (264)
-#define PN532_EXTENDED_FRAME__OVERHEAD (11)
-#define PN532_BUFFER_LEN (PN532_EXTENDED_FRAME__DATA_MAX_LEN + PN532_EXTENDED_FRAME__OVERHEAD)
-
-#define PN532_UART_BAUDRATE (115200)
-
-#define PN532_I2C_ADDRESS (0x48)
-#define PN532_I2C_READBIT (0x01)
-#define PN532_I2C_READYTIMEOUT (20) // Max number of attempts to read Ready bit (see UM 5-Nov-2007 Section 6.2.4)
-
-// Generic interface for the different serial buses available on the PN532
-void pn532_bus_HWInit(void);
-pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData);
-pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen);
-pn532_error_t pn532_bus_Wakeup(void);
-
-#endif
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_bus_i2c.c
- @author K. Townsend (microBuilder.eu)
-
- @section LICENSE
-
- Software License Agreement (BSD License)
-
- Copyright (c) 2012, microBuilder SARL
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the copyright holders nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-/**************************************************************************/
-#include <string.h>
-
-#include "pn532.h"
-#include "pn532_bus.h"
-
-#ifdef PN532_BUS_I2C
-
-#include "core/systick/systick.h"
-#include "core/gpio/gpio.h"
-#include "core/i2c/i2c.h"
-
-extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
-extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
-extern volatile uint32_t I2CReadLength, I2CWriteLength;
-
-/* ======================================================================
- PRIVATE FUNCTIONS
- ====================================================================== */
-
-/**************************************************************************/
-/*!
- @brief Writes an 8 bit value over I2C
-
- @note Possible error messages are:
-
- - PN532_ERROR_I2C_NACK
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_i2c_WriteData (const byte_t * pbtData, const size_t szData)
-{
- uint32_t i2cState;
-
- // Clear write buffers
- uint32_t i;
- for ( i = 0; i < I2C_BUFSIZE; i++ )
- {
- I2CMasterBuffer[i] = 0x00;
- }
-
- // Send the specified bytes
- I2CWriteLength = szData+1;
- I2CReadLength = 0;
- I2CMasterBuffer[0] = PN532_I2C_ADDRESS; // I2C device address
- for ( i = 0; i < szData; i++ )
- {
- I2CMasterBuffer[i+1] = pbtData[i];
- }
- i2cState = i2cEngine();
-
- // Check if we got an ACK
- if ((i2cState == I2CSTATE_NACK) || (i2cState == I2CSTATE_SLA_NACK))
- {
- // I2C slave didn't acknowledge the master transfer
- // The PN532 probably isn't connected properly or the
- // bus select pins are in the wrong state
- return PN532_ERROR_I2C_NACK;
- }
-
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- @brief Checks the 'IRQ' pin to know if the PN532 is ready to send
- a response or not
-
- @note The IRQ bit may stay high intentionally, and this isn't
- always an error condition. When PN532_COMMAND_INLISTPASSIVETARGET
- is sent, for example, the PN532 will wait until a card
- enters the magnetic field, and IRQ will remain high since
- there is no response ready yet. The IRQ pin will go low
- as soon as a card enters the magentic field and the data
- has been retrieved from it.
-
- @returns 1 if a response is ready, 0 if the PN532 is still busy or a
- timeout occurred
-*/
-/**************************************************************************/
-uint8_t pn532_bus_i2c_WaitForReady(void)
-{
- uint8_t busy = 1;
- // uint8_t busyTimeout = 0;
-
- while (busy)
- {
- // For now, we wait forever until a command is ready
- // ToDo: Add user-specified timeout
- busy = gpioGetValue(PN532_I2C_IRQPORT, PN532_I2C_IRQPIN);
- systickDelay(1);
- // busyTimeout++;
- // if (busyTimeout == PN532_I2C_READYTIMEOUT)
- // {
- // return false;
- // }
- }
-
- return true;
-}
-
-/**************************************************************************/
-/*!
- @brief Builds a standard PN532 frame using the supplied data
-
- @param pbtFrame Pointer to the field that will hold the frame data
- @param pszFrame Pointer to the field that will hold the frame length
- @param pbtData Pointer to the data to insert in a frame
- @param swData Length of the data to insert in bytes
-
- @note Possible error messages are:
-
- - PN532_ERROR_EXTENDEDFRAME
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_i2c_BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
-{
- if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
- {
- // Extended frames currently unsupported
- return PN532_ERROR_EXTENDEDFRAME;
- }
-
- // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
- pbtFrame[3] = szData + 1;
- // LCS - Packet length checksum
- pbtFrame[4] = 256 - (szData + 1);
- // TFI
- pbtFrame[5] = 0xD4;
- // DATA - Copy the PN53X command into the packet buffer
- memcpy (pbtFrame + 6, pbtData, szData);
-
- // DCS - Calculate data payload checksum
- byte_t btDCS = (256 - 0xD4);
- size_t szPos;
- for (szPos = 0; szPos < szData; szPos++)
- {
- btDCS -= pbtData[szPos];
- }
- pbtFrame[6 + szData] = btDCS;
-
- // 0x00 - End of stream marker
- pbtFrame[szData + 7] = 0x00;
-
- (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
-
- return PN532_ERROR_NONE;
-}
-
-/* ======================================================================
- PUBLIC FUNCTIONS
- ====================================================================== */
-
-/**************************************************************************/
-/*!
- @brief Initialises I2C and configures the PN532 HW
-*/
-/**************************************************************************/
-void pn532_bus_HWInit(void)
-{
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Initialising I2C %s", CFG_PRINTF_NEWLINE);
- #endif
- i2cInit(I2CMASTER);
-
- // Set IRQ pin to input
- gpioSetDir(PN532_I2C_IRQPORT, PN532_I2C_IRQPIN, gpioDirection_Input);
-
- // Set reset pin as output and reset device
- gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Resetting the PN532...\r\n");
- #endif
- gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
- systickDelay(400);
- gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
-
- // Wait for the PN532 to finish booting
- systickDelay(100);
-}
-
-/**************************************************************************/
-/*!
- @brief Sends the specified command to the PN532, automatically
- creating an appropriate frame for it
-
- @param pdbData Pointer to the byte data to send
- @param szData Length in bytes of the data to send
-
- @note Possible error messages are:
-
- - PN532_ERROR_EXTENDEDFRAME // Extended frames not supported
- - PN532_ERROR_BUSY // Already busy with a command
- - PN532_ERROR_I2C_NACK // No ACK on I2C
- - PN532_ERROR_READYSTATUSTIMEOUT // Timeout waiting for ready bit
- - PN532_ERROR_INVALIDACK // No ACK frame received
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
-{
- pn532_error_t error = PN532_ERROR_NONE;
- pn532_pcb_t *pn532 = pn532GetPCB();
-
- // Check if we're busy
- if (pn532->state == PN532_STATE_BUSY)
- {
- return PN532_ERROR_BUSY;
- }
-
- // Flag the stack as busy
- pn532->state = PN532_STATE_BUSY;
-
- // --------------------------------------------------------------------
- // Send the command frame
- // --------------------------------------------------------------------
- byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
- size_t szFrame = 0;
-
- // Build the frame
- pn532_bus_i2c_BuildFrame (abtFrame, &szFrame, pbtData, szData);
-
- // Keep track of the last command that was sent
- pn532->lastCommand = pbtData[0];
-
- // Output the frame data for debugging if requested
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Sending (%02d): ", szFrame);
- pn532PrintHex(abtFrame, szFrame);
- #endif
-
- // Send data to the PN532
- error = pn532_bus_i2c_WriteData(abtFrame, szFrame);
-
- if (error == PN532_ERROR_I2C_NACK)
- {
- // Most likely error is PN532_ERROR_I2C_NACK
- // meaning no I2C ACK received from the PN532
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG ("No ACK received on I2C bus%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return error;
- }
-
- // --------------------------------------------------------------------
- // Wait for the IRQ/Ready flag
- // --------------------------------------------------------------------
- if (!(pn532_bus_i2c_WaitForReady()))
- {
- pn532->state = PN532_STATE_READY;
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_READYSTATUSTIMEOUT;
- }
-
- // --------------------------------------------------------------------
- // Read the ACK frame
- // --------------------------------------------------------------------
- uint32_t i;
- // Clear buffer
- for ( i = 0; i < I2C_BUFSIZE; i++ )
- {
- I2CMasterBuffer[i] = 0x00;
- }
- I2CWriteLength = 0;
- I2CReadLength = 7; // ACK + Ready bit = 7
- I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
- i2cEngine();
-
- // Make sure the received ACK matches the prototype
- const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
- byte_t abtRxBuf[6];
- // memcpy(abtRxBuf, I2CSlaveBuffer+1, 6);
- for ( i = 0; i < 6; i++ )
- {
- abtRxBuf[i] = I2CSlaveBuffer[i+1];
- }
- if (0 != (memcmp (abtRxBuf, abtAck, 6)))
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG ("Invalid ACK: ");
- pn532PrintHex(abtRxBuf, 6);
- PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_INVALIDACK;
- }
-
- // --------------------------------------------------------------------
- // Wait for the post-ACK IRQ/Ready flag
- // --------------------------------------------------------------------
- if (!(pn532_bus_i2c_WaitForReady()))
- {
- pn532->state = PN532_STATE_READY;
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
- #endif
- return PN532_ERROR_READYSTATUSTIMEOUT;
- }
-
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- @brief Reads a response from the PN532
-
- @note Possible error message are:
-
- - PN532_ERROR_BUSY
- - PN532_ERROR_RESPONSEBUFFEREMPTY
- - PN532_ERROR_PREAMBLEMISMATCH
- - PN532_ERROR_APPLEVELERROR
- - PN532_ERROR_EXTENDEDFRAME
- - PN532_ERROR_LENCHECKSUMMISMATCH
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
-{
- pn532_pcb_t *pn532 = pn532GetPCB();
-
- // Check if we're busy
- if (pn532->state == PN532_STATE_BUSY)
- {
- return PN532_ERROR_BUSY;
- }
-
- // Flag the stack as busy
- pn532->state = PN532_STATE_BUSY;
-
- // Reset the app error flag
- pn532->appError = PN532_APPERROR_NONE;
-
- uint32_t i;
- for ( i = 0; i < I2C_BUFSIZE; i++ )
- {
- I2CMasterBuffer[i] = 0x00;
- }
- I2CWriteLength = 0;
- I2CReadLength = I2C_BUFSIZE;
- I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
- i2cEngine();
-
- // Display the raw response data for debugging if requested
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Received (%02d): ", I2C_BUFSIZE-1);
- pn532PrintHex(pbtResponse, I2C_BUFSIZE-1);
- #endif
-
- // Use the full I2C buffer size for now (until we're sure we have a good frame)
- *pszRxLen = I2C_BUFSIZE - 1;
-
- // Fill the response buffer from I2C (skipping the leading 'ready' bit when using I2C)
- // memcpy(pbtResponse, I2CSlaveBuffer+1, I2C_BUFSIZE-1);
- for ( i = 0; i < I2C_BUFSIZE-1; i++ )
- {
- pbtResponse[i] = I2CSlaveBuffer[i+1];
- }
-
- // Check the frame type
- if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
- {
- // Error frame
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
- #endif
- // Set application error message ID
- pn532->appError = pbtResponse[5];
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_APPLEVELERROR;
- }
- else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
- {
- // Extended frame
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_EXTENDEDFRAME;
- }
- else
- {
- // Normal frame
- if (256 != (pbtResponse[3] + pbtResponse[4]))
- {
- // TODO: Retry
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_LENCHECKSUMMISMATCH;
- }
- }
-
- // Figure out how large the response really is
- // Response Frame Len = pbtResponse[3] + 7 (00 00 FF LEN LCS TFI [DATA] DCS)
- *pszRxLen = pbtResponse[3] + 7;
-
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- @brief Sends the wakeup sequence to the PN532.
-
- @note Possible error message are:
-
- - PN532_ERROR_BUSY
- - PN532_ERROR_I2C_NACK // No I2C ACK
- - PN532_ERROR_READYSTATUSTIMEOUT // Timed out waiting for ready bit
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_Wakeup(void)
-{
- pn532_error_t error = PN532_ERROR_NONE;
- byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
- uint32_t i;
-
- pn532_pcb_t *pn532 = pn532GetPCB();
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
- #endif
- error = pn532_bus_i2c_WriteData(abtWakeUp,sizeof(abtWakeUp));
- systickDelay(100);
-
- // Wait for the IRQ/Ready flag to indicate a response is ready
- if (!(pn532_bus_i2c_WaitForReady()))
- {
- error = PN532_ERROR_READYSTATUSTIMEOUT;
- }
-
- // Read and discard the ACK frame
- for ( i = 0; i < I2C_BUFSIZE; i++ )
- {
- I2CMasterBuffer[i] = 0x00;
- }
- I2CWriteLength = 0;
- I2CReadLength = 7; // ACK + Ready bit = 7
- I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
- i2cEngine();
- systickDelay(1);
-
- // Wait for the IRQ/Ready flag to indicate a response is ready
- if (!(pn532_bus_i2c_WaitForReady()))
- {
- error = PN532_ERROR_READYSTATUSTIMEOUT;
- }
-
- pn532->state = PN532_STATE_READY;
- return error;
-}
-
-#endif // #ifdef PN532_BUS_I2C
\ No newline at end of file
+++ /dev/null
-/**************************************************************************/
-/*!
- @file pn532_bus_uart.c
-*/
-/**************************************************************************/
-#include <string.h>
-
-#include "pn532.h"
-#include "pn532_bus.h"
-
-#ifdef PN532_BUS_UART
-
-#include "core/systick/systick.h"
-#include "core/gpio/gpio.h"
-#include "core/uart/uart.h"
-
-/**************************************************************************/
-/*!
- @brief Builds a standard PN532 frame using the supplied data
-
- @param pbtFrame Pointer to the field that will hold the frame data
- @param pszFrame Pointer to the field that will hold the frame length
- @param pbtData Pointer to the data to insert in a frame
- @param swData Length of the data to insert in bytes
-
- @note Possible error messages are:
-
- - PN532_ERROR_EXTENDEDFRAME
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
-{
- if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
- {
- // Extended frames currently unsupported
- return PN532_ERROR_EXTENDEDFRAME;
- }
-
- // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
- pbtFrame[3] = szData + 1;
- // LCS - Packet length checksum
- pbtFrame[4] = 256 - (szData + 1);
- // TFI
- pbtFrame[5] = 0xD4;
- // DATA - Copy the PN53X command into the packet buffer
- memcpy (pbtFrame + 6, pbtData, szData);
-
- // DCS - Calculate data payload checksum
- byte_t btDCS = (256 - 0xD4);
- size_t szPos;
- for (szPos = 0; szPos < szData; szPos++)
- {
- btDCS -= pbtData[szPos];
- }
- pbtFrame[6 + szData] = btDCS;
-
- // 0x00 - End of stream marker
- pbtFrame[szData + 7] = 0x00;
-
- (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
-
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- @brief Initialises UART and configures the PN532
-*/
-/**************************************************************************/
-void pn532_bus_HWInit(void)
-{
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Initialising UART (%d)%s", PN532_UART_BAUDRATE, CFG_PRINTF_NEWLINE);
- #endif
- uartInit(PN532_UART_BAUDRATE);
-
- // Set reset pin as output and reset device
- gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Resetting the PN532...\r\n");
- #endif
- gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
- systickDelay(400);
- gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
-
- // Wait for the PN532 to finish booting
- systickDelay(100);
-}
-
-/**************************************************************************/
-/*!
- @brief Sends the specified command to the PN532, automatically
- creating an appropriate frame for it
-
- @param pdbData Pointer to the byte data to send
- @param szData Length in bytes of the data to send
-
- @note Possible error messages are:
-
- - PN532_ERROR_BUSY
- - PN532_ERROR_NOACK
- - PN532_ERROR_INVALIDACK
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
-{
- pn532_pcb_t *pn532 = pn532GetPCB();
-
- // Check if we're busy
- if (pn532->state == PN532_STATE_BUSY)
- {
- return PN532_ERROR_BUSY;
- }
-
- // Flag the stack as busy
- pn532->state = PN532_STATE_BUSY;
-
- // Every packet must start with "00 00 ff"
- byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
- size_t szFrame = 0;
-
- // Build the frame
- pn532_bus_BuildFrame (abtFrame, &szFrame, pbtData, szData);
-
- // Keep track of the last command that was sent
- pn532->lastCommand = pbtData[0];
-
- // Output the frame data for debugging if requested
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Sending (%02d): ", szFrame);
- pn532PrintHex(abtFrame, szFrame);
- #endif
-
- // Send data to the PN532
- uartSend (abtFrame, szFrame);
-
- // Wait for ACK
- byte_t abtRxBuf[6];
- uart_pcb_t *uart = uartGetPCB();
- systickDelay(10); // FIXME: How long should we wait for ACK?
- if (uart->rxfifo.len < 6)
- {
- // Unable to read ACK
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_NOACK;
- }
-
- // Read ACK ... this will also remove it from the buffer
- const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
- abtRxBuf[0] = uartRxBufferRead();
- abtRxBuf[1] = uartRxBufferRead();
- abtRxBuf[2] = uartRxBufferRead();
- abtRxBuf[3] = uartRxBufferRead();
- abtRxBuf[4] = uartRxBufferRead();
- abtRxBuf[5] = uartRxBufferRead();
-
- // Make sure the received ACK matches the prototype
- if (0 != (memcmp (abtRxBuf, abtAck, 6)))
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG ("Invalid ACK: ");
- pn532PrintHex(abtRxBuf, 6);
- PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_INVALIDACK;
- }
-
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- @brief Reads a response from the PN532
-
- @note Possible error message are:
-
- - PN532_ERROR_BUSY
- - PN532_ERROR_RESPONSEBUFFEREMPTY
- - PN532_ERROR_PREAMBLEMISMATCH
- - PN532_ERROR_APPLEVELERROR
- - PN532_ERROR_EXTENDEDFRAME
- - PN532_ERROR_LENCHECKSUMMISMATCH
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
-{
- pn532_pcb_t *pn532 = pn532GetPCB();
-
- // Check if we're busy
- if (pn532->state == PN532_STATE_BUSY)
- {
- return PN532_ERROR_BUSY;
- }
-
- // Flag the stack as busy
- pn532->state = PN532_STATE_BUSY;
-
- // Reset the app error flag
- pn532->appError = PN532_APPERROR_NONE;
-
- // Read response from uart
- if (!uartRxBufferReadArray(pbtResponse, pszRxLen))
- {
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_RESPONSEBUFFEREMPTY;
- }
-
- // Display the raw response data for debugging if requested
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Received (%02d): ", *pszRxLen);
- pn532PrintHex(pbtResponse, *pszRxLen);
- #endif
-
- // Check preamble
- const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
- if (0 != (memcmp (pbtResponse, pn53x_preamble, 3)))
- {
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_PREAMBLEMISMATCH;
- }
-
- // Check the frame type
- if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
- {
- // Error frame
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
- #endif
- // Set application error message ID
- pn532->appError = pbtResponse[5];
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_APPLEVELERROR;
- }
- else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
- {
- // Extended frame
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_EXTENDEDFRAME;
- }
- else
- {
- // Normal frame
- if (256 != (pbtResponse[3] + pbtResponse[4]))
- {
- // TODO: Retry
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
- #endif
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_LENCHECKSUMMISMATCH;
- }
- // size_t szPayloadLen = abtRx[3] - 2;
- }
-
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_NONE;
-}
-
-/**************************************************************************/
-/*!
- @brief Sends the wakeup sequence to the PN532.
-*/
-/**************************************************************************/
-pn532_error_t pn532_bus_Wakeup(void)
-{
- size_t szLen;
- byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
-
- pn532_pcb_t *pn532 = pn532GetPCB();
-
- #ifdef PN532_DEBUGMODE
- PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
- #endif
- uartSend(abtWakeUp,sizeof(abtWakeUp));
- systickDelay(100);
-
- byte_t response[32];
- pn532_bus_ReadResponse(response, &szLen);
-
- // Todo: Check for error ... currently throws a checksum error
- // that isn't really an error
-
- pn532->state = PN532_STATE_READY;
- return PN532_ERROR_NONE;
-}
-
-#endif // #ifdef PN532_BUS_UART
\ No newline at end of file