1
0
mirror of https://github.com/whowechina/chu_pico.git synced 2024-11-24 11:00:10 +01:00

AIME reader (50%, not working)

This commit is contained in:
whowechina 2023-10-22 23:09:32 +08:00
parent ff3768244b
commit 9395c5c5b1
8 changed files with 572 additions and 16 deletions

View File

@ -4,7 +4,8 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip)
function(make_firmware board board_def)
pico_sdk_init()
add_executable(${board}
main.c slider.c air.c rgb.c save.c config.c cli.c commands.c lzfx.c
main.c slider.c air.c rgb.c save.c config.c commands.c
aime.c cli.c lzfx.c
vl53l0x.c mpr121.c pn532.c usb_descriptors.c)
target_compile_definitions(${board} PUBLIC ${board_def})
pico_enable_stdio_usb(${board} 1)

488
firmware/src/aime.c Normal file
View File

@ -0,0 +1,488 @@
/*
* AIME Reader
* WHowe <github.com/whowechina>
*
* Use PN532 to read AIME
*/
#include <stdint.h>
#include <stdbool.h>
#include "bsp/board.h"
#include "hardware/gpio.h"
#include "hardware/i2c.h"
#include "board_defs.h"
#include "i2c_hub.h"
#include "pn532.h"
#define FRAME_TIMEOUT 200000
enum {
CMD_GET_FW_VERSION = 0x30,
CMD_GET_HW_VERSION = 0x32,
// Card read
CMD_START_POLLING = 0x40,
CMD_STOP_POLLING = 0x41,
CMD_CARD_DETECT = 0x42,
CMD_CARD_SELECT = 0x43,
CMD_CARD_HALT = 0x44,
// MIFARE
CMD_MIFARE_KEY_SET_A = 0x50,
CMD_MIFARE_AUTHORIZE_A = 0x51,
CMD_MIFARE_READ = 0x52,
CMD_MIFARE_WRITE = 0x53,
CMD_MIFARE_KEY_SET_B = 0x54,
CMD_MIFARE_AUTHORIZE_B = 0x55,
// Boot,update
CMD_TO_UPDATER_MODE = 0x60,
CMD_SEND_HEX_DATA = 0x61,
CMD_TO_NORMAL_MODE = 0x62,
CMD_SEND_BINDATA_INIT = 0x63,
CMD_SEND_BINDATA_EXEC = 0x64,
// FeliCa
CMD_FELICA_PUSH = 0x70,
CMD_FELICA_THROUGH = 0x71,
CMD_FELICA_THROUGH_POLL = 0x00,
CMD_FELICA_THROUGH_READ = 0x06,
CMD_FELICA_THROUGH_WRITE = 0x08,
CMD_FELICA_THROUGH_GET_SYSTEM_CODE = 0x0C,
CMD_FELICA_THROUGH_NDA_A4 = 0xA4,
// LED board
CMD_EXT_BOARD_LED = 0x80,
CMD_EXT_BOARD_LED_RGB = 0x81,
CMD_EXT_BOARD_LED_RGB_UNKNOWN = 0x82, // 未知
CMD_EXT_BOARD_INFO = 0xf0,
CMD_EXT_FIRM_SUM = 0xf2,
CMD_EXT_SEND_HEX_DATA = 0xf3,
CMD_EXT_TO_BOOT_MODE = 0xf4,
CMD_EXT_TO_NORMAL_MODE = 0xf5,
};
enum { // 未确认效果
STATUS_OK = 0,
STATUS_NFCRW_INIT_ERROR = 1,
STATUS_NFCRW_FIRMWARE_UP_TO_DATE = 3,
STATUS_NFCRW_ACCESS_ERROR = 4,
STATUS_CARD_DETECT_TIMEOUT = 5,
STATUS_CARD_DETECT_ERROR = 32,
STATUS_FELICA_ERROR = 33,
};
const char *fw_version[] = { "TN32MSEC003S F/W Ver1.2", "\x94" };
const char *hw_version[] = { "TN32MSEC003S H/W Ver3.0", "837-15396" };
const char *led_info[] = { "15084\xFF\x10\x00\x12", "000-00000\xFF\x11\x40" };
static int baudrate_mode = 0;
static void aime_set_baudrate(int mode)
{
baudrate_mode = (mode == 0) ? 0 : 1;
}
static int aime_interface = -1;
void aime_init(int interface)
{
aime_interface = interface;
i2c_select(I2C_PORT, 1 << 5); // PN532 on IR1 (I2C mux chn 5)
pn532_config_sam();
}
union __attribute__((packed)) {
struct {
uint8_t len;
uint8_t addr;
uint8_t seq;
uint8_t cmd;
uint8_t status;
uint8_t payload_len;
uint8_t payload[];
};
uint8_t raw[256];
} response;
union __attribute__((packed)) {
struct {
uint8_t len;
uint8_t addr;
uint8_t seq;
uint8_t cmd;
uint8_t payload_len;
uint8_t payload[];
};
uint8_t raw[256];
} request;
struct {
bool active;
uint8_t len;
uint8_t check_sum;
bool escaping;
uint64_t time;
} req_ctx;
static uint8_t key_sets[2][6]; // 'KeyA' and 'KeyB'
static void build_response(int payload_len)
{
response.len = payload_len + 6;
response.addr = request.addr;
response.seq = request.seq;
response.cmd = request.cmd;
response.status = STATUS_OK;
response.payload_len = payload_len;
}
static void send_response()
{
uint8_t checksum = 0;
uint8_t sync = 0xe0;
tud_cdc_n_write(aime_interface, &sync, 1);
for (int i = 0; i < response.len; i++) {
uint8_t c = response.raw[i];
checksum += c;
if (c == 0xe0 || c == 0xd0) {
uint8_t escape = 0xd0;
tud_cdc_n_write(aime_interface, &escape, 1);
c--;
}
tud_cdc_n_write(aime_interface, &c, 1);
}
tud_cdc_n_write(aime_interface, &checksum, 1);
tud_cdc_n_write_flush(aime_interface);
}
static void simple_response(uint8_t status)
{
build_response(0);
response.status = status;
send_response();
}
static void cmd_to_normal_mode()
{
simple_response(pn532_firmware_ver() ? STATUS_NFCRW_FIRMWARE_UP_TO_DATE
: STATUS_NFCRW_INIT_ERROR);
}
static void cmd_fake_version(const char *version[])
{
int len = strlen(version[baudrate_mode]);
build_response(len);
memcpy(response.payload, version[baudrate_mode], len);
send_response();
}
static void cmd_get_hw_version()
{
build_response(2);
response.payload[0] = 0x01;
response.payload[1] = 0x00;
send_response();
}
static void cmd_key_set(int type)
{
memcpy(key_sets[type], request.payload, 6);
build_response(0);
send_response();
}
static void cmd_set_polling(bool enabled)
{
pn532_set_rf_field(0, enabled ? 1 : 0);
simple_response(STATUS_OK);
}
static void cmd_detect_card()
{
typedef struct __attribute__((packed)) {
uint8_t count;
uint8_t type;
uint8_t id_len;
uint8_t uid[20];
} card_info_t;
card_info_t *card_info = (card_info_t *) response.payload;
int len = sizeof(card_info->uid);
if (pn532_poll_mifare(card_info->uid, &len)) {
build_response(len > 4 ? 10 : 7);
card_info->count = 1;
card_info->type = 0x10;
card_info->id_len = len;
printf("Card Mifare %d\n", card_info->id_len);
} else if (pn532_poll_felica(card_info->uid, &len)) {
build_response(19);
card_info->count = 1;
card_info->type = 0x20;
card_info->id_len = 16;
printf("Card Felica %d\n", card_info->id_len);
} else {
build_response(1);
card_info->count = 0;
response.status = STATUS_OK;
}
send_response();
}
typedef struct __attribute__((packed)) {
struct {
uint8_t idm[8];
uint8_t len;
uint8_t code;
} encap;
union {
struct {
uint8_t system_code[2];
uint8_t request_code;
uint8_t timeout;
} poll;
struct {
uint8_t rw_idm[8];
uint8_t service_num;
uint8_t service_code[2];
uint8_t block_num;
uint8_t block_list[2];
uint8_t blocks[16];
} other;
uint8_t payload[32];
};
} felica_thru_req_t;
typedef struct __attribute__((packed)) {
struct {
uint8_t len;
uint8_t code;
uint8_t idm[8];
} encap;
union {
struct {
uint8_t pmm[8];
uint8_t system_code[2];
} poll;
struct {
uint8_t rw_status[2];
uint8_t block_num;
uint8_t blocks[16];
} other;
uint8_t payload[32];
};
} felica_thru_resp_t;
static void cmd_felica_thru()
{
felica_thru_req_t *req = (felica_thru_req_t *) request.payload;
felica_thru_resp_t *resp = (felica_thru_resp_t *) response.payload;
uint8_t card[20];
int len = 20;
if (!pn532_poll_felica(card, &len)) {
simple_response(STATUS_FELICA_ERROR);
}
printf("Felica Thru:");
for (int i = 0; i < 16; i++) {
printf(" %02x", request.payload[i]);
}
printf("\n");
uint8_t code = req->encap.code;
resp->encap.code = code + 1;
switch (code) {
case CMD_FELICA_THROUGH_POLL:
printf("\tPOLL\n");
build_response(20);
memcpy(resp->encap.idm, card, 8);
memcpy(resp->poll.pmm, card + 8, 8);
if (len == 20) {
memcpy(resp->poll.system_code, card + 16, 2);
} else {
memcpy(resp->poll.system_code, req->poll.system_code, 2);
}
break;
case CMD_FELICA_THROUGH_GET_SYSTEM_CODE:
printf("\tGET_SYSTEM_CODE\n");
build_response(13);
resp->payload[0] = 0x01;
resp->payload[1] = resp->poll.system_code[0];
resp->payload[2] = resp->poll.system_code[0];
break;
case CMD_FELICA_THROUGH_NDA_A4:
printf("\tNDA_A4\n");
build_response(11);
resp->payload[0] = 0x00;
break;
case CMD_FELICA_THROUGH_READ:
printf("\tREAD\n");
#if 0
uint8_t services[2] = { req->other.service_code[0], req->other.service_code[1] };
for (int i = 0; i < req->other.block_num; i++) {
uint16_t blockList[1] = { (uint16_t)(req->blockList[i][0] << 8 | req->blockList[i][1]) };
if (nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 1, blockList, res.blockData[i]) != 1) {
memset(res.blockData[i], 0, 16); // dummy data
}
}
res.RW_status[0] = 0;
res.RW_status[1] = 0;
res.numBlock = req->numBlock;
res_init(0x0D + req->numBlock * 16);
#endif
build_response(0);
break;
case CMD_FELICA_THROUGH_WRITE:
printf("\tWRITE\n");
build_response(12);
resp->other.rw_status[0] = 0;
resp->other.rw_status[1] = 0;
break;
default:
printf("\tUnknown through: %02x\n", code);
build_response(0);
response.status = STATUS_OK;
}
resp->encap.len = response.payload_len;
printf("Felica Thru Response:");
for (int i = 0; i < response.payload_len; i++) {
printf(" %02x", response.payload[i]);
}
printf("\n");
send_response();
}
static uint32_t led_color;
static void cmd_led_rgb()
{
printf("\t RGB: %02x %02x %02x\n", request.payload[0], request.payload[1], request.payload[2]);
led_color = request.payload[0] << 16 | request.payload[1] << 8 | request.payload[2];
build_response(0);
send_response();
}
static void aime_handle_frame()
{
i2c_select(I2C_PORT, 1 << 5); // PN532 on IR1 (I2C mux chn 5)
switch (request.cmd) {
case CMD_TO_NORMAL_MODE:
printf("CMD_TO_NORMAL_MODE\n");
cmd_to_normal_mode();
break;
case CMD_GET_FW_VERSION:
printf("CMD_GET_FW_VERSION\n");
cmd_fake_version(fw_version);
break;
case CMD_GET_HW_VERSION:
printf("CMD_GET_HW_VERSION\n");
cmd_fake_version(hw_version);
break;
case CMD_MIFARE_KEY_SET_A:
printf("CMD_MIFARE_KEY_SET_A\n");
cmd_key_set(0);
break;
case CMD_MIFARE_KEY_SET_B:
printf("CMD_MIFARE_KEY_SET_B\n");
cmd_key_set(1);
break;
case CMD_START_POLLING:
printf("CMD_START_POLLING\n");
cmd_set_polling(true);
break;
case CMD_STOP_POLLING:
printf("CMD_TO_NORMAL_MODE\n");
cmd_set_polling(false);
break;
case CMD_CARD_DETECT:
printf("CMD_CARD_DETECT\n");
cmd_detect_card();
break;
case CMD_FELICA_THROUGH:
printf("CMD_FELICA_THROUGH\n");
cmd_felica_thru();
break;
case CMD_EXT_BOARD_INFO:
printf("CMD_EXT_BOARD_INFO\n");
cmd_fake_version(led_info);
break;
case CMD_EXT_BOARD_LED_RGB:
printf("CMD_EXT_BOARD_LED_RGB\n");
cmd_led_rgb();
break;
default:
printf("Unknown command: %02x [", request.cmd);
for (int i = 0; i < request.len; i++) {
printf(" %02x", request.raw[i]);
}
printf("]\n");
simple_response(STATUS_OK);
break;
}
}
static bool aime_feed(int c)
{
if (c == 0xe0) {
req_ctx.active = true;
req_ctx.len = 0;
req_ctx.check_sum = 0;
req_ctx.escaping = false;
req_ctx.time = time_us_64();
return true;
}
if (!req_ctx.active) {
return false;
}
if (c == 0xd0) {
req_ctx.escaping = true;
return true;
}
if (req_ctx.escaping) {
c++;
req_ctx.escaping = false;
}
if (req_ctx.len != 0 && req_ctx.len == request.len) {
if (req_ctx.check_sum == c) {
aime_handle_frame();
req_ctx.active = false;
}
return true;
}
request.raw[req_ctx.len] = c;
req_ctx.len++;
req_ctx.check_sum += c;
return true;
}
void aime_update()
{
if (req_ctx.active && time_us_64() - req_ctx.time > FRAME_TIMEOUT) {
req_ctx.active = false;
}
if (tud_cdc_n_available(aime_interface)) {
uint8_t buf[32];
uint32_t count = tud_cdc_n_read(aime_interface, buf, sizeof(buf));
for (int i = 0; i < count; i++) {
aime_feed(buf[i]);
}
}
}

