From 924b46ca533dfdb7723f94fbda9c8bd7c8c3d436 Mon Sep 17 00:00:00 2001 From: whowechina Date: Sun, 21 Apr 2024 16:03:32 +0800 Subject: [PATCH] Light follows aime or bana led commands --- firmware/include/bana.h | 46 +- firmware/src/lib/aime.c | 1020 +++++++++++++++++++-------------------- firmware/src/lib/bana.c | 248 +++++++--- firmware/src/light.c | 14 +- firmware/src/light.h | 52 +- firmware/src/main.c | 641 ++++++++++++------------ 6 files changed, 1074 insertions(+), 947 deletions(-) diff --git a/firmware/include/bana.h b/firmware/include/bana.h index ef260c6..a81623f 100644 --- a/firmware/include/bana.h +++ b/firmware/include/bana.h @@ -1,22 +1,24 @@ -/* - * Bandai Namco Protocol - * WHowe - */ - -#ifndef BANA_H -#define BANA_H - -#include -#include - -/* return true if accepts a byte, false if rejects */ -typedef void (*bana_putc_func)(uint8_t byte); - -void bana_init(bana_putc_func putc_func); - -bool bana_feed(int c); - -/* bana activity expires at this time */ -uint64_t bana_expire_time(); - -#endif +/* + * Bandai Namco Protocol + * WHowe + */ + +#ifndef BANA_H +#define BANA_H + +#include +#include + +/* return true if accepts a byte, false if rejects */ +typedef void (*bana_putc_func)(uint8_t byte); + +void bana_init(bana_putc_func putc_func); + +bool bana_feed(int c); + +/* bana activity expires at this time */ +uint64_t bana_expire_time(); + +uint32_t bana_led_color(); + +#endif diff --git a/firmware/src/lib/aime.c b/firmware/src/lib/aime.c index 411ca56..0ef4409 100644 --- a/firmware/src/lib/aime.c +++ b/firmware/src/lib/aime.c @@ -1,510 +1,510 @@ -/* - * AIME Reader - * WHowe - * - * Use NFC Module to read AIME - */ - -#include -#include -#include - -#include "bsp/board.h" -#include "hardware/gpio.h" -#include "hardware/i2c.h" - -#include "nfc.h" -#include "aime.h" - -#define AIME_EXPIRE_TIME 5000000ULL -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, - - // LED board - CMD_EXT_BOARD_LED_RGB = 0x81, - CMD_EXT_BOARD_INFO = 0xf0, - CMD_EXT_TO_NORMAL_MODE = 0xf5, -}; - -enum { - STATUS_OK = 0, - STATUS_INVALID_COMMAND = 3, -}; - -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 ver_mode = 1; - -static struct { - bool enabled; - bool active; // currently active - uint8_t idm[8]; - const uint8_t pmm[8]; - const uint8_t syscode[2]; -} virtual_aic = { false, false, - "", "\x00\xf1\x00\x00\x00\x01\x43\x00", "\x88\xb4" }; - -static void putc_trap(uint8_t byte) -{ -} - -static aime_putc_func aime_putc = putc_trap; - -void aime_set_mode(int mode) -{ - ver_mode = (mode == 0) ? 0 : 1; -} - -const char *aime_get_mode_string() -{ - return hw_version[ver_mode]; -} - -void aime_init(aime_putc_func putc_func) -{ - aime_putc = putc_func; -} - -void aime_virtual_aic(bool enable) -{ - virtual_aic.enabled = enable; -} - -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; - aime_putc(sync); - - printf(" -> %02x(%d)", response.status, response.status); - if (response.payload_len > 0) { - printf(" [%d]", response.payload_len); - } - - 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; - aime_putc(escape); - c--; - } - aime_putc(c); - } - - aime_putc(checksum); -} - -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(STATUS_INVALID_COMMAND); -} - -static void cmd_fake_version(const char *version[]) -{ - int len = strlen(version[ver_mode]); - build_response(len); - memcpy(response.payload, version[ver_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) -{ - nfc_rf_field(enabled); - 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 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); - - printf("\nMIFARE Card:"); - for (int i = 0; i < len; i++) { - printf(" %02x", uid[i]); - } -} - -static void handle_felica_card(const uint8_t idm[8], const uint8_t pmm[8]) -{ - 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, idm, 8); - memcpy(card->pmm, pmm, 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 cmd_detect_card() -{ - nfc_card_t card = nfc_detect_card(); - display_card(&card); - - switch (card.card_type) { - case NFC_CARD_MIFARE: - if (virtual_aic.enabled) { - printf("\nVirtual FeliCa from MIFARE."); - virtual_aic.active = true; - memcpy(virtual_aic.idm, "\x01\x01", 2); - if (card.len == 4) { - memcpy(virtual_aic.idm + 2, card.uid, 4); - memcpy(virtual_aic.idm + 6, card.uid, 2); - } else if (card.len == 7) { - memcpy(virtual_aic.idm + 2, card.uid, 6); - } - fake_felica_card(); - } else { - handle_mifare_card(card.uid, card.len); - } - break; - case NFC_CARD_FELICA: - if (virtual_aic.enabled) { - printf("\nVirtual FeliCa from FeliCa."); - virtual_aic.active = true; - memcpy(virtual_aic.idm, card.uid, 8); - fake_felica_card(); - } else { - handle_felica_card(card.uid, card.pmm); - } - break; - case NFC_CARD_VICINITY: - if (virtual_aic.enabled) { - printf("\nVirtual FeliCa from 15693."); - virtual_aic.active = true; - memcpy(virtual_aic.idm, card.uid, 8); - virtual_aic.idm[0] = 0x01; - fake_felica_card(); - } - break; - default: - handle_no_card(); - break; - } - - send_response(); -} - -static void cmd_card_select() -{ - send_simple_response(STATUS_OK); -} - -static void cmd_mifare_auth(int type) -{ - const uint8_t *key = mifare_keys[type]; - nfc_mifare_auth(request.mifare.uid, request.mifare.block_id, - type, key); - send_simple_response(STATUS_OK); -} - -static void cmd_mifare_read() -{ - build_response(16); - memset(response.payload, 0, 16); - nfc_mifare_read(request.mifare.block_id, response.payload); - send_response(); -} - -static void cmd_mifare_halt() -{ - send_simple_response(STATUS_OK); -} - -static void cmd_felica() -{ - send_simple_response(STATUS_INVALID_COMMAND); - return; -} - -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() -{ - switch (request.cmd) { - case CMD_TO_NORMAL_MODE: - printf("\nAIME: cmd_to_normal"); - cmd_to_normal_mode(); - break; - case CMD_GET_FW_VERSION: - printf("\nAIME: fw_version"); - cmd_fake_version(fw_version); - break; - case CMD_GET_HW_VERSION: - printf("\nAIME: hw_version"); - cmd_fake_version(hw_version); - break; - case CMD_MIFARE_KEY_SET_A: - printf("\nAIME: key A"); - cmd_key_set(mifare_keys[0]); - break; - case CMD_MIFARE_KEY_SET_B: - printf("\nAIME: key B"); - 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_PUSH: - case CMD_FELICA_OP: - printf("\nAIME: felica op"); - cmd_felica(); - break; - - case CMD_CARD_SELECT: - printf("\nAIME: card select"); - cmd_card_select(); - break; - - case CMD_MIFARE_AUTHORIZE_A: - printf("\nAIME: auth A"); - cmd_mifare_auth(0); - break; - - case CMD_MIFARE_AUTHORIZE_B: - printf("\nAIME: auth B"); - cmd_mifare_auth(1); - break; - - case CMD_MIFARE_READ: - printf("\nAIME: mifare read"); - cmd_mifare_read(); - break; - - case CMD_CARD_HALT: - printf("\nAIME: mifare halt"); - cmd_mifare_halt(); - break; - - case CMD_EXT_BOARD_INFO: - printf("\nAIME: led info"); - cmd_fake_version(led_info); - break; - case CMD_EXT_BOARD_LED_RGB: - printf("\nAIME: led rgb"); - cmd_led_rgb(); - break; - - case CMD_SEND_HEX_DATA: - case CMD_EXT_TO_NORMAL_MODE: - printf("\nAIME: hex data or ex to normal: %d", request.cmd); - send_simple_response(STATUS_OK); - break; - - default: - printf("\nUnknown command: %02x [", request.cmd); - for (int i = 0; i < request.len; i++) { - printf(" %02x", request.raw[i]); - } - printf("]"); - send_simple_response(STATUS_OK); - break; - } -} - -static uint64_t expire_time; - -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; - expire_time = time_us_64() + AIME_EXPIRE_TIME; - } - return true; - } - - request.raw[req_ctx.len] = c; - req_ctx.len++; - req_ctx.check_sum += c; - - return true; -} - -uint64_t aime_expire_time() -{ - return expire_time; -} - -uint32_t aime_led_color() -{ - return led_color; -} +/* + * AIME Reader + * WHowe + * + * Use NFC Module to read AIME + */ + +#include +#include +#include + +#include "bsp/board.h" +#include "hardware/gpio.h" +#include "hardware/i2c.h" + +#include "nfc.h" +#include "aime.h" + +#define AIME_EXPIRE_TIME 5000000ULL +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, + + // LED board + CMD_EXT_BOARD_LED_RGB = 0x81, + CMD_EXT_BOARD_INFO = 0xf0, + CMD_EXT_TO_NORMAL_MODE = 0xf5, +}; + +enum { + STATUS_OK = 0, + STATUS_INVALID_COMMAND = 3, +}; + +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 ver_mode = 1; + +static struct { + bool enabled; + bool active; // currently active + uint8_t idm[8]; + const uint8_t pmm[8]; + const uint8_t syscode[2]; +} virtual_aic = { false, false, + "", "\x00\xf1\x00\x00\x00\x01\x43\x00", "\x88\xb4" }; + +static void putc_trap(uint8_t byte) +{ +} + +static aime_putc_func aime_putc = putc_trap; + +void aime_set_mode(int mode) +{ + ver_mode = (mode == 0) ? 0 : 1; +} + +const char *aime_get_mode_string() +{ + return hw_version[ver_mode]; +} + +void aime_init(aime_putc_func putc_func) +{ + aime_putc = putc_func; +} + +void aime_virtual_aic(bool enable) +{ + virtual_aic.enabled = enable; +} + +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; + aime_putc(sync); + + printf(" -> %02x(%d)", response.status, response.status); + if (response.payload_len > 0) { + printf(" [%d]", response.payload_len); + } + + 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; + aime_putc(escape); + c--; + } + aime_putc(c); + } + + aime_putc(checksum); +} + +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(STATUS_INVALID_COMMAND); +} + +static void cmd_fake_version(const char *version[]) +{ + int len = strlen(version[ver_mode]); + build_response(len); + memcpy(response.payload, version[ver_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) +{ + nfc_rf_field(enabled); + 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 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); + + printf("\nMIFARE Card:"); + for (int i = 0; i < len; i++) { + printf(" %02x", uid[i]); + } +} + +static void handle_felica_card(const uint8_t idm[8], const uint8_t pmm[8]) +{ + 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, idm, 8); + memcpy(card->pmm, pmm, 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 cmd_detect_card() +{ + nfc_card_t card = nfc_detect_card(); + display_card(&card); + + switch (card.card_type) { + case NFC_CARD_MIFARE: + if (virtual_aic.enabled) { + printf("\nVirtual FeliCa from MIFARE."); + virtual_aic.active = true; + memcpy(virtual_aic.idm, "\x01\x01", 2); + if (card.len == 4) { + memcpy(virtual_aic.idm + 2, card.uid, 4); + memcpy(virtual_aic.idm + 6, card.uid, 2); + } else if (card.len == 7) { + memcpy(virtual_aic.idm + 2, card.uid, 6); + } + fake_felica_card(); + } else { + handle_mifare_card(card.uid, card.len); + } + break; + case NFC_CARD_FELICA: + if (virtual_aic.enabled) { + printf("\nVirtual FeliCa from FeliCa."); + virtual_aic.active = true; + memcpy(virtual_aic.idm, card.uid, 8); + fake_felica_card(); + } else { + handle_felica_card(card.uid, card.pmm); + } + break; + case NFC_CARD_VICINITY: + if (virtual_aic.enabled) { + printf("\nVirtual FeliCa from 15693."); + virtual_aic.active = true; + memcpy(virtual_aic.idm, card.uid, 8); + virtual_aic.idm[0] = 0x01; + fake_felica_card(); + } + break; + default: + handle_no_card(); + break; + } + + send_response(); +} + +static void cmd_card_select() +{ + send_simple_response(STATUS_OK); +} + +static void cmd_mifare_auth(int type) +{ + const uint8_t *key = mifare_keys[type]; + nfc_mifare_auth(request.mifare.uid, request.mifare.block_id, + type, key); + send_simple_response(STATUS_OK); +} + +static void cmd_mifare_read() +{ + build_response(16); + memset(response.payload, 0, 16); + nfc_mifare_read(request.mifare.block_id, response.payload); + send_response(); +} + +static void cmd_mifare_halt() +{ + send_simple_response(STATUS_OK); +} + +static void cmd_felica() +{ + send_simple_response(STATUS_INVALID_COMMAND); + return; +} + +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 handle_frame() +{ + switch (request.cmd) { + case CMD_TO_NORMAL_MODE: + printf("\nAIME: cmd_to_normal"); + cmd_to_normal_mode(); + break; + case CMD_GET_FW_VERSION: + printf("\nAIME: fw_version"); + cmd_fake_version(fw_version); + break; + case CMD_GET_HW_VERSION: + printf("\nAIME: hw_version"); + cmd_fake_version(hw_version); + break; + case CMD_MIFARE_KEY_SET_A: + printf("\nAIME: key A"); + cmd_key_set(mifare_keys[0]); + break; + case CMD_MIFARE_KEY_SET_B: + printf("\nAIME: key B"); + 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_PUSH: + case CMD_FELICA_OP: + printf("\nAIME: felica op"); + cmd_felica(); + break; + + case CMD_CARD_SELECT: + printf("\nAIME: card select"); + cmd_card_select(); + break; + + case CMD_MIFARE_AUTHORIZE_A: + printf("\nAIME: auth A"); + cmd_mifare_auth(0); + break; + + case CMD_MIFARE_AUTHORIZE_B: + printf("\nAIME: auth B"); + cmd_mifare_auth(1); + break; + + case CMD_MIFARE_READ: + printf("\nAIME: mifare read"); + cmd_mifare_read(); + break; + + case CMD_CARD_HALT: + printf("\nAIME: mifare halt"); + cmd_mifare_halt(); + break; + + case CMD_EXT_BOARD_INFO: + printf("\nAIME: led info"); + cmd_fake_version(led_info); + break; + case CMD_EXT_BOARD_LED_RGB: + printf("\nAIME: led rgb"); + cmd_led_rgb(); + break; + + case CMD_SEND_HEX_DATA: + case CMD_EXT_TO_NORMAL_MODE: + printf("\nAIME: hex data or ex to normal: %d", request.cmd); + send_simple_response(STATUS_OK); + break; + + default: + printf("\nUnknown command: %02x [", request.cmd); + for (int i = 0; i < request.len; i++) { + printf(" %02x", request.raw[i]); + } + printf("]"); + send_simple_response(STATUS_OK); + break; + } +} + +static uint64_t expire_time; + +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) { + handle_frame(); + req_ctx.active = false; + expire_time = time_us_64() + AIME_EXPIRE_TIME; + } + return true; + } + + request.raw[req_ctx.len] = c; + req_ctx.len++; + req_ctx.check_sum += c; + + return true; +} + +uint64_t aime_expire_time() +{ + return expire_time; +} + +uint32_t aime_led_color() +{ + return led_color; +} diff --git a/firmware/src/lib/bana.c b/firmware/src/lib/bana.c index bc87907..1a1d98c 100644 --- a/firmware/src/lib/bana.c +++ b/firmware/src/lib/bana.c @@ -1,79 +1,169 @@ -/* - * Bandai Namco NFC Reader - * WHowe - * - * Use NFC Module to read BANA - */ - -#include -#include -#include - -#include "bsp/board.h" -#include "hardware/gpio.h" -#include "hardware/i2c.h" - -#include "nfc.h" -#include "bana.h" - -#define BANA_EXPIRE_TIME 5000000ULL - -static void putc_trap(uint8_t byte) -{ -} - -static bana_putc_func bana_putc = putc_trap; - -void bana_init(bana_putc_func putc_func) -{ - bana_putc = putc_func; -} - -/* -static uint8_t mifare_keys[2][6]; // 'KeyA' and 'KeyB' - -static union __attribute__((packed)) { - struct { - }; - uint8_t raw[256]; -} response; - -static union __attribute__((packed)) { - struct { - }; - uint8_t raw[256]; -} request; - -struct { - bool active; - uint8_t len; - uint8_t check_sum; - bool escaping; - uint64_t time; -} req_ctx; -*/ - -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 uid[6]; - }; -} card_info_t; - -static uint64_t expire_time; - -bool bana_feed(int c) -{ - return true; -} - -uint64_t bana_expire_time() -{ - return expire_time; -} +/* + * Bandai Namco NFC Reader + * WHowe + * + * Use NFC Module to read BANA + */ + +#include +#include +#include + +#include "bsp/board.h" +#include "hardware/gpio.h" +#include "hardware/i2c.h" + +#include "nfc.h" +#include "bana.h" + +#define BANA_EXPIRE_TIME 5000000ULL + +static void putc_trap(uint8_t byte) +{ +} + +static bana_putc_func bana_putc = putc_trap; + +static void bana_puts(const char *str, size_t len) +{ + for (size_t i = 0; i < len; i++) { + bana_putc(str[i]); + } +} + +void bana_init(bana_putc_func putc_func) +{ + bana_putc = putc_func; +} + +typedef union __attribute__((packed)) { + struct { + struct { + uint8_t padding[3]; + uint8_t len; + uint8_t len_check; + } hdr; + uint8_t dir; + uint8_t cmd; + uint8_t data[0]; + }; + uint8_t raw[48]; +} message_t; + +static message_t request, response; + +struct { + uint8_t frame_len; + uint32_t time; +} req_ctx; + +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 uid[6]; + }; +} card_info_t; + +static uint64_t expire_time; + +static void send_response() +{ + uint8_t checksum = 0xff; + for (int i = 0; i < response.hdr.len; i++) { + checksum += response.raw[5 + i]; + } + + memcpy(response.hdr.padding, "\x00\x00\xff", 3); + response.hdr.len_check = ~response.hdr.len + 1; + + response.raw[5 + response.hdr.len] = ~checksum; + response.raw[6 + response.hdr.len] = 0; + + int total_len = 7 + response.hdr.len; + bana_puts((const char *)response.raw, total_len); + + printf("\nResp: %d %d\n", response.hdr.len, response.cmd); + for (int i = 0; i < total_len; i++) { + printf(">%02x", response.raw[i]); + } +} + +static void send_simple_response(uint8_t code) +{ + response.hdr.len = 2; + response.dir = 0xd5; + response.cmd = code; + send_response(); +} + +static void send_ack() +{ + bana_puts("\x00\x00\xff\x00\xff\x00", 6); +} + +static uint32_t led_color = 0; + +static void handle_frame() +{ + printf("\nBana: %d %02x", request.hdr.len, request.cmd); + if (request.hdr.len == 0) { + send_ack(); + return; + } + + if (request.hdr.len + 7 != req_ctx.frame_len) { + return; + } + + if (request.hdr.len != 0) { + printf("Req: %d %02x", request.hdr.len, request.cmd); + send_simple_response(request.cmd + 1); + } +} + +bool bana_feed(int c) +{ + uint32_t now = time_us_32(); + + if ((req_ctx.frame_len == sizeof(request)) || + (now - req_ctx.time > 100000)) { + req_ctx.frame_len = 0; + } + + req_ctx.time = now; + + request.raw[req_ctx.frame_len] = c; + req_ctx.frame_len++; + + if ((req_ctx.frame_len == 1) && (request.raw[0] == 0x55)) { + req_ctx.frame_len = 0; + } if ((req_ctx.frame_len == 3) && + (memcmp(request.hdr.padding, "\x00\x00\xff", 3) != 0)) { + request.raw[0] = request.raw[1]; + request.raw[1] = request.raw[2]; + req_ctx.frame_len--; + } if ((req_ctx.frame_len == 6) && (request.hdr.len == 0)) { + req_ctx.frame_len = 0; + } else if (req_ctx.frame_len == request.hdr.len + 7) { + handle_frame(); + req_ctx.frame_len = 0; + expire_time = time_us_64() + BANA_EXPIRE_TIME; + } + return true; +} + +uint64_t bana_expire_time() +{ + return expire_time; +} + +uint32_t bana_led_color() +{ + return led_color; +} diff --git a/firmware/src/light.c b/firmware/src/light.c index 0120ce0..c869a46 100644 --- a/firmware/src/light.c +++ b/firmware/src/light.c @@ -237,10 +237,18 @@ void light_init() } } +static bool rainbow = true; +void light_set_rainbow(bool enable) +{ + rainbow = enable; +} + void light_update() { - generate_color_wheel(); - rainbow_update(); - rainbow_fade(); + if (rainbow) { + generate_color_wheel(); + rainbow_update(); + rainbow_fade(); + } drive_led(); } diff --git a/firmware/src/light.h b/firmware/src/light.h index 140eb3f..2a7e800 100644 --- a/firmware/src/light.h +++ b/firmware/src/light.h @@ -1,25 +1,27 @@ -/* - * RGB LED (WS2812) Strip control - * WHowe - */ - -#ifndef RGB_H -#define RGB_H - -#include -#include -#include - -#include "config.h" - -void light_init(); -void light_update(); - -uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix); -uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v); - -void light_set_color(unsigned index, uint32_t color); -void light_set_color_all(uint32_t color); -void light_stimulate(); - -#endif +/* + * RGB LED (WS2812) Strip control + * WHowe + */ + +#ifndef RGB_H +#define RGB_H + +#include +#include +#include + +#include "config.h" + +void light_init(); +void light_update(); + +uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix); +uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v); + +void light_set_color(unsigned index, uint32_t color); +void light_set_color_all(uint32_t color); + +void light_set_rainbow(bool enable); +void light_stimulate(); + +#endif diff --git a/firmware/src/main.c b/firmware/src/main.c index aeb11c2..4f6fd5d 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -1,308 +1,333 @@ -/* - * Controller Main - * WHowe - */ - -#include -#include -#include - -#include "pico/stdio.h" -#include "pico/stdlib.h" -#include "bsp/board.h" -#include "pico/multicore.h" -#include "pico/bootrom.h" - -#include "hardware/gpio.h" -#include "hardware/sync.h" -#include "hardware/structs/ioqspi.h" -#include "hardware/structs/sio.h" - -#include "board_defs.h" - -#include "tusb.h" -#include "usb_descriptors.h" - -#include "save.h" -#include "config.h" -#include "cli.h" -#include "commands.h" -#include "light.h" -#include "keypad.h" - -#include "nfc.h" - -#include "aime.h" - -static struct { - uint8_t current[9]; - uint8_t reported[9]; - uint64_t report_time; -} hid_cardio; - -void report_hid_cardio() -{ - if (!tud_hid_ready()) { - return; - } - - uint64_t now = time_us_64(); - - if (memcmp(hid_cardio.current, "\0\0\0\0\0\0\0\0\0", 9) != 0) { - light_stimulate(); - } - - if ((memcmp(hid_cardio.current, hid_cardio.reported, 9) != 0) && - (now - hid_cardio.report_time > 1000000)) { - - tud_hid_n_report(0x00, hid_cardio.current[0], hid_cardio.current + 1, 8); - memcpy(hid_cardio.reported, hid_cardio.current, 9); - hid_cardio.report_time = now; - } -} - -struct __attribute__((packed)) { - uint8_t modifier; - uint8_t keymap[15]; -} hid_nkro; - -static const char keymap[12] = KEYPAD_NKRO_MAP; - -void report_hid_key() -{ - if (!tud_hid_ready()) { - return; - } - - uint16_t keys = keypad_read(); - for (int i = 0; i < keypad_key_num(); i++) { - uint8_t code = keymap[i]; - uint8_t byte = code / 8; - uint8_t bit = code % 8; - if (keys & (1 << i)) { - hid_nkro.keymap[byte] |= (1 << bit); - } else { - hid_nkro.keymap[byte] &= ~(1 << bit); - } - } - tud_hid_n_report(1, 0, &hid_nkro, sizeof(hid_nkro)); -} - -void report_usb_hid() -{ - report_hid_cardio(); - report_hid_key(); -} - -static mutex_t core1_io_lock; -static void core1_loop() -{ - while (1) { - if (mutex_try_enter(&core1_io_lock, NULL)) { - light_update(); - mutex_exit(&core1_io_lock); - } - cli_fps_count(1); - sleep_us(500); - } -} - -static void update_cardio(nfc_card_t *card) -{ - switch (card->card_type) { - case NFC_CARD_MIFARE: - hid_cardio.current[0] = REPORT_ID_EAMU; - hid_cardio.current[1] = 0xe0; - hid_cardio.current[2] = 0x04; - if (card->len == 4) { - memcpy(hid_cardio.current + 3, card->uid, 4); - memcpy(hid_cardio.current + 7, card->uid, 2); - } else if (card->len == 7) { - memcpy(hid_cardio.current + 3, card->uid + 1, 6); - } - break; - case NFC_CARD_FELICA: - hid_cardio.current[0] = REPORT_ID_FELICA; - memcpy(hid_cardio.current + 1, card->uid, 8); - break; - case NFC_CARD_VICINITY: - hid_cardio.current[0] = REPORT_ID_EAMU; - memcpy(hid_cardio.current + 1, card->uid, 8); - break; - default: - memset(hid_cardio.current, 0, 9); - return; - } - - printf(" -> CardIO "); - for (int i = 1; i < 9; i++) { - printf("%02X", hid_cardio.current[i]); - } -} - -void detect_card() -{ - if (time_us_64() < aime_expire_time()) { - return; - } - - static nfc_card_t old_card = { 0 }; - - nfc_rf_field(true); - nfc_card_t card = nfc_detect_card(); - nfc_rf_field(false); - - if (memcmp(&old_card, &card, sizeof(old_card)) == 0) { - return; - } - - old_card = card; - - display_card(&card); - update_cardio(&card); -} - -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]; - int count = tud_cdc_n_read(aime_intf, buf, sizeof(buf)); - for (int i = 0; i < count; i++) { - if ((aic_cfg->mode & 0xf0) == 0) { - aime_feed(buf[i]); - } else { - //bana_feed(buf[i]); - } - } - } -} - -void wait_loop() -{ - keypad_update(); - report_hid_key(); - - tud_task(); - cli_run(); - - cli_fps_count(0); -} - -static void core0_loop() -{ - while(1) { - tud_task(); - - cli_run(); - aime_run(); - - save_loop(); - cli_fps_count(0); - - keypad_update(); - detect_card(); - - report_usb_hid(); - - sleep_ms(1); - } -} - -void init() -{ - tusb_init(); - stdio_init_all(); - light_init(); - keypad_init(); - - config_init(); - mutex_init(&core1_io_lock); - save_init(0xca340a1c, &core1_io_lock); - - nfc_init_i2c(I2C_PORT, I2C_SCL, I2C_SDA, I2C_FREQ); - nfc_init_spi(SPI_PORT, SPI_MISO, SPI_SCK, SPI_MOSI, SPI_RST, SPI_NSS, SPI_BUSY); - nfc_init(); - nfc_set_wait_loop(wait_loop); - - aime_init(cdc_aime_putc); - aime_virtual_aic(aic_cfg->virtual_aic); - - if ((aic_cfg->mode & 0x0f) == 0) { - aime_set_mode(aic_cfg->mode); - } - - //bana_init(); - - cli_init("aic_pico>", "\n << AIC Pico >>\n" - " https://github.com/whowechina\n\n"); - - commands_init(); -} - -/* if certain key pressed when booting, enter update mode */ -static void update_check() -{ - const uint8_t pins[] = { 10, 11 }; // keypad 00 and * - bool all_pressed = true; - for (int i = 0; i < sizeof(pins); i++) { - uint8_t gpio = pins[i]; - gpio_init(gpio); - gpio_set_function(gpio, GPIO_FUNC_SIO); - gpio_set_dir(gpio, GPIO_IN); - gpio_pull_up(gpio); - sleep_ms(1); - if (gpio_get(gpio)) { - all_pressed = false; - break; - } - } - - if (all_pressed) { - sleep_ms(100); - reset_usb_boot(0, 2); - return; - } -} - -static void sys_init() -{ - sleep_ms(50); - set_sys_clock_khz(150000, true); - board_init(); -} - -int main(void) -{ - sys_init(); - update_check(); - init(); - multicore_launch_core1(core1_loop); - core0_loop(); - return 0; -} - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, - hid_report_type_t report_type, uint8_t *buffer, - uint16_t reqlen) -{ - printf("Get from USB %d-%d\n", report_id, report_type); - return 0; -} - -// Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, - hid_report_type_t report_type, uint8_t const *buffer, - uint16_t bufsize) -{ -} +/* + * Controller Main + * WHowe + */ + +#include +#include +#include + +#include "pico/stdio.h" +#include "pico/stdlib.h" +#include "bsp/board.h" +#include "pico/multicore.h" +#include "pico/bootrom.h" + +#include "hardware/gpio.h" +#include "hardware/sync.h" +#include "hardware/structs/ioqspi.h" +#include "hardware/structs/sio.h" + +#include "board_defs.h" + +#include "tusb.h" +#include "usb_descriptors.h" + +#include "save.h" +#include "config.h" +#include "cli.h" +#include "commands.h" +#include "light.h" +#include "keypad.h" + +#include "nfc.h" + +#include "aime.h" +#include "bana.h" + +static struct { + uint8_t current[9]; + uint8_t reported[9]; + uint64_t report_time; +} hid_cardio; + +void report_hid_cardio() +{ + if (!tud_hid_ready()) { + return; + } + + uint64_t now = time_us_64(); + + if (memcmp(hid_cardio.current, "\0\0\0\0\0\0\0\0\0", 9) != 0) { + light_stimulate(); + } + + if ((memcmp(hid_cardio.current, hid_cardio.reported, 9) != 0) && + (now - hid_cardio.report_time > 1000000)) { + + tud_hid_n_report(0x00, hid_cardio.current[0], hid_cardio.current + 1, 8); + memcpy(hid_cardio.reported, hid_cardio.current, 9); + hid_cardio.report_time = now; + } +} + +struct __attribute__((packed)) { + uint8_t modifier; + uint8_t keymap[15]; +} hid_nkro; + +static const char keymap[12] = KEYPAD_NKRO_MAP; + +void report_hid_key() +{ + if (!tud_hid_ready()) { + return; + } + + uint16_t keys = keypad_read(); + for (int i = 0; i < keypad_key_num(); i++) { + uint8_t code = keymap[i]; + uint8_t byte = code / 8; + uint8_t bit = code % 8; + if (keys & (1 << i)) { + hid_nkro.keymap[byte] |= (1 << bit); + } else { + hid_nkro.keymap[byte] &= ~(1 << bit); + } + } + tud_hid_n_report(1, 0, &hid_nkro, sizeof(hid_nkro)); +} + +void report_usb_hid() +{ + report_hid_cardio(); + report_hid_key(); +} + +static void light_effect() +{ + uint64_t now = time_us_64(); + if (now < aime_expire_time()) { + light_set_rainbow(false); + light_set_color_all(aime_led_color()); + } else if (now < bana_expire_time()) { + light_set_rainbow(false); + light_set_color_all(bana_led_color()); + } else { + light_set_rainbow(true); + } + light_update(); +} + +static mutex_t core1_io_lock; +static void core1_loop() +{ + while (1) { + if (mutex_try_enter(&core1_io_lock, NULL)) { + light_effect(); + mutex_exit(&core1_io_lock); + } + cli_fps_count(1); + sleep_us(500); + } +} + +static void update_cardio(nfc_card_t *card) +{ + switch (card->card_type) { + case NFC_CARD_MIFARE: + hid_cardio.current[0] = REPORT_ID_EAMU; + hid_cardio.current[1] = 0xe0; + hid_cardio.current[2] = 0x04; + if (card->len == 4) { + memcpy(hid_cardio.current + 3, card->uid, 4); + memcpy(hid_cardio.current + 7, card->uid, 2); + } else if (card->len == 7) { + memcpy(hid_cardio.current + 3, card->uid + 1, 6); + } + break; + case NFC_CARD_FELICA: + hid_cardio.current[0] = REPORT_ID_FELICA; + memcpy(hid_cardio.current + 1, card->uid, 8); + break; + case NFC_CARD_VICINITY: + hid_cardio.current[0] = REPORT_ID_EAMU; + memcpy(hid_cardio.current + 1, card->uid, 8); + break; + default: + memset(hid_cardio.current, 0, 9); + return; + } + + printf(" -> CardIO "); + for (int i = 1; i < 9; i++) { + printf("%02X", hid_cardio.current[i]); + } +} + +void detect_card() +{ + if ((time_us_64() < aime_expire_time()) || + (time_us_64() < bana_expire_time())) { + return; + } + + static nfc_card_t old_card = { 0 }; + + nfc_rf_field(true); + nfc_card_t card = nfc_detect_card(); + nfc_rf_field(false); + + if (memcmp(&old_card, &card, sizeof(old_card)) == 0) { + return; + } + + old_card = card; + + display_card(&card); + update_cardio(&card); +} + +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]; + int count = tud_cdc_n_read(aime_intf, buf, sizeof(buf)); + if (count <= 0) { + return; + } + + printf("\n> "); + for (int i = 0; i < count; i++) { + printf("|%02x", buf[i]); + if ((aic_cfg->mode & 0xf0) == 0) { + aime_feed(buf[i]); + } else { + bana_feed(buf[i]); + } + } + + light_set_color_all(aime_led_color()); + } +} + +void wait_loop() +{ + keypad_update(); + report_hid_key(); + + tud_task(); + cli_run(); + + cli_fps_count(0); +} + +static void core0_loop() +{ + while(1) { + tud_task(); + + cli_run(); + aime_run(); + + save_loop(); + cli_fps_count(0); + + keypad_update(); + detect_card(); + + report_usb_hid(); + + sleep_ms(1); + } +} + +void init() +{ + tusb_init(); + stdio_init_all(); + light_init(); + keypad_init(); + + config_init(); + mutex_init(&core1_io_lock); + save_init(0xca340a1c, &core1_io_lock); + + nfc_init_i2c(I2C_PORT, I2C_SCL, I2C_SDA, I2C_FREQ); + nfc_init_spi(SPI_PORT, SPI_MISO, SPI_SCK, SPI_MOSI, SPI_RST, SPI_NSS, SPI_BUSY); + nfc_init(); + nfc_set_wait_loop(wait_loop); + + aime_init(cdc_aime_putc); + aime_virtual_aic(aic_cfg->virtual_aic); + + if ((aic_cfg->mode & 0x0f) == 0) { + aime_set_mode(aic_cfg->mode); + } + + bana_init(cdc_aime_putc); + + cli_init("aic_pico>", "\n << AIC Pico >>\n" + " https://github.com/whowechina\n\n"); + + commands_init(); +} + +/* if certain key pressed when booting, enter update mode */ +static void update_check() +{ + const uint8_t pins[] = { 10, 11 }; // keypad 00 and * + bool all_pressed = true; + for (int i = 0; i < sizeof(pins); i++) { + uint8_t gpio = pins[i]; + gpio_init(gpio); + gpio_set_function(gpio, GPIO_FUNC_SIO); + gpio_set_dir(gpio, GPIO_IN); + gpio_pull_up(gpio); + sleep_ms(1); + if (gpio_get(gpio)) { + all_pressed = false; + break; + } + } + + if (all_pressed) { + sleep_ms(100); + reset_usb_boot(0, 2); + return; + } +} + +static void sys_init() +{ + sleep_ms(50); + set_sys_clock_khz(150000, true); + board_init(); +} + +int main(void) +{ + sys_init(); + update_check(); + init(); + multicore_launch_core1(core1_loop); + core0_loop(); + return 0; +} + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, + hid_report_type_t report_type, uint8_t *buffer, + uint16_t reqlen) +{ + printf("Get from USB %d-%d\n", report_id, report_type); + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, + hid_report_type_t report_type, uint8_t const *buffer, + uint16_t bufsize) +{ +}