1
0
mirror of https://github.com/whowechina/chu_pico.git synced 2024-09-23 18:48:23 +02:00

Use aic_pico as a library via submodule

This commit is contained in:
whowechina 2024-03-16 17:02:52 +08:00
parent 0eb6147f95
commit 7a75940a3e
13 changed files with 92 additions and 1295 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "aic_pico"]
path = firmware/modules/aic_pico
url = https://github.com/whowechina/aic_pico

9
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"files.associations": {
"mpr121.h": "c",
"board_defs.h": "c",
"pn532.h": "c",
"cli.h": "c",
"vl53l0x.h": "c"
}
}

Binary file not shown.

View File

@ -1,11 +1,14 @@
cmake_minimum_required(VERSION 3.12)
project(chu_pico C CXX ASM)
# Pull in SDK (must set be before project)
include(pico_sdk_import.cmake)
project(iidx_pico C CXX ASM)
set(CMAKE_C_STANDARD 11)
pico_sdk_init()
add_subdirectory(modules/aic_pico/firmware aic)
include_directories(modules/aic_pico/firmware/include)
add_subdirectory(src)

View File

@ -1,12 +1,8 @@
set(BTSTACK_ROOT ${PICO_SDK_PATH}/lib/btstack)
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 commands.c
aime.c cli.c lzfx.c
vl53l0x.c mpr121.c pn532.c usb_descriptors.c)
cli.c lzfx.c vl53l0x.c mpr121.c usb_descriptors.c)
target_compile_definitions(${board} PUBLIC ${board_def})
pico_enable_stdio_usb(${board} 1)
pico_enable_stdio_uart(${board} 0)
@ -15,11 +11,9 @@ function(make_firmware board board_def)
target_compile_options(${board} PRIVATE -Wall -Werror -Wfatal-errors -O3)
target_include_directories(${board} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(${board} PRIVATE
${BTSTACK_ROOT}/src
${LWIP_ROOT}/src/include)
target_link_libraries(${board} PRIVATE
aic
pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash
hardware_adc hardware_i2c hardware_watchdog
tinyusb_device tinyusb_board)
@ -31,4 +25,3 @@ function(make_firmware board board_def)
endfunction()
make_firmware(chu_pico BOARD_CHU_PICO)

View File

@ -1,712 +0,0 @@
/*
* 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_OP = 0x71,
CMD_FELICA_OP_POLL = 0x00,
CMD_FELICA_OP_READ = 0x06,
CMD_FELICA_OP_WRITE = 0x08,
CMD_FELICA_OP_GET_SYSTEM_CODE = 0x0C,
CMD_FELICA_OP_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 struct {
bool enabled; // feature enabled
bool active; // currently active
uint8_t idm[8];
const uint8_t pmm[8];
const uint8_t syscode[2];
} virtual_aic = { true, false, "", "\x00\xf1\x00\x00\x00\x01\x43\x00", "\x88\xb4" };
void aime_set_baudrate(int mode)
{
baudrate_mode = (mode == 0) ? 0 : 1;
}
void aime_set_virtual_aic(bool enable)
{
virtual_aic.enabled = enable;
}
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();
}
static uint8_t mifare_keys[2][6]; // 'KeyA' and 'KeyB'
static 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;
static union __attribute__((packed)) {
struct {
uint8_t len;
uint8_t addr;
uint8_t seq;
uint8_t cmd;
uint8_t payload_len;
union {
struct {
uint8_t uid[4];
uint8_t block_id;
} mifare;
struct {
uint8_t idm[8];
uint8_t len;
uint8_t code;
uint8_t data[0];
} felica;
uint8_t payload[250];
};
};
uint8_t raw[256];
} request;
struct {
bool active;
uint8_t len;
uint8_t check_sum;
bool escaping;
uint64_t time;
} req_ctx;
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 send_simple_response(uint8_t status)
{
build_response(0);
response.status = status;
send_response();
}
static void cmd_to_normal_mode()
{
send_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_key_set(uint8_t key[6])
{
memcpy(key, request.payload, 6);
send_simple_response(STATUS_OK);
}
static void cmd_set_polling(bool enabled)
{
pn532_set_rf_field(0, enabled ? 1 : 0);
send_simple_response(STATUS_OK);
}
typedef struct __attribute__((packed)) {
uint8_t count;
uint8_t type;
uint8_t id_len;
union {
struct {
uint8_t idm[8];
uint8_t pmm[8];
uint8_t syscode[2];
};
uint8_t uid[6];
};
} card_info_t;
static void handle_mifare_card(const uint8_t *uid, int len)
{
card_info_t *card = (card_info_t *) response.payload;
build_response(len > 4 ? 10 : 7);
card->count = 1;
card->type = 0x10;
card->id_len = len;
memcpy(card->uid, uid, len);
}
static void handle_felica_card(const uint8_t felica_ids[18])
{
build_response(19);
card_info_t *card = (card_info_t *) response.payload;
card->count = 1;
card->type = 0x20;
card->id_len = 16;
memcpy(card->idm, felica_ids, 8);
memcpy(card->pmm, felica_ids + 8, 8);
}
static void fake_felica_card()
{
build_response(19);
card_info_t *card = (card_info_t *) response.payload;
card->count = 1;
card->type = 0x20;
card->id_len = 16;
memcpy(card->idm, virtual_aic.idm, 8);
memcpy(card->pmm, virtual_aic.pmm, 8);
}
static void handle_no_card()
{
build_response(1);
card_info_t *card = (card_info_t *) response.payload;
card->count = 0;
response.status = STATUS_OK;
}
static void printf_hex(const uint8_t *hex, int len, const char *tail)
{
for (int i = 0; i < len; i ++) {
printf(" %02x", hex[i]);
}
printf("%s", tail);
}
static void cmd_detect_card()
{
uint8_t buf[18];
virtual_aic.active = false;
int len = sizeof(buf);
if (pn532_poll_mifare(buf, &len)) {
printf("Detected Mifare - ");
printf_hex(buf, len, "\n");
if (virtual_aic.enabled) {
virtual_aic.active = true;
memset(virtual_aic.idm, 0, 8);
memcpy(virtual_aic.idm, "\x01\x01", 2);
memcpy(virtual_aic.idm + 2, buf, len);
printf("Virtual AIC -");
printf_hex(virtual_aic.idm, 8, ",");
printf_hex(virtual_aic.pmm, 8, ",");
printf_hex(virtual_aic.syscode, 2, "\n");
fake_felica_card();
} else {
handle_mifare_card(buf, len);
}
} else if (pn532_poll_felica(buf, buf + 8, buf + 16, false)) {
printf("Detected Felica -");
printf_hex(buf, 8, ",");
printf_hex(buf + 8, 8, ",");
printf_hex(buf + 16, 2, "\n");
handle_felica_card(buf);
} else {
handle_no_card();
}
send_response();
}
static void cmd_card_select()
{
printf("CARD SELECT %d\n", request.payload_len);
send_simple_response(STATUS_OK);
}
static void cmd_mifare_auth(int type)
{
printf("MIFARE AUTH\n");
pn532_mifare_auth(request.mifare.uid, request.mifare.block_id, type, mifare_keys[type]);
send_simple_response(STATUS_OK);
}
static void cmd_mifare_read()
{
printf("MIFARE READ %02x %02x %02x %02x %02x\n", request.mifare.block_id,
request.mifare.uid[0], request.mifare.uid[1], request.mifare.uid[2],
request.mifare.uid[3]);
build_response(16);
memset(response.payload, 0, 16);
pn532_mifare_read(request.mifare.block_id, response.payload);
send_response();
}
static void cmd_mifare_halt()
{
printf("MIFARE HALT\n");
send_simple_response(STATUS_OK);
}
typedef struct __attribute__((packed)) {
uint8_t len;
uint8_t code;
uint8_t idm[8];
uint8_t data[0];
} felica_resp_t;
typedef struct __attribute__((packed)) {
uint8_t idm[8];
uint8_t pmm[8];
uint8_t syscode[2];
} card_id_t;
static int cmd_felica_poll(const card_id_t *card)
{
typedef struct __attribute__((packed)) {
uint8_t pmm[8];
uint8_t syscode[2];
} felica_poll_resp_t;
printf("FELICA POLL\n");
felica_resp_t *felica_resp = (felica_resp_t *) response.payload;
felica_poll_resp_t *poll_resp = (felica_poll_resp_t *) felica_resp->data;
if (virtual_aic.active) {
memcpy(poll_resp->pmm, virtual_aic.pmm, 8);
memcpy(poll_resp->syscode, virtual_aic.syscode, 2);
} else {
memcpy(poll_resp->pmm, card->pmm, 8);
memcpy(poll_resp->syscode, card->syscode, 2);
}
return sizeof(*poll_resp);
}
static int cmd_felica_get_syscode(const card_id_t *card)
{
printf("FELICA GET_SYSTEM_CODE\n");
felica_resp_t *felica_resp = (felica_resp_t *) response.payload;
felica_resp->data[0] = 0x01;
if (virtual_aic.active) {
memcpy(felica_resp->data, virtual_aic.syscode, 2);
} else {
felica_resp->data[1] = card->syscode[0];
felica_resp->data[2] = card->syscode[1];
}
return 3;
}
static int cmd_felica_read()
{
printf("FELICA READ\n");
uint8_t *req_data = request.felica.data;
if (req_data[8] != 1) {
printf("Felica Encap READ Error: service_num != 1\n");
return -1;
}
uint16_t svc_code = req_data[9] | (req_data[10] << 8);
typedef struct __attribute__((packed)) {
uint8_t rw_status[2];
uint8_t block_num;
uint8_t block_data[0][16];
} encap_read_resp_t;
felica_resp_t *felica_resp = (felica_resp_t *) response.payload;
encap_read_resp_t *read_resp = (encap_read_resp_t *) felica_resp->data;
uint8_t *block = req_data + 11;
uint8_t block_num = block[0];
memset(read_resp->block_data, 0, block_num * 16);
for (int i = 0; i < block_num; i++) {
uint16_t block_id = (block[i * 2 + 1] << 8) | block[i * 2 + 2];
if (block_id == 0x8082) {
memcpy(read_resp->block_data[i], felica_resp->idm, 8);
}
if (!virtual_aic.active) {
pn532_felica_read_wo_encrypt(svc_code, block_id, read_resp->block_data[i]);
}
}
read_resp->rw_status[0] = 0x00;
read_resp->rw_status[1] = 0x00;
read_resp->block_num = block_num;
return sizeof(*read_resp) + block_num * 16;
}
static int cmd_felica_write()
{
printf("FELICA WRITE\n");
uint8_t *req_data = request.felica.data;
if (req_data[8] != 1) {
printf("Felica Encap Write Error: service_num != 1\n");
return -1;
}
uint16_t svc_code = req_data[9] | (req_data[10] << 8);
uint8_t *block = req_data + 11;
uint8_t block_num = block[0];
felica_resp_t *felica_resp = (felica_resp_t *) response.payload;
uint8_t *rw_status = felica_resp->data;
printf("svc code: %04x\n", svc_code);
printf("blocks:");
for (int i = 0; i < block_num; i++) {
uint16_t block_id = (block[i * 2 + 1] << 8) | block[i * 2 + 2];
printf(" %04x", block_id);
}
printf("\n");
uint8_t *block_data = block + 1 + block_num * 2;
rw_status[0] = 0x00;
rw_status[1] = 0x00;
for (int i = 0; i < block_num; i++) {
printf("writing %02x %02x\n", block_data[i * 16], block_data[i * 16 + 15]);
// uint16_t block_id = (block[i * 2 + 1] << 8) | block[i * 2 + 2];
// int result = pn532_felica_write_wo_encrypt(svc_code, block_id, block_data + i * 16);
int result = 0;
if (result < 0) {
rw_status[0] = 0x01;
rw_status[1] = 0x01;
}
}
return 2;
}
#if 0
case CMD_FELICA_OP_NDA_A4:
printf("\tNDA_A4\n");
build_response(11);
resp->payload[0] = 0x00;
break;
default:
printf("\tUnknown through: %02x\n", code);
build_response(0);
response.status = STATUS_OK;
#endif
static void cmd_felica()
{
card_id_t card;
if (!pn532_poll_felica(card.idm, card.pmm, card.syscode, true)) {
send_simple_response(STATUS_FELICA_ERROR);
}
uint8_t felica_code = request.felica.code;
printf("Felica (%02x):", felica_code);
for (int i = 0; i < request.payload_len; i++) {
printf(" %02x", request.payload[i]);
}
printf("\n");
int datalen = -1;
switch (felica_code) {
case CMD_FELICA_OP_GET_SYSTEM_CODE:
datalen = cmd_felica_get_syscode(&card);
break;
case CMD_FELICA_OP_POLL:
datalen = cmd_felica_poll(&card);
break;
case CMD_FELICA_OP_READ:
datalen = cmd_felica_read();
break;
case CMD_FELICA_OP_WRITE:
datalen = cmd_felica_write();
break;
default:
printf("Unknown code %d\n", felica_code);
break;
}
if (datalen < 0) {
send_simple_response(STATUS_FELICA_ERROR);
return;
}
felica_resp_t *felica_resp = (felica_resp_t *) response.payload;
build_response(sizeof(*felica_resp) + datalen);
felica_resp->len = response.payload_len;
felica_resp->code = felica_code + 1;
if (virtual_aic.active) {
memcpy(felica_resp->idm, virtual_aic.idm, 8);
} else {
memcpy(felica_resp->idm, card.idm, 8);
}
send_response();
printf("Felica Response:");
for (int i = 0; i < felica_resp->len - 10; i++) {
printf(" %02x", felica_resp->data[i]);
}
printf("\n");
}
static uint32_t led_color;
static void cmd_led_rgb()
{
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:
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(mifare_keys[0]);
break;
case CMD_MIFARE_KEY_SET_B:
printf("CMD_MIFARE_KEY_SET_B\n");
cmd_key_set(mifare_keys[1]);
break;
case CMD_START_POLLING:
cmd_set_polling(true);
break;
case CMD_STOP_POLLING:
cmd_set_polling(false);
break;
case CMD_CARD_DETECT:
cmd_detect_card();
break;
case CMD_FELICA_OP:
cmd_felica();
break;
case CMD_CARD_SELECT:
cmd_card_select();
break;
case CMD_MIFARE_AUTHORIZE_A:
cmd_mifare_auth(0);
break;
case CMD_MIFARE_AUTHORIZE_B:
cmd_mifare_auth(1);
break;
case CMD_MIFARE_READ:
cmd_mifare_read();
break;
case CMD_CARD_HALT:
cmd_mifare_halt();
break;
case CMD_EXT_BOARD_INFO:
cmd_fake_version(led_info);
break;
case CMD_EXT_BOARD_LED_RGB:
cmd_led_rgb();
break;
case CMD_SEND_HEX_DATA:
case CMD_EXT_TO_NORMAL_MODE:
send_simple_response(STATUS_OK);
break;
default:
printf("Unknown command: %02x [", request.cmd);
for (int i = 0; i < request.len; i++) {
printf(" %02x", request.raw[i]);
}
printf("]\n");
send_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]);
}
}
}
uint32_t aime_led_color()
{
return led_color;
}

View File

@ -1,17 +0,0 @@
/*
* AIME Reader
* WHowe <github.com/whowechina>
*/
#ifndef AIME_H
#define AIME_H
void aime_init(int interface);
void aime_update();
uint32_t aime_led_color();
// mode 0 or 1
void aime_set_baudrate(int mode);
void aime_set_virtual_aic(bool enable);
#endif

View File

@ -7,6 +7,8 @@
#include "pico/stdio.h"
#include "pico/stdlib.h"
#include "aime.h"
#include "config.h"
#include "air.h"
#include "slider.h"
@ -14,8 +16,7 @@
#include "cli.h"
#include "i2c_hub.h"
#include "pn532.h"
#include "nfc.h"
#define SENSE_LIMIT_MAX 9
#define SENSE_LIMIT_MIN -9
@ -73,6 +74,12 @@ static void disp_hid()
chu_cfg->hid.nkro ? "on" : "off" );
}
static void disp_aime()
{
printf("[AIME]\n");
printf(" Virtual AIC: %s\n", chu_cfg->virtual_aic ? "ON" : "OFF");
}
void handle_display(int argc, char *argv[])
{
const char *usage = "Usage: display [colors|style|tof|sense|hid]\n";
@ -87,11 +94,12 @@ void handle_display(int argc, char *argv[])
disp_tof();
disp_sense();
disp_hid();
disp_aime();
return;
}
const char *choices[] = {"colors", "style", "tof", "sense", "hid"};
switch (cli_match_prefix(choices, 5, argv[0])) {
const char *choices[] = {"colors", "style", "tof", "sense", "hid", "aime"};
switch (cli_match_prefix(choices, 6, argv[0])) {
case 0:
disp_colors();
break;
@ -107,6 +115,9 @@ void handle_display(int argc, char *argv[])
case 4:
disp_hid();
break;
case 5:
disp_aime();
break;
default:
printf(usage);
break;
@ -402,30 +413,36 @@ static void handle_factory_reset()
static void handle_nfc()
{
i2c_select(I2C_PORT, 1 << 5); // PN532 on IR1 (I2C mux chn 5)
bool ret = pn532_config_sam();
printf("Sam: %d\n", ret);
uint8_t buf[32];
int len = sizeof(buf);
ret = pn532_poll_mifare(buf, &len);
printf("Mifare: %d -", len);
if (ret) {
for (int i = 0; i < len; i++) {
printf(" %02x", buf[i]);
}
printf("NFC module: %s\n", nfc_module_name());
nfc_rf_field(true);
nfc_card_t card = nfc_detect_card();
nfc_rf_field(false);
printf("Card: %s", nfc_card_name(card.card_type));
for (int i = 0; i < card.len; i++) {
printf(" %02x", card.uid[i]);
}
printf("\n");
}
printf("Felica: ");
if (pn532_poll_felica(buf, buf + 8, buf + 16, false)) {
for (int i = 0; i < 18; i++) {
printf(" %02x%s", buf[i], (i % 8 == 7) ? "," : "");
static void handle_virtual(int argc, char *argv[])
{
const char *usage = "Usage: virtual <on|off>\n";
if (argc != 1) {
printf("%s", usage);
return;
}
const char *commands[] = { "on", "off" };
int match = cli_match_prefix(commands, 2, argv[0]);
if (match < 0) {
printf("%s", usage);
return;
}
printf("\n");
chu_cfg->virtual_aic = (match == 0);
aime_virtual_aic(chu_cfg->virtual_aic);
config_changed();
}
void commands_init()
@ -442,4 +459,5 @@ void commands_init()
cli_register("save", handle_save, "Save config to flash.");
cli_register("factory", handle_factory_reset, "Reset everything to default.");
cli_register("nfc", handle_nfc, "NFC debug.");
cli_register("virtual", handle_virtual, "Virtual AIC card.");
}

View File

@ -38,6 +38,7 @@ static chu_cfg_t default_cfg = {
.joy = 1,
.nkro = 0,
},
.virtual_aic = false,
};
chu_runtime_t *chu_runtime;

View File

@ -38,6 +38,7 @@ typedef struct __attribute__((packed)) {
uint8_t joy : 4;
uint8_t nkro : 4;
} hid;
bool virtual_aic;
} chu_cfg_t;
typedef struct {

View File

@ -21,14 +21,16 @@
#include "tusb.h"
#include "usb_descriptors.h"
#include "board_defs.h"
#include "aime.h"
#include "nfc.h"
#include "board_defs.h"
#include "save.h"
#include "config.h"
#include "cli.h"
#include "commands.h"
#include "aime.h"
#include "i2c_hub.h"
#include "slider.h"
#include "air.h"
#include "rgb.h"
@ -144,6 +146,26 @@ static void run_lights()
}
}
const int aime_intf = 1;
static void cdc_aime_putc(uint8_t byte)
{
tud_cdc_n_write(aime_intf, &byte, 1);
tud_cdc_n_write_flush(aime_intf);
}
static void aime_run()
{
if (tud_cdc_n_available(aime_intf)) {
uint8_t buf[32];
uint32_t count = tud_cdc_n_read(aime_intf, buf, sizeof(buf));
i2c_select(I2C_PORT, 1 << 5); // PN532 on IR1 (I2C mux chn 5)
for (int i = 0; i < count; i++) {
aime_feed(buf[i]);
}
}
}
static mutex_t core1_io_lock;
static void core1_loop()
{
@ -164,7 +186,7 @@ static void core0_loop()
tud_task();
cli_run();
aime_update();
aime_run();
save_loop();
cli_fps_count(0);
@ -194,7 +216,11 @@ void init()
air_init();
rgb_init();
aime_init(1);
nfc_attach_i2c(I2C_PORT);
i2c_select(I2C_PORT, 1 << 5); // PN532 on IR1 (I2C mux chn 5)
nfc_init();
aime_init(cdc_aime_putc);
aime_virtual_aic(chu_cfg->virtual_aic);
cli_init("chu_pico>", "\n << Chu Pico Controller >>\n"
" https://github.com/whowechina\n\n");

View File

@ -1,497 +0,0 @@
/*
* 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;
}
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[5 + len];
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;
write_frame(frame, 7 + len);
return read_ack();
}
int pn532_read_data(uint8_t *data, uint8_t len)
{
uint8_t resp[len + 7];
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;
memcpy(data + 2, param, len);
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;
}
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_rf()
{
uint8_t param[] = {0x05, 0xff, 0x01, 0x50};
pn532_write_command(0x32, param, sizeof(param));
return pn532_read_response(0x32, param, sizeof(param)) == 0;
}
bool pn532_config_sam()
{
uint8_t param[] = {0x01, 0x14, 0x01};
pn532_write_command(0x14, param, sizeof(param));
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 };
pn532_write_command(0x32, param, 2);
return pn532_read_response(0x32, NULL, 0) >= 0;
}
static uint8_t readbuf[255];
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, readbuf, sizeof(readbuf));
if (result < 1 || readbuf[0] != 1) {
return false;
}
if (result != readbuf[5] + 6) {
return false;
}
if (*len < readbuf[5]) {
return false;
}
memcpy(uid, readbuf + 6, readbuf[5]);
*len = readbuf[5];
return true;
}
bool pn532_poll_14443b(uint8_t *uid, int *len)
{
uint8_t param[] = {0x01, 0x03, 0x00};
int ret = pn532_write_command(0x4a, param, sizeof(param));
if (ret < 0) {
return false;
}
int result = pn532_read_response(0x4a, readbuf, sizeof(readbuf));
if (result < 1 || readbuf[0] != 1) {
printf("result: %d\n", result);
return false;
}
if (result != readbuf[5] + 6) {
printf("result: %d %d\n", result, readbuf[5]);
return false;
}
if (*len < readbuf[5]) {
printf("result: %d %d\n", result, readbuf[5]);
return false;
}
memcpy(uid, readbuf + 6, readbuf[5]);
*len = readbuf[5];
return true;
}
static struct __attribute__((packed)) {
uint8_t idm[8];
uint8_t pmm[8];
uint8_t syscode[2];
uint8_t inlist_tag;
} felica_poll_cache;
bool pn532_poll_felica(uint8_t uid[8], uint8_t pmm[8], uint8_t syscode[2], bool from_cache)
{
if (from_cache) {
memcpy(uid, felica_poll_cache.idm, 8);
memcpy(pmm, felica_poll_cache.pmm, 8);
memcpy(syscode, felica_poll_cache.syscode, 2);
return true;
}
uint8_t param[] = { 1, 1, 0, 0xff, 0xff, 1, 0};
int ret = pn532_write_command(0x4a, param, sizeof(param));
if (ret < 0) {
return false;
}
int result = pn532_read_response(0x4a, readbuf, sizeof(readbuf));
if (result != 22 || readbuf[0] != 1 || readbuf[2] != 20) {
return false;
}
memcpy(&felica_poll_cache, readbuf + 4, 18);
felica_poll_cache.inlist_tag = readbuf[1];
memcpy(uid, readbuf + 4, 8);
memcpy(pmm, readbuf + 12, 8);
memcpy(syscode, readbuf + 20, 2);
return true;
}
bool pn532_mifare_auth(const uint8_t uid[4], uint8_t block_id, uint8_t key_id, const uint8_t *key)
{
uint8_t param[] = { 1, key_id ? 1 : 0, block_id,
key[0], key[1], key[2], key[3], key[4], key[5],
uid[0], uid[1], uid[2], uid[3] };
int ret = pn532_write_command(0x40, param, sizeof(param));
if (ret < 0) {
printf("Failed mifare auth command\n");
return false;
}
int result = pn532_read_response(0x40, readbuf, sizeof(readbuf));
if (readbuf[0] != 0) {
printf("PN532 Mifare AUTH failed %d %02x\n", result, readbuf[0]);
return false;
}
return true;
}
bool pn532_mifare_read(uint8_t block_id, uint8_t block_data[16])
{
uint8_t param[] = { 1, 0x30, block_id };
int ret = pn532_write_command(0x40, param, sizeof(param));
if (ret < 0) {
printf("Failed mifare read command\n");
return false;
}
int result = pn532_read_response(0x40, readbuf, sizeof(readbuf));
if (readbuf[0] != 0 || result != 17) {
printf("PN532 Mifare READ failed %d %02x\n", result, readbuf[0]);
return false;
}
memmove(block_data, readbuf + 1, 16);
return true;
}
int pn532_felica_command(uint8_t cmd, const uint8_t *param, uint8_t param_len, uint8_t *outbuf)
{
int cmd_len = param_len + 11;
uint8_t cmd_buf[cmd_len + 1];
cmd_buf[0] = felica_poll_cache.inlist_tag;
cmd_buf[1] = cmd_len;
cmd_buf[2] = cmd;
memcpy(cmd_buf + 3, felica_poll_cache.idm, 8);
memcpy(cmd_buf + 11, param, param_len);
int ret = pn532_write_command(0x40, cmd_buf, sizeof(cmd_buf));
if (ret < 0) {
printf("Failed send felica command\n");
return -1;
}
int result = pn532_read_response(0x40, readbuf, sizeof(readbuf));
int outlen = readbuf[1] - 1;
if ((readbuf[0] & 0x3f) != 0 || result - 2 != outlen) {
return -1;
}
memmove(outbuf, readbuf + 2, outlen);
return outlen;
}
bool pn532_felica_read_wo_encrypt(uint16_t svc_code, uint16_t block_id, uint8_t block_data[16])
{
uint8_t param[] = { 1, svc_code & 0xff, svc_code >> 8,
1, block_id >> 8, block_id & 0xff };
int result = pn532_felica_command(0x06, param, sizeof(param), readbuf);
if (result != 12 + 16 || readbuf[9] != 0 || readbuf[10] != 0) {
printf("PN532 Felica READ read failed %d %02x %02x\n",
result, readbuf[9], readbuf[10]);
for (int i = 0; i < result; i++) {
printf(" %02x", readbuf[i]);
}
printf("\n");
return false;
}
const uint8_t *result_data = readbuf + 12;
memcpy(block_data, result_data, 16);
return true;
}
bool pn532_felica_write_wo_encrypt(uint16_t svc_code, uint16_t block_id, const uint8_t block_data[16])
{
uint8_t param[22] = { 1, svc_code & 0xff, svc_code >> 8,
1, block_id >> 8, block_id & 0xff };
memcpy(param + 6, block_data, 16);
int result = pn532_felica_command(0x08, param, sizeof(param), readbuf);
if (result < 0) {
printf("PN532 Felica WRITE failed %d\n", result);
return false;
}
for (int i = 0; i < result; i++) {
printf(" %02x", readbuf[i]);
}
printf("\n");
return false;
}

View File

@ -1,31 +0,0 @@
/*
* 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);
uint32_t pn532_firmware_ver();
bool pn532_config_sam();
bool pn532_config_rf();
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_14443b(uint8_t *uid, int *len);
bool pn532_poll_felica(uint8_t uid[8], uint8_t pmm[8], uint8_t syscode[2], bool from_cache);
bool pn532_mifare_auth(const uint8_t uid[4], uint8_t block_id, uint8_t key_id, const uint8_t *key);
bool pn532_mifare_read(uint8_t block_id, uint8_t block_data[16]);
bool pn532_felica_read_wo_encrypt(uint16_t svc_code, uint16_t block_id, uint8_t block_data[16]);
bool pn532_felica_write_wo_encrypt(uint16_t svc_code, uint16_t block_id, const uint8_t block_data[16]);
#endif