From: Kevin Townsend Date: Sat, 10 Mar 2012 00:44:48 +0000 (+0100) Subject: Moved to /rf X-Git-Url: http://git.rohieb.name/hackover2013-badge-firmware.git/commitdiff_plain/eb5531b307f75eb3d3a3b6cee380072f8af187fd Moved to /rf --- diff --git a/drivers/chibi/chb.c b/drivers/chibi/chb.c deleted file mode 100644 index 2c02f1a..0000000 --- a/drivers/chibi/chb.c +++ /dev/null @@ -1,231 +0,0 @@ -/******************************************************************* - 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 -#include - -#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; idata + 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 -} - diff --git a/drivers/chibi/chb.h b/drivers/chibi/chb.h deleted file mode 100644 index 6fb7827..0000000 --- a/drivers/chibi/chb.h +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************* - 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 diff --git a/drivers/chibi/chb_buf.c b/drivers/chibi/chb_buf.c deleted file mode 100644 index a08c856..0000000 --- a/drivers/chibi/chb_buf.c +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************* - 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 -#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; -} diff --git a/drivers/chibi/chb_buf.h b/drivers/chibi/chb_buf.h deleted file mode 100644 index ec75812..0000000 --- a/drivers/chibi/chb_buf.h +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************* - 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 diff --git a/drivers/chibi/chb_drvr.c b/drivers/chibi/chb_drvr.c deleted file mode 100644 index fb78918..0000000 --- a/drivers/chibi/chb_drvr.c +++ /dev/null @@ -1,925 +0,0 @@ -/******************************************************************* - 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 -#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= 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; ioverflow++; - - // 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 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<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(); -} diff --git a/drivers/chibi/chb_drvr.h b/drivers/chibi/chb_drvr.h deleted file mode 100644 index 48990bb..0000000 --- a/drivers/chibi/chb_drvr.h +++ /dev/null @@ -1,374 +0,0 @@ -/******************************************************************* - 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 - diff --git a/drivers/chibi/chb_eeprom.c b/drivers/chibi/chb_eeprom.c deleted file mode 100644 index d7e5f09..0000000 --- a/drivers/chibi/chb_eeprom.c +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************* - 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); -} - diff --git a/drivers/chibi/chb_eeprom.h b/drivers/chibi/chb_eeprom.h deleted file mode 100644 index 3c3df71..0000000 --- a/drivers/chibi/chb_eeprom.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************* - 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 diff --git a/drivers/chibi/chb_spi.c b/drivers/chibi/chb_spi.c deleted file mode 100644 index e552184..0000000 --- a/drivers/chibi/chb_spi.c +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************* - 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; -} diff --git a/drivers/chibi/chb_spi.h b/drivers/chibi/chb_spi.h deleted file mode 100644 index 220feb7..0000000 --- a/drivers/chibi/chb_spi.h +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************* - 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 diff --git a/drivers/chibi/types.h b/drivers/chibi/types.h deleted file mode 100644 index c551bbc..0000000 --- a/drivers/chibi/types.h +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************* - 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 -#include - -// 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 diff --git a/drivers/rf/chibi/chb.c b/drivers/rf/chibi/chb.c new file mode 100644 index 0000000..2c02f1a --- /dev/null +++ b/drivers/rf/chibi/chb.c @@ -0,0 +1,231 @@ +/******************************************************************* + 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 +#include + +#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; idata + 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 +} + diff --git a/drivers/rf/chibi/chb.h b/drivers/rf/chibi/chb.h new file mode 100644 index 0000000..6fb7827 --- /dev/null +++ b/drivers/rf/chibi/chb.h @@ -0,0 +1,100 @@ +/******************************************************************* + 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 diff --git a/drivers/rf/chibi/chb_buf.c b/drivers/rf/chibi/chb_buf.c new file mode 100644 index 0000000..a08c856 --- /dev/null +++ b/drivers/rf/chibi/chb_buf.c @@ -0,0 +1,89 @@ +/******************************************************************* + 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 +#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; +} diff --git a/drivers/rf/chibi/chb_buf.h b/drivers/rf/chibi/chb_buf.h new file mode 100644 index 0000000..ec75812 --- /dev/null +++ b/drivers/rf/chibi/chb_buf.h @@ -0,0 +1,44 @@ +/******************************************************************* + 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 diff --git a/drivers/rf/chibi/chb_drvr.c b/drivers/rf/chibi/chb_drvr.c new file mode 100644 index 0000000..fb78918 --- /dev/null +++ b/drivers/rf/chibi/chb_drvr.c @@ -0,0 +1,925 @@ +/******************************************************************* + 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 +#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= 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; ioverflow++; + + // 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 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<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(); +} diff --git a/drivers/rf/chibi/chb_drvr.h b/drivers/rf/chibi/chb_drvr.h new file mode 100644 index 0000000..48990bb --- /dev/null +++ b/drivers/rf/chibi/chb_drvr.h @@ -0,0 +1,374 @@ +/******************************************************************* + 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 + diff --git a/drivers/rf/chibi/chb_eeprom.c b/drivers/rf/chibi/chb_eeprom.c new file mode 100644 index 0000000..4849928 --- /dev/null +++ b/drivers/rf/chibi/chb_eeprom.c @@ -0,0 +1,70 @@ +/******************************************************************* + 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); +} + diff --git a/drivers/rf/chibi/chb_eeprom.h b/drivers/rf/chibi/chb_eeprom.h new file mode 100644 index 0000000..3c3df71 --- /dev/null +++ b/drivers/rf/chibi/chb_eeprom.h @@ -0,0 +1,50 @@ +/******************************************************************* + 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 diff --git a/drivers/rf/chibi/chb_spi.c b/drivers/rf/chibi/chb_spi.c new file mode 100644 index 0000000..e552184 --- /dev/null +++ b/drivers/rf/chibi/chb_spi.c @@ -0,0 +1,77 @@ +/******************************************************************* + 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; +} diff --git a/drivers/rf/chibi/chb_spi.h b/drivers/rf/chibi/chb_spi.h new file mode 100644 index 0000000..220feb7 --- /dev/null +++ b/drivers/rf/chibi/chb_spi.h @@ -0,0 +1,62 @@ +/******************************************************************* + 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 diff --git a/drivers/rf/chibi/types.h b/drivers/rf/chibi/types.h new file mode 100644 index 0000000..c551bbc --- /dev/null +++ b/drivers/rf/chibi/types.h @@ -0,0 +1,54 @@ +/******************************************************************* + 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 +#include + +// 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 diff --git a/drivers/rf/pn532/helpers/pn532_mifare.h b/drivers/rf/pn532/helpers/pn532_mifare.h new file mode 100644 index 0000000..94d2c2e --- /dev/null +++ b/drivers/rf/pn532/helpers/pn532_mifare.h @@ -0,0 +1,29 @@ +/**************************************************************************/ +/*! + @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 diff --git a/drivers/rf/pn532/helpers/pn532_mifare_classic.c b/drivers/rf/pn532/helpers/pn532_mifare_classic.c new file mode 100644 index 0000000..debf834 --- /dev/null +++ b/drivers/rf/pn532/helpers/pn532_mifare_classic.c @@ -0,0 +1,458 @@ +/**************************************************************************/ +/*! + @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 + +#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; +} diff --git a/drivers/rf/pn532/helpers/pn532_mifare_classic.h b/drivers/rf/pn532/helpers/pn532_mifare_classic.h new file mode 100644 index 0000000..81177e9 --- /dev/null +++ b/drivers/rf/pn532/helpers/pn532_mifare_classic.h @@ -0,0 +1,17 @@ +/**************************************************************************/ +/*! + @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 diff --git a/drivers/rf/pn532/helpers/pn532_mifare_ultralight.c b/drivers/rf/pn532/helpers/pn532_mifare_ultralight.c new file mode 100644 index 0000000..0876101 --- /dev/null +++ b/drivers/rf/pn532/helpers/pn532_mifare_ultralight.c @@ -0,0 +1,286 @@ +/**************************************************************************/ +/*! + @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 + +#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; +} + diff --git a/drivers/rf/pn532/helpers/pn532_mifare_ultralight.h b/drivers/rf/pn532/helpers/pn532_mifare_ultralight.h new file mode 100644 index 0000000..78239c9 --- /dev/null +++ b/drivers/rf/pn532/helpers/pn532_mifare_ultralight.h @@ -0,0 +1,16 @@ +/**************************************************************************/ +/*! + @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 diff --git a/drivers/rf/pn532/pn532.c b/drivers/rf/pn532/pn532.c new file mode 100644 index 0000000..78eae7f --- /dev/null +++ b/drivers/rf/pn532/pn532.c @@ -0,0 +1,163 @@ +/**************************************************************************/ +/*! + @file pn532.c +*/ +/**************************************************************************/ +#include + +#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; + } +} diff --git a/drivers/rf/pn532/pn532.h b/drivers/rf/pn532/pn532.h new file mode 100644 index 0000000..4ddf19a --- /dev/null +++ b/drivers/rf/pn532/pn532.h @@ -0,0 +1,144 @@ +/**************************************************************************/ +/*! + @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 diff --git a/drivers/rf/pn532/pn532_bus.h b/drivers/rf/pn532/pn532_bus.h new file mode 100644 index 0000000..9a509b9 --- /dev/null +++ b/drivers/rf/pn532/pn532_bus.h @@ -0,0 +1,39 @@ +/**************************************************************************/ +/*! + @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 diff --git a/drivers/rf/pn532/pn532_bus_i2c.c b/drivers/rf/pn532/pn532_bus_i2c.c new file mode 100644 index 0000000..bbcff7c --- /dev/null +++ b/drivers/rf/pn532/pn532_bus_i2c.c @@ -0,0 +1,490 @@ +/**************************************************************************/ +/*! + @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 + +#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 diff --git a/drivers/rf/pn532/pn532_bus_uart.c b/drivers/rf/pn532/pn532_bus_uart.c new file mode 100644 index 0000000..981df74 --- /dev/null +++ b/drivers/rf/pn532/pn532_bus_uart.c @@ -0,0 +1,298 @@ +/**************************************************************************/ +/*! + @file pn532_bus_uart.c +*/ +/**************************************************************************/ +#include + +#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 diff --git a/drivers/sensors/pn532/helpers/pn532_mifare.h b/drivers/sensors/pn532/helpers/pn532_mifare.h deleted file mode 100644 index 94d2c2e..0000000 --- a/drivers/sensors/pn532/helpers/pn532_mifare.h +++ /dev/null @@ -1,29 +0,0 @@ -/**************************************************************************/ -/*! - @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 diff --git a/drivers/sensors/pn532/helpers/pn532_mifare_classic.c b/drivers/sensors/pn532/helpers/pn532_mifare_classic.c deleted file mode 100644 index debf834..0000000 --- a/drivers/sensors/pn532/helpers/pn532_mifare_classic.c +++ /dev/null @@ -1,458 +0,0 @@ -/**************************************************************************/ -/*! - @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 - -#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; -} diff --git a/drivers/sensors/pn532/helpers/pn532_mifare_classic.h b/drivers/sensors/pn532/helpers/pn532_mifare_classic.h deleted file mode 100644 index 81177e9..0000000 --- a/drivers/sensors/pn532/helpers/pn532_mifare_classic.h +++ /dev/null @@ -1,17 +0,0 @@ -/**************************************************************************/ -/*! - @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 diff --git a/drivers/sensors/pn532/helpers/pn532_mifare_ultralight.c b/drivers/sensors/pn532/helpers/pn532_mifare_ultralight.c deleted file mode 100644 index 0876101..0000000 --- a/drivers/sensors/pn532/helpers/pn532_mifare_ultralight.c +++ /dev/null @@ -1,286 +0,0 @@ -/**************************************************************************/ -/*! - @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 - -#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; -} - diff --git a/drivers/sensors/pn532/helpers/pn532_mifare_ultralight.h b/drivers/sensors/pn532/helpers/pn532_mifare_ultralight.h deleted file mode 100644 index 78239c9..0000000 --- a/drivers/sensors/pn532/helpers/pn532_mifare_ultralight.h +++ /dev/null @@ -1,16 +0,0 @@ -/**************************************************************************/ -/*! - @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 diff --git a/drivers/sensors/pn532/pn532.c b/drivers/sensors/pn532/pn532.c deleted file mode 100644 index 78eae7f..0000000 --- a/drivers/sensors/pn532/pn532.c +++ /dev/null @@ -1,163 +0,0 @@ -/**************************************************************************/ -/*! - @file pn532.c -*/ -/**************************************************************************/ -#include - -#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; - } -} diff --git a/drivers/sensors/pn532/pn532.h b/drivers/sensors/pn532/pn532.h deleted file mode 100644 index 4ddf19a..0000000 --- a/drivers/sensors/pn532/pn532.h +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************/ -/*! - @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 diff --git a/drivers/sensors/pn532/pn532_bus.h b/drivers/sensors/pn532/pn532_bus.h deleted file mode 100644 index 9a509b9..0000000 --- a/drivers/sensors/pn532/pn532_bus.h +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************/ -/*! - @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 diff --git a/drivers/sensors/pn532/pn532_bus_i2c.c b/drivers/sensors/pn532/pn532_bus_i2c.c deleted file mode 100644 index bbcff7c..0000000 --- a/drivers/sensors/pn532/pn532_bus_i2c.c +++ /dev/null @@ -1,490 +0,0 @@ -/**************************************************************************/ -/*! - @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 - -#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 diff --git a/drivers/sensors/pn532/pn532_bus_uart.c b/drivers/sensors/pn532/pn532_bus_uart.c deleted file mode 100644 index 981df74..0000000 --- a/drivers/sensors/pn532/pn532_bus_uart.c +++ /dev/null @@ -1,298 +0,0 @@ -/**************************************************************************/ -/*! - @file pn532_bus_uart.c -*/ -/**************************************************************************/ -#include - -#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