mirror of
https://github.com/whowechina/chu_pico.git
synced 2025-02-22 04:39:30 +01:00
PN532 code started.
This commit is contained in:
parent
420c565f28
commit
099228dbbb
306
firmware/src/pn532.c
Normal file
306
firmware/src/pn532.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* PN532 NFC Reader
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#include "pn532.h"
|
||||
#include "board_defs.h"
|
||||
|
||||
#define IO_TIMEOUT_US 1000
|
||||
#define PN532_I2C_ADDRESS 0x24
|
||||
|
||||
#define PN532_PREAMBLE 0
|
||||
#define PN532_STARTCODE1 0
|
||||
#define PN532_STARTCODE2 0xff
|
||||
#define PN532_POSTAMBLE 0
|
||||
|
||||
#define PN532_HOSTTOPN532 0xd4
|
||||
#define PN532_PN532TOHOST 0xd5
|
||||
|
||||
void pn532_init()
|
||||
{
|
||||
i2c_init(I2C_PORT, I2C_FREQ);
|
||||
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SDA);
|
||||
gpio_pull_up(I2C_SCL);
|
||||
}
|
||||
|
||||
static int pn532_write(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
return i2c_write_blocking_until(I2C_PORT, PN532_I2C_ADDRESS, data, len, false,
|
||||
time_us_64() + IO_TIMEOUT_US * len);
|
||||
}
|
||||
|
||||
static int pn532_read(uint8_t *data, uint8_t len)
|
||||
{
|
||||
return i2c_read_blocking_until(I2C_PORT, PN532_I2C_ADDRESS, data, len, false,
|
||||
time_us_64() + IO_TIMEOUT_US * len);
|
||||
}
|
||||
|
||||
static bool pn532_wait_ready()
|
||||
{
|
||||
uint8_t status = 0;
|
||||
|
||||
for (int retry = 0; retry < 20; retry++) {
|
||||
if (pn532_read(&status, 1) == 1 && status == 0x01) {
|
||||
return true;
|
||||
}
|
||||
sleep_us(1000);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int read_frame(uint8_t *frame, uint8_t len)
|
||||
{
|
||||
uint8_t buf[len + 1];
|
||||
int ret = pn532_read(buf, len + 1);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("I2C data read: %d -", ret);
|
||||
for (int i = 0; i < len + 1; i++) {
|
||||
printf(" %02x", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (ret == len + 1) {
|
||||
memcpy(frame, buf + 1, len);
|
||||
return len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_frame(const uint8_t *frame, uint8_t len)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("I2C frame write: %d -", len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
printf(" %02x", frame[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
return pn532_write(frame, len);
|
||||
}
|
||||
|
||||
static bool read_ack()
|
||||
{
|
||||
uint8_t resp[6];
|
||||
|
||||
if (!pn532_wait_ready()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = read_frame(resp, 6);
|
||||
|
||||
const uint8_t expect_ack[] = {0, 0, 0xff, 0, 0xff, 0};
|
||||
if (memcmp(resp, expect_ack, 6) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int pn532_write_data(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t frame[40];
|
||||
frame[0] = PN532_PREAMBLE;
|
||||
frame[1] = PN532_STARTCODE1;
|
||||
frame[2] = PN532_STARTCODE2;
|
||||
uint8_t checksum = 0xff;
|
||||
|
||||
frame[3] = len;
|
||||
frame[4] = (~len + 1);
|
||||
for (int i = 0; i < len; i++) {
|
||||
frame[5 + i] = data[i];
|
||||
checksum += data[i];
|
||||
}
|
||||
|
||||
frame[5 + len] = ~checksum;
|
||||
frame[6 + len] = PN532_POSTAMBLE;
|
||||
|
||||
int result = write_frame(frame, 7 + len);
|
||||
|
||||
return read_ack();
|
||||
}
|
||||
|
||||
int pn532_read_data(uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t resp[len + 7];
|
||||
|
||||
int result = read_frame(resp, len + 7);
|
||||
|
||||
if (resp[0] != PN532_PREAMBLE ||
|
||||
resp[1] != PN532_STARTCODE1 ||
|
||||
resp[2] != PN532_STARTCODE2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t length = resp[3];
|
||||
uint8_t length_check = length + resp[4];
|
||||
|
||||
if (length > len ||
|
||||
length_check != 0 ||
|
||||
resp[length + 6] != PN532_POSTAMBLE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (int i = 0; i <= length; i++) {
|
||||
data[i] = resp[5 + i];
|
||||
checksum += resp[5 + i];
|
||||
}
|
||||
|
||||
if (checksum != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int pn532_write_command(uint8_t cmd, const uint8_t *param, uint8_t len)
|
||||
{
|
||||
uint8_t data[len + 2];
|
||||
data[0] = PN532_HOSTTOPN532;
|
||||
data[1] = cmd;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
data[2 + i] = param[i];
|
||||
}
|
||||
|
||||
return pn532_write_data(data, len + 2);
|
||||
}
|
||||
|
||||
static void write_nack()
|
||||
{
|
||||
const uint8_t nack[] = {0, 0, 0xff, 0xff, 0, 0};
|
||||
pn532_write(nack, 6);
|
||||
}
|
||||
|
||||
int pn532_peak_response_len()
|
||||
{
|
||||
uint8_t buf[6];
|
||||
if (!pn532_wait_ready()) {
|
||||
return -1;
|
||||
}
|
||||
pn532_read(buf, 6);
|
||||
if (buf[0] != 0x01 ||
|
||||
buf[1] != PN532_PREAMBLE ||
|
||||
buf[2] != PN532_STARTCODE1 ||
|
||||
buf[3] != PN532_STARTCODE2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_nack();
|
||||
return buf[4];
|
||||
}
|
||||
|
||||
int pn532_read_response(uint8_t cmd, uint8_t *resp, uint8_t len)
|
||||
{
|
||||
int real_len = pn532_peak_response_len();
|
||||
if (real_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!pn532_wait_ready()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (real_len < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t data[real_len];
|
||||
int ret = pn532_read_data(data, real_len);
|
||||
if (ret != real_len ||
|
||||
data[0] != PN532_PN532TOHOST ||
|
||||
data[1] != cmd + 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int data_len = real_len - 2;
|
||||
if (data_len > len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data_len > 0) {
|
||||
memcpy(resp, data + 2, data_len);
|
||||
}
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
bool pn532_config_sam()
|
||||
{
|
||||
uint8_t param[] = {0x01, 0x14, 0x01};
|
||||
int result = pn532_write_command(0x14, param, 3);
|
||||
|
||||
return pn532_read_response(0x14, NULL, 0) == 0;
|
||||
}
|
||||
|
||||
static uint8_t card[32];
|
||||
|
||||
bool pn532_poll_mifare(uint8_t *uid, int *len)
|
||||
{
|
||||
uint8_t param[] = {0x01, 0x00};
|
||||
int ret = pn532_write_command(0x4a, param, sizeof(param));
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = pn532_read_response(0x4a, card, sizeof(card));
|
||||
if (result < 1 || card[0] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result != card[5] + 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*len < card[5]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(uid, card + 6, card[5]);
|
||||
*len = card[5];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pn532_poll_felica(uint8_t *uid, int *len)
|
||||
{
|
||||
uint8_t param[] = { 1, 1, 0, 0xff, 0xff, 0, 0};
|
||||
int ret = pn532_write_command(0x4a, param, sizeof(param));
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = pn532_read_response(0x4a, card, sizeof(card));
|
||||
if (result < 1 || card[0] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((result == 20 && card[2] == 18) ||
|
||||
(result == 22 && card[2] == 20)) {
|
||||
if (*len < card[2]) {
|
||||
return false;
|
||||
}
|
||||
*len = card[2];
|
||||
memcpy(uid, card + 4, card[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
18
firmware/src/pn532.h
Normal file
18
firmware/src/pn532.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* PN532 NFC Reader
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PN532_H
|
||||
#define PN532_H
|
||||
|
||||
void pn532_init();
|
||||
int pn532_write_command(uint8_t cmd, const uint8_t *param, uint8_t len);
|
||||
int pn532_read_response(uint8_t cmd, uint8_t *resp, uint8_t len);
|
||||
|
||||
bool pn532_config_sam();
|
||||
bool pn532_poll_mifare(uint8_t *uid, int *len);
|
||||
bool pn532_poll_felica(uint8_t *uid, int *len);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user