12
firmware/src/aime.h Normal file
View File

@ -0,0 +1,12 @@
/*
* AIME Reader
* WHowe <github.com/whowechina>
*/
#ifndef AIME_H
#define AIME_H
void aime_init(int interface);
void aime_update();
#endif

View File

@ -27,6 +27,7 @@
#include "config.h"
#include "cli.h"
#include "commands.h"
#include "aime.h"
#include "slider.h"
#include "air.h"
@ -151,6 +152,8 @@ static void core0_loop()
tud_task();
cli_run();
aime_update();
save_loop();
cli_fps_count(0);
@ -179,8 +182,11 @@ void init()
air_init();
rgb_init();
aime_init(1);
cli_init("chu_pico>", "\n << Chu Pico Controller >>\n"
" https://github.com/whowechina\n\n");
commands_init();
}

View File

@ -242,6 +242,27 @@ int pn532_read_response(uint8_t cmd, uint8_t *resp, uint8_t len)
return data_len;
}
uint32_t pn532_firmware_ver()
{
int ret = pn532_write_command(0x02, NULL, 0);
if (ret < 0) {
return 0;
}
uint8_t ver[4];
int result = pn532_read_response(0x4a, ver, sizeof(ver));
if (result < 4) {
return 0;
}
uint32_t version = 0;
for (int i = 0; i < 4; i++) {
version <<= 8;
version |= ver[i];
}
return version;
}
bool pn532_config_sam()
{
uint8_t param[] = {0x01, 0x14, 0x01};
@ -250,6 +271,15 @@ bool pn532_config_sam()
return pn532_read_response(0x14, NULL, 0) == 0;
}
bool pn532_set_rf_field(uint8_t auto_rf, uint8_t on_off)
{
uint8_t param[] = { 1, auto_rf | on_off };
int result = pn532_write_command(0x32, param, 2);
return pn532_read_response(0x32, NULL, 0) >= 0;
}
static uint8_t card[32];
bool pn532_poll_mifare(uint8_t *uid, int *len)
@ -288,11 +318,13 @@ bool pn532_poll_felica(uint8_t *uid, int *len)
}
int result = pn532_read_response(0x4a, card, sizeof(card));
if (result < 1 || card[0] != 1) {
if (card[0] != 1) {
return false;
}
if ((result == 20 && card[2] == 18) ||
printf("Felica poll: len=%d\n", card[2]);
if ((result == 20 && card[2] == 18) ||
(result == 22 && card[2] == 20)) {
if (*len < card[2]) {
return false;

View File

@ -11,8 +11,13 @@ 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);
uint32_t pn532_firmware_ver();
bool pn532_config_sam();
bool pn532_set_rf_field(uint8_t auto_rf, uint8_t on_off);
bool pn532_poll_mifare(uint8_t *uid, int *len);
bool pn532_poll_felica(uint8_t *uid, int *len);
#endif

View File

@ -97,7 +97,7 @@ extern "C" {
//------------- CLASS -------------//
#define CFG_TUD_HID 3
#define CFG_TUD_CDC 1
#define CFG_TUD_CDC 2
#define CFG_TUD_MSC 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0

View File

@ -111,16 +111,24 @@ uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf)
// Configuration Descriptor
//--------------------------------------------------------------------+
enum { ITF_NUM_JOY, ITF_NUM_LED, ITF_NUM_NKRO, ITF_NUM_CDC, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
enum { ITF_NUM_JOY, ITF_NUM_LED, ITF_NUM_NKRO,
ITF_NUM_CLI, ITF_NUM_CLI_DATA,
ITF_NUM_AIME, ITF_NUM_AIME_DATA,
ITF_NUM_TOTAL };
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN * 3 + TUD_CDC_DESC_LEN)
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN * 3 + TUD_CDC_DESC_LEN * 2)
#define EPNUM_JOY 0x84
#define EPNUM_LED 0x85
#define EPNUM_KEY 0x86
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_JOY 0x81
#define EPNUM_LED 0x82
#define EPNUM_KEY 0x83
#define EPNUM_CLI_NOTIF 0x85
#define EPNUM_CLI_OUT 0x06
#define EPNUM_CLI_IN 0x86
#define EPNUM_AIME_NOTIF 0x87
#define EPNUM_AIME_OUT 0x08
#define EPNUM_AIME_IN 0x88
uint8_t const desc_configuration_joy[] = {
// Config number, interface count, string index, total length, attribute,
@ -142,8 +150,11 @@ uint8_t const desc_configuration_joy[] = {
sizeof(desc_hid_report_nkro), EPNUM_KEY,
CFG_TUD_HID_EP_BUFSIZE, 1),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 7, EPNUM_CDC_NOTIF,
8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
TUD_CDC_DESCRIPTOR(ITF_NUM_CLI, 7, EPNUM_CLI_NOTIF,
8, EPNUM_CLI_OUT, EPNUM_CLI_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_AIME, 8, EPNUM_AIME_NOTIF,
8, EPNUM_AIME_OUT, EPNUM_AIME_IN, 64),
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
@ -166,7 +177,8 @@ const char *string_desc_arr[] = {
"Chu Pico Joystick",
"Chu Pico LED",
"Chu Pico NKRO",
"Chu Pico Serial Port",
"Chu Pico CLI Port",
"Chu Pico AIME Port",
};
// Invoked when received GET STRING DESCRIPTOR request