上传本地文件
This commit is contained in:
commit
e2408bccf3
143
Arduino-Aime-Reader/Arduino-Aime-Reader.ino
Normal file
143
Arduino-Aime-Reader/Arduino-Aime-Reader.ino
Normal file
@ -0,0 +1,143 @@
|
||||
#include "cmd.h"
|
||||
bool high_baudrate = true;//high_baudrate=true
|
||||
|
||||
void setup() {
|
||||
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
|
||||
FastLED.setBrightness(255);
|
||||
FastLED.showColor(0);
|
||||
nfc.begin();
|
||||
while (!nfc.getFirmwareVersion()) {
|
||||
FastLED.showColor(0xFF0000);
|
||||
delay(500);
|
||||
FastLED.showColor(0);
|
||||
delay(500);
|
||||
}
|
||||
nfc.setPassiveActivationRetries(0x10);//设定等待次数
|
||||
nfc.SAMConfig();
|
||||
memset(&req, 0, sizeof(req.bytes));
|
||||
memset(&res, 0, sizeof(res.bytes));
|
||||
|
||||
SerialDevice.begin(high_baudrate ? 115200 : 38400);
|
||||
FastLED.showColor(high_baudrate ? 0x0000FF : 0x00FF00);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
SerialCheck();
|
||||
packet_write();
|
||||
}
|
||||
|
||||
static uint8_t len, r, checksum;
|
||||
static bool escape = false;
|
||||
|
||||
static uint8_t packet_read() {
|
||||
|
||||
while (SerialDevice.available()) {
|
||||
r = SerialDevice.read();
|
||||
if (r == 0xE0) {
|
||||
req.frame_len = 0xFF;
|
||||
continue;
|
||||
}
|
||||
if (req.frame_len == 0xFF) {
|
||||
req.frame_len = r;
|
||||
len = 0;
|
||||
checksum = r;
|
||||
continue;
|
||||
}
|
||||
if (r == 0xD0) {
|
||||
escape = true;
|
||||
continue;
|
||||
}
|
||||
if (escape) {
|
||||
r++;
|
||||
escape = false;
|
||||
}
|
||||
req.bytes[++len] = r;
|
||||
if (len == req.frame_len && checksum == r) {
|
||||
return req.cmd;
|
||||
}
|
||||
checksum += r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void packet_write() {
|
||||
uint8_t checksum = 0, len = 0;
|
||||
if (res.cmd == 0) {
|
||||
return;
|
||||
}
|
||||
SerialDevice.write(0xE0);
|
||||
while (len <= res.frame_len) {
|
||||
uint8_t w;
|
||||
if (len == res.frame_len) {
|
||||
w = checksum;
|
||||
} else {
|
||||
w = res.bytes[len];
|
||||
checksum += w;
|
||||
}
|
||||
if (w == 0xE0 || w == 0xD0) {
|
||||
SerialDevice.write(0xD0);
|
||||
SerialDevice.write(--w);
|
||||
} else {
|
||||
SerialDevice.write(w);
|
||||
}
|
||||
len++;
|
||||
}
|
||||
res.cmd = 0;
|
||||
}
|
||||
|
||||
void SerialCheck() {
|
||||
switch (packet_read()) {
|
||||
case SG_NFC_CMD_RESET:
|
||||
sg_nfc_cmd_reset();
|
||||
break;
|
||||
case SG_NFC_CMD_GET_FW_VERSION:
|
||||
sg_nfc_cmd_get_fw_version();
|
||||
break;
|
||||
case SG_NFC_CMD_GET_HW_VERSION:
|
||||
sg_nfc_cmd_get_hw_version();
|
||||
break;
|
||||
case SG_NFC_CMD_POLL:
|
||||
sg_nfc_cmd_poll();
|
||||
break;
|
||||
case SG_NFC_CMD_MIFARE_READ_BLOCK:
|
||||
sg_nfc_cmd_mifare_read_block();
|
||||
break;
|
||||
case SG_NFC_CMD_FELICA_ENCAP:
|
||||
sg_nfc_cmd_felica_encap();
|
||||
break;
|
||||
case SG_NFC_CMD_AIME_AUTHENTICATE:
|
||||
sg_nfc_cmd_aime_authenticate();
|
||||
break;
|
||||
case SG_NFC_CMD_BANA_AUTHENTICATE:
|
||||
sg_nfc_cmd_bana_authenticate();
|
||||
break;
|
||||
case SG_NFC_CMD_MIFARE_SELECT_TAG:
|
||||
sg_nfc_cmd_mifare_select_tag();
|
||||
break;
|
||||
case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
|
||||
sg_nfc_cmd_mifare_set_key_aime();
|
||||
break;
|
||||
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
|
||||
sg_nfc_cmd_mifare_set_key_bana();
|
||||
break;
|
||||
case SG_NFC_CMD_RADIO_ON:
|
||||
sg_nfc_cmd_radio_on();
|
||||
break;
|
||||
case SG_NFC_CMD_RADIO_OFF:
|
||||
sg_nfc_cmd_radio_off();
|
||||
break;
|
||||
case SG_RGB_CMD_RESET:
|
||||
sg_led_cmd_reset();
|
||||
break;
|
||||
case SG_RGB_CMD_GET_INFO:
|
||||
sg_led_cmd_get_info();
|
||||
break;
|
||||
case SG_RGB_CMD_SET_COLOR:
|
||||
sg_led_cmd_set_color();
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
sg_res_init();
|
||||
}
|
||||
}
|
57
Arduino-Aime-Reader/README.md
Normal file
57
Arduino-Aime-Reader/README.md
Normal file
@ -0,0 +1,57 @@
|
||||
# Arduino-Aime-Reader
|
||||
使用 Arduino + PN532 + WS2812B 制作的 Aime 兼容读卡器。
|
||||
**目前所有主要功能已经实现,如果没有 bug 应该不会再更新。**
|
||||
English: [lawliuwuu/Arduino-Aime-Reader](https://github.com/lawliuwuu/Arduino-Aime-Reader)
|
||||
|
||||
支持卡片类型: [FeliCa](https://zh.wikipedia.org/wiki/FeliCa)(Amusement IC、Suica、八达通等)和 [MIFARE](https://zh.wikipedia.org/wiki/MIFARE)(Aime,Banapassport)。
|
||||
实现逻辑为官方读卡器串口数据对比 + 脑补,不保证正确实现。
|
||||
通信数据格式参考了 [Segatools]() 和官方读卡器抓包数据,可在 [Example.txt](doc/Example.txt) 和 [nfc.txt](doc/nfc.txt) 查看。
|
||||
一个使用例:[ESP32-CardReader](https://github.com/Sucareto/ESP32-CardReader)
|
||||
|
||||
### 使用方法:
|
||||
1. 按照 [PN532](https://github.com/elechouse/PN532) 的提示安装库
|
||||
2. 按照使用方式,在 Arduino 和 PN532 接好连接线(I2C或SPI),并调整 PN532 上的拨码开关
|
||||
3. 接上 WS2812B 灯条(可选)
|
||||
4. 上传 [ReaderTest](tools/ReaderTest/ReaderTest.ino) 测试硬件是否工作正常
|
||||
5. 若读卡正常,可按照支持列表打开设备管理器设置 COM 端口号
|
||||
6. 按照游戏的波特率设置代码的`high_baudrate`选项,`115200`是`true`,`38400`是`false`
|
||||
7. 上传程序打开游戏测试
|
||||
8. 安装 [MifareClassicTool](https://github.com/ikarus23/MifareClassicTool),修改 [Aime 卡示例](doc/aime示例.mct) 后写入空白 MIFARE UID/CUID 卡
|
||||
|
||||
某些 Arduino 可能需要在游戏主程序连接前给串口以正确的波特率发送 DTR/RTS,需要先打开一次 Arduino 串口监视器再启动主程序。
|
||||
如果是 SDBT,可以在启动前运行一次 [DTR-RTS.exe](tools/DTR-RTS.exe) 以向 COM1 和 COM12 发送DTR/RTS。
|
||||
如果需要向其他端口和特定的波特率发送,可以修改 [DTR-RTS.c](tools/DTR-RTS.c) 然后编译。
|
||||
|
||||
|
||||
### 支持列表:
|
||||
| 游戏代号 | COM端口号 | 支持的卡 | 默认波特率 |
|
||||
| - | - | - | - |
|
||||
| SDDT/SDEZ | COM1 | FeliCa,MIFARE | 115200 |
|
||||
| SDEY | COM2 | MIFARE | 38400 |
|
||||
| SDHD | COM4 | FeliCa,MIFARE | cvt=38400,sp=115200 |
|
||||
| SBZV/SDDF | COM10 | FeliCa,MIFARE | 38400 |
|
||||
| SDBT | COM12 | FeliCa,MIFARE | 38400 |
|
||||
|
||||
- 如果读卡器没有正常工作,可以切换波特率试下
|
||||
- 有使用 amdaemon 的,可以参考 config_common.json 内 aime > unit > port 确认端口号
|
||||
- 如果 `"high_baudrate" : true` 则波特率是`115200`,否则就是`38400`
|
||||
|
||||
|
||||
### 已测试开发板:
|
||||
- SparkFun Pro Micro(ATmega32U4),需要发送 DTR/RTS
|
||||
- SparkFun SAMD21 Dev Breakout(ATSAMD21G18)
|
||||
- NodeMCU 1.0(ESP-12E + CP2102 & CH340),SDA=D2,SCL=D1
|
||||
- NodeMCU-32S(ESP32-S + CH340)
|
||||
|
||||
|
||||
### 已知问题:
|
||||
- 在 NDA_08 命令的写入 Felica 操作没有实现,因为未确认是否会影响卡片后续使用
|
||||
- 未确定`res.status`的意义,因此`res.status = 1;`可能是错误的
|
||||
- 未实现`mifare_select_tag`,未支持多卡选择,只会读到最先识别的卡片
|
||||
|
||||
|
||||
### 引用库:
|
||||
- 驱动 WS2812B:[FastLED](https://github.com/FastLED/FastLED)
|
||||
- 驱动 PN532:[PN532](https://github.com/elechouse/PN532)
|
||||
- 读取 FeliCa 参考:[PN532を使ってArduinoでFeliCa学生証を読む方法](https://qiita.com/gpioblink/items/91597a5275862f7ffb3c)
|
||||
- 读取 FeliCa 数据的程序:[NFC TagInfo](https://play.google.com/store/apps/details?id=at.mroland.android.apps.nfctaginfo),[NFC TagInfo by NXP](https://play.google.com/store/apps/details?id=com.nxp.taginfolite)
|
323
Arduino-Aime-Reader/cmd.h
Normal file
323
Arduino-Aime-Reader/cmd.h
Normal file
@ -0,0 +1,323 @@
|
||||
#include "FastLED.h"
|
||||
#define NUM_LEDS 1
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#define SerialDevice Serial
|
||||
#define LED_PIN 5
|
||||
|
||||
|
||||
#if defined(PN532_SPI_SS)
|
||||
#pragma message "使用 SPI 连接 PN532"
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
PN532_SPI pn532(SPI, PN532_SPI_SS);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
PN532_I2C pn532(Wire);
|
||||
#endif
|
||||
|
||||
#include "PN532.h"
|
||||
PN532 nfc(pn532);
|
||||
|
||||
uint8_t AimeKey[6], BanaKey[6];
|
||||
|
||||
enum {
|
||||
SG_NFC_CMD_GET_FW_VERSION = 0x30,
|
||||
SG_NFC_CMD_GET_HW_VERSION = 0x32,
|
||||
SG_NFC_CMD_RADIO_ON = 0x40,
|
||||
SG_NFC_CMD_RADIO_OFF = 0x41,
|
||||
SG_NFC_CMD_POLL = 0x42,
|
||||
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
|
||||
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50,
|
||||
SG_NFC_CMD_BANA_AUTHENTICATE = 0x51,
|
||||
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
|
||||
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54,
|
||||
SG_NFC_CMD_AIME_AUTHENTICATE = 0x55,
|
||||
SG_NFC_CMD_TO_UPDATER_MODE = 0x60,
|
||||
SG_NFC_CMD_SEND_HEX_DATA = 0x61,
|
||||
SG_NFC_CMD_RESET = 0x62,
|
||||
SG_NFC_CMD_FELICA_ENCAP = 0x71,
|
||||
SG_RGB_CMD_SET_COLOR = 0x81,
|
||||
SG_RGB_CMD_GET_INFO = 0xF0,
|
||||
SG_RGB_CMD_RESET = 0xF5,
|
||||
|
||||
//FELICA_ENCAP
|
||||
FELICA_CMD_POLL = 0x00,
|
||||
FELICA_CMD_NDA_06 = 0x06,
|
||||
FELICA_CMD_NDA_08 = 0x08,
|
||||
FELICA_CMD_GET_SYSTEM_CODE = 0x0C,
|
||||
FELICA_CMD_NDA_A4 = 0xA4,
|
||||
};
|
||||
|
||||
typedef union packet_req {
|
||||
uint8_t bytes[128];
|
||||
struct {
|
||||
uint8_t frame_len;
|
||||
uint8_t addr;
|
||||
uint8_t seq_no;
|
||||
uint8_t cmd;
|
||||
uint8_t payload_len;
|
||||
union {
|
||||
uint8_t key[6]; //sg_nfc_req_mifare_set_key(bana or aime)
|
||||
uint8_t color_payload[3];//sg_led_req_set_color
|
||||
struct { //sg_nfc_cmd_mifare_select_tag,sg_nfc_cmd_mifare_authenticate,sg_nfc_cmd_mifare_read_block
|
||||
uint8_t uid[4];
|
||||
uint8_t block_no;
|
||||
};
|
||||
struct { //sg_nfc_req_felica_encap
|
||||
uint8_t encap_IDm[8];
|
||||
uint8_t encap_len;
|
||||
uint8_t encap_code;
|
||||
union {
|
||||
struct { //FELICA_CMD_POLL,猜测
|
||||
uint8_t poll_systemCode[2];
|
||||
uint8_t poll_requestCode;
|
||||
uint8_t poll_timeout;
|
||||
};
|
||||
struct { //NDA_06,NDA_08,NDA_A4
|
||||
uint8_t RW_IDm[8];
|
||||
uint8_t numService;//and NDA_A4 unknown byte
|
||||
uint8_t serviceCodeList[2];
|
||||
uint8_t numBlock;
|
||||
uint8_t blockList[1][2];//长度可变
|
||||
uint8_t blockData[16];//WriteWithoutEncryption,ignore
|
||||
};
|
||||
uint8_t felica_payload[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} packet_req_t;
|
||||
|
||||
typedef union packet_res {
|
||||
uint8_t bytes[128];
|
||||
struct {
|
||||
uint8_t frame_len;
|
||||
uint8_t addr;
|
||||
uint8_t seq_no;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t payload_len;
|
||||
union {
|
||||
char version[23]; //sg_nfc_res_get_fw_version,sg_nfc_res_get_hw_version
|
||||
uint8_t info_payload[9]; //sg_led_res_get_info
|
||||
uint8_t block[16]; //sg_nfc_res_mifare_read_block
|
||||
struct { //sg_nfc_res_poll
|
||||
uint8_t count;
|
||||
uint8_t type;
|
||||
uint8_t id_len;
|
||||
union {
|
||||
uint8_t mifare_uid[4];
|
||||
struct {
|
||||
uint8_t IDm[8];
|
||||
uint8_t PMm[8];
|
||||
};
|
||||
};
|
||||
};
|
||||
struct { //sg_nfc_res_felica_encap
|
||||
uint8_t encap_len;
|
||||
uint8_t encap_code;
|
||||
uint8_t encap_IDm[8];
|
||||
union {
|
||||
struct {//FELICA_CMD_POLL
|
||||
uint8_t poll_PMm[8];
|
||||
uint8_t poll_systemCode[2];
|
||||
};
|
||||
struct {
|
||||
uint8_t RW_status[2];//猜测,NDA_06,NDA_08
|
||||
uint8_t numBlock;//NDA_06
|
||||
uint8_t blockData[1][1][16];//NDA_06
|
||||
};
|
||||
uint8_t felica_payload[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} packet_res_t;
|
||||
|
||||
static packet_req_t req;
|
||||
static packet_res_t res;
|
||||
|
||||
static void sg_res_init(uint8_t payload_len = 0) { //初始化模板
|
||||
res.frame_len = 6 + payload_len;
|
||||
res.addr = req.addr;
|
||||
res.seq_no = req.seq_no;
|
||||
res.cmd = req.cmd;
|
||||
res.status = 0;
|
||||
res.payload_len = payload_len;
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_reset() { //重置读卡器
|
||||
nfc.begin();
|
||||
nfc.setPassiveActivationRetries(0x01); //设定等待次数,0xFF永远等待
|
||||
nfc.SAMConfig();
|
||||
if (nfc.getFirmwareVersion()) {
|
||||
nfc.SAMConfig();
|
||||
sg_res_init();
|
||||
res.status = 3;
|
||||
return;
|
||||
}
|
||||
FastLED.showColor(0xFF0000);
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_get_fw_version() {
|
||||
sg_res_init(23);
|
||||
memcpy(res.version, "TN32MSEC003S F/W Ver1.2", 23);
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_get_hw_version() {
|
||||
sg_res_init(23);
|
||||
memcpy(res.version, "TN32MSEC003S H/W Ver3.0", 23);
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_mifare_set_key_aime() {
|
||||
sg_res_init();
|
||||
memcpy(AimeKey, req.key, 6);
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_mifare_set_key_bana() {
|
||||
sg_res_init();
|
||||
memcpy(BanaKey, req.key, 6);
|
||||
}
|
||||
|
||||
static void sg_led_cmd_reset() {
|
||||
sg_res_init();
|
||||
}
|
||||
|
||||
static void sg_led_cmd_get_info() {
|
||||
sg_res_init(9);
|
||||
static uint8_t info[9] = {'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12};
|
||||
memcpy(res.info_payload, info, 9);
|
||||
}
|
||||
|
||||
static void sg_led_cmd_set_color() {
|
||||
FastLED.showColor(CRGB(req.color_payload[0], req.color_payload[1], req.color_payload[2]));
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_radio_on() {
|
||||
sg_res_init();
|
||||
nfc.setRFField(0x00, 0x01);
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_radio_off() {
|
||||
sg_res_init();
|
||||
nfc.setRFField(0x00, 0x00);
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_poll() { //卡号发送
|
||||
uint16_t SystemCode;
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len)) {
|
||||
sg_res_init(0x07);
|
||||
res.count = 1;
|
||||
res.type = 0x10;
|
||||
return;
|
||||
}
|
||||
else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) {//< 0: error
|
||||
sg_res_init(0x13);
|
||||
res.count = 1;
|
||||
res.type = 0x20;
|
||||
res.id_len = 0x10;
|
||||
return;
|
||||
} else {
|
||||
sg_res_init(1);
|
||||
res.count = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_mifare_select_tag() {
|
||||
sg_res_init();
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_aime_authenticate() {
|
||||
sg_res_init();
|
||||
//AuthenticateBlock(uid,uidLen,block,keyType(A=0,B=1),keyData)
|
||||
if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, AimeKey)) {
|
||||
return;
|
||||
} else {
|
||||
res.status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_bana_authenticate() {
|
||||
sg_res_init();
|
||||
//AuthenticateBlock(uid,uidLen,block,keyType(A=0,B=1),keyData)
|
||||
if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, BanaKey)) {
|
||||
return;
|
||||
} else {
|
||||
res.status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_mifare_read_block() {//读取卡扇区数据
|
||||
if (nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) {
|
||||
sg_res_init(0x10);
|
||||
return;
|
||||
}
|
||||
sg_res_init();
|
||||
res.status = 1;
|
||||
}
|
||||
|
||||
static void sg_nfc_cmd_felica_encap() {
|
||||
uint16_t SystemCode;
|
||||
if (nfc.felica_Polling(0xFFFF, 0x01, res.encap_IDm, res.poll_PMm, &SystemCode, 200) == 1) {
|
||||
SystemCode = SystemCode >> 8 | SystemCode << 8;//SystemCode,大小端反转注意
|
||||
}
|
||||
else {
|
||||
sg_res_init();
|
||||
res.status = 1;
|
||||
return;
|
||||
}
|
||||
uint8_t code = req.encap_code;
|
||||
res.encap_code = code + 1;
|
||||
switch (code) {
|
||||
case FELICA_CMD_POLL:
|
||||
{
|
||||
sg_res_init(0x14);
|
||||
res.poll_systemCode[0] = SystemCode;
|
||||
res.poll_systemCode[1] = SystemCode >> 8;
|
||||
}
|
||||
break;
|
||||
case FELICA_CMD_GET_SYSTEM_CODE:
|
||||
{
|
||||
sg_res_init(0x0D);
|
||||
res.felica_payload[0] = 0x01;//未知
|
||||
res.felica_payload[1] = SystemCode;//SystemCode
|
||||
res.felica_payload[2] = SystemCode >> 8;
|
||||
}
|
||||
break;
|
||||
case FELICA_CMD_NDA_A4:
|
||||
{
|
||||
sg_res_init(0x0B);
|
||||
res.felica_payload[0] = 0x00;
|
||||
}
|
||||
break;
|
||||
case FELICA_CMD_NDA_06:
|
||||
{
|
||||
uint16_t serviceCodeList[1] = {(uint16_t)(req.serviceCodeList[1] << 8 | req.serviceCodeList[0])};//大小端反转注意
|
||||
for (uint8_t i = 0; i < req.numBlock; 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;
|
||||
sg_res_init(0x0D + req.numBlock * 16);
|
||||
}
|
||||
break;
|
||||
case FELICA_CMD_NDA_08:
|
||||
{
|
||||
sg_res_init(0x0C);//此处应有写入卡,但是不打算实现
|
||||
res.RW_status[0] = 0;
|
||||
res.RW_status[1] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sg_res_init();
|
||||
res.status = 1;
|
||||
}
|
||||
res.encap_len = res.payload_len;
|
||||
}
|
51
Arduino-Aime-Reader/doc/Example.txt
Normal file
51
Arduino-Aime-Reader/doc/Example.txt
Normal file
@ -0,0 +1,51 @@
|
||||
//SG_NFC_CMD_GET_FW_VERSION
|
||||
E0 [05] 00 09 (30) 00 [ ]
|
||||
E0 [1D] 00 [ ] (30) 00 17 [54 4E 33 32 4D 53 45 43 30 30 33 53 20 46 2F 57 20 56 65 72 31 2E 32] [ ]
|
||||
|
||||
//SG_NFC_CMD_GET_HW_VERSION
|
||||
E0 [05] 00 [ ] (32) 00 [ ]
|
||||
E0 [1D] 00 [ ] (32) 00 17 [54 4E 33 32 4D 53 45 43 30 30 33 53 20 48 2F 57 20 56 65 72 33 2E 30] [ ]
|
||||
|
||||
//SG_RGB_CMD_GET_INFO
|
||||
E0 [05] 08 [ ] (F0) 00 [ ]
|
||||
E0 [0F] 08 [ ] (F0) 00 [09 31 35 30 38 34 FF 10 00 12] [ ]
|
||||
|
||||
//SG_NFC_CMD_POLL,FELICA
|
||||
E0 [05] 00 [ ] (42) 00 [ ]
|
||||
E0 [19] 00 [ ] (42) 00 13 01 20 10 [ 8 byte IDm ] [ 8 byte PMm ] [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,Skip reply
|
||||
E0 [13] 00 [ ] (71) [ ] [ 8 byte IDm ] [ payload_len ] ( ) [ any data ] [ ]
|
||||
E0 [06] 00 [ ] (71) [01] 00 [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_POLL
|
||||
E0 [13] 00 [ ] (71) 0E [ 8 byte IDm ] 06 (00) [FF FF 01 0F] [ ]
|
||||
E0 [1A] 00 [ ] (71) 00 [14 14] (01) [ 8 byte IDm ] [ 8 byte PMm ] [ 2 byte system_code ] [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_GET_SYSTEM_CODE
|
||||
E0 [17] 00 [ ] (71) 12 [ 8 byte IDm ] 0A (0C) [ 8 byte IDm ] [ ]
|
||||
E0 [13] 00 [ ] (71) 00 [0D 0D] (0D) [ 8 byte IDm ] 01 00 00 [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_A4
|
||||
E0 [18] 00 [ ] (71) 13 [ 8 byte IDm ] 0B (A4) [ 8 byte IDm ] 00 [ ]
|
||||
E0 [11] 00 [ ] (71) 00 [0B 0B] (A5) [ 8 byte IDm ] 00 [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_06,read block
|
||||
E0 [1D] 00 [ ] (71) 18 [ 8 byte IDm ] 10 (06) [ 8 byte IDm ] [ Service len ] [ Service Code(little-endian) ] [ Block len ] [ Block Code(big-endian) ] [ ]
|
||||
E0 [23] 00 [ ] (71) 00 [1D 1D] (07) [ 8 byte IDm ] [00 00] [ Block len ] [ 16 byte Block Data ] [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_06, read multiple blocks,Service Code=0x000B(read-only),Block Code={0x8082,0x8086,0x8090,0x8091}
|
||||
E0 [23] 00 [ ] (71) 1E [ 8 byte IDm ] 16 (06) [ 8 byte IDm ] [01] [0B 00] [04] [80 82] [80 86] [80 90] [80 91] [ ]
|
||||
E0 [53] 00 [ ] (71) 00 [4D 4D] (07) [ 8 byte IDm ] [00 00] [04] [ 8 byte IDm ] [ 16*len byte Block Data ] [ ]
|
||||
|
||||
//SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_08,write block,Service Code=0x0009(read/write),Block Code=0x8080
|
||||
E0 [2D] 00 [ ] (71) 28 [ 8 byte IDm ] 20 (08) [ 8 byte IDm ] [01] [09 00] [01] [80 80] [ 16 byte Block Data ] [ ]
|
||||
E0 [12] 00 [ ] (71) 00 [0C 0C] (09) [ 8 byte IDm ] [00 00] [ ]
|
||||
|
||||
//SG_NFC_CMD_POLL,MIFARE
|
||||
E0 [05] 00 [ ] (42) 00 [ ]
|
||||
E0 [0D] 00 [ ] (42) 00 07 01 10 04 [ 4 byte UID ] [ ]
|
||||
|
||||
//SG_NFC_CMD_MIFARE_READ_BLOCK
|
||||
E0 [0A] 00 [ ] (52) 05 [ 4 byte UID ] [ block_no ] 84
|
||||
E0 [16] 00 [ ] (52) 00 10 [ 16 byte block data ] [ ]
|
80
Arduino-Aime-Reader/doc/aime示例.mct
Normal file
80
Arduino-Aime-Reader/doc/aime示例.mct
Normal file
@ -0,0 +1,80 @@
|
||||
+Sector: 0
|
||||
1DB40F0DAB880400C832002000000016
|
||||
00000000000000000000000000000000
|
||||
00000000000010114514191981023333
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 1
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 2
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 3
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 4
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 5
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 6
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 7
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 8
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 9
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 10
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 11
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 12
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 13
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 14
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
||||
+Sector: 15
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
57434346763208778F11574343467632
|
244
Arduino-Aime-Reader/doc/nfc.txt
Normal file
244
Arduino-Aime-Reader/doc/nfc.txt
Normal file
@ -0,0 +1,244 @@
|
||||
N.B. Quoted strings are NOT NUL-terminated unless otherwise noted.
|
||||
Useful reading: https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
|
||||
|
||||
(AiMe branded cards are Mifare Classic cards. Other technologies exist though)
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
Hardware:
|
||||
Assembly connector:
|
||||
5V Host in
|
||||
Tx;Rx;GND Host RS232 in
|
||||
Tx;Rx;GND Daisy-chain out
|
||||
Main board (probably LED controller):
|
||||
Silk "837-15084"
|
||||
CN1: Host 5V power in, ?V NFC-sub power out
|
||||
CN2: Host RS232 Tx;Rx;GND in, NFC-sub Tx;Rx out
|
||||
CN3: LED-Sub power and data(?) out
|
||||
DIPSW1: Set to hex nibble 8.
|
||||
Contains ADM3222 RS232 transceiver IC
|
||||
Contains ATMega32 MCU
|
||||
NFC subboard:
|
||||
Sticker: Model "TN32MSEC003S"
|
||||
CN1: ?V power and Tx;Rx;GND in, Tx;Rx;GND ass'y CN daisy out.
|
||||
DIPSW1: Set to hex nibble 0.
|
||||
Contains ATmega168 MCU
|
||||
Contains ADM3202A RS232 transceiver IC
|
||||
Contains shielded RF circuit
|
||||
Entire non-ground-plane PCB area is visible through the chassis
|
||||
torx screws lol
|
||||
LED subboard:
|
||||
Silk: "837-15120"
|
||||
CN1: ?V power and Tx;Rx;GND in.
|
||||
Five RGB LEDs and a bunch of resistors
|
||||
No visible logic ICs..?
|
||||
No DIPSW.
|
||||
|
||||
JVS framing:
|
||||
E0 sync
|
||||
D0 escape (+1 to unescape)
|
||||
Checksum is sum of bytes after unescaping
|
||||
|
||||
Frame header:
|
||||
Frame length (including length byte itself)
|
||||
Address
|
||||
Sequence no, hopefully loops before hitting esc byte...
|
||||
Command byte
|
||||
|
||||
Bus addressing:
|
||||
Low nibble set using DIPSWs
|
||||
High nibble ???
|
||||
Daisy chaining mechanism unknown (RS232 wires probably multi-tap)
|
||||
|
||||
Startup
|
||||
-------
|
||||
|
||||
Addr 00 Command 62:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Unknown. Reset?
|
||||
|
||||
Addr 00 Command 30:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
17 Payload length
|
||||
.. "TN32MSEC003S F/W Ver1.2E"
|
||||
Description:
|
||||
Get firmware version
|
||||
|
||||
Addr 00 Command 32:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
17 Payload length
|
||||
.. "TN32MSEC003S H/W Ver3.0J"
|
||||
Description:
|
||||
Get hardware version
|
||||
|
||||
Addr 08 Command f5:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
LED sub-board reset.
|
||||
Won't accept LED commands until you do this.
|
||||
|
||||
Addr 08 Command f0:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
09 Payload length
|
||||
.. "15084" (part nr for LED board)
|
||||
FF ??
|
||||
11 ??
|
||||
00 ??
|
||||
12 ??
|
||||
Description:
|
||||
Get board "info"
|
||||
|
||||
Addr 00 Command 54:
|
||||
Req:
|
||||
06 Payload length
|
||||
57 'W'
|
||||
43 'C'
|
||||
43 'C'
|
||||
46 'F'
|
||||
76 'v'
|
||||
32 '2'
|
||||
Resp:
|
||||
00 Status byte?
|
||||
00 ??
|
||||
Description:
|
||||
Set Mifare KeyA.
|
||||
"WCCF" might refer this this SEGA arcade game:
|
||||
https://en.wikipedia.org/wiki/World_Club_Champion_Football
|
||||
It's quite old and has AiMe readers, maybe where they first appeared?
|
||||
|
||||
Addr 00 Command 50:
|
||||
Req:
|
||||
06 Payload length
|
||||
60 ??
|
||||
90 ??
|
||||
D0 ?? (This is escaped of course)
|
||||
06 ??
|
||||
32 ??
|
||||
F5 ??
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Possibly Mifare KeyB.
|
||||
|
||||
Polling
|
||||
-------
|
||||
|
||||
Addr 00 Command 40:
|
||||
Req:
|
||||
01 Payload length
|
||||
03 ??
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Poll some other NFC technology?
|
||||
|
||||
Addr 00 Command 42:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp if no MiFare card:
|
||||
00 Status byte
|
||||
01 Payload length
|
||||
00 (represents nothing i guess)
|
||||
Resp if MiFare card:
|
||||
00 Status byte?
|
||||
07 Payload length
|
||||
01 Chunk length?
|
||||
10 ?? Block size maybe?
|
||||
04 Chunk length?
|
||||
.. Mifare UID, four bytes.
|
||||
Description:
|
||||
Check for Mifare card presence?
|
||||
|
||||
Addr 00 Command 41:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Unknown. Poll some other NFC technology?
|
||||
|
||||
Card read
|
||||
---------
|
||||
|
||||
Addr 00 Command 43:
|
||||
Req:
|
||||
04 Payload length
|
||||
.. Mifare UID, four bytes.
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Select MiFare by UID?
|
||||
|
||||
Addr 00 Command 55:
|
||||
Req:
|
||||
05 Payload length
|
||||
.. Mifare UID, four bytes.
|
||||
03 ??
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Unknown.
|
||||
Block 3 on a Mifare sector contains keys and an access control list.
|
||||
It is generally not accessed directly (unless being provisioned?)
|
||||
|
||||
Addr 00 Command 52:
|
||||
Req:
|
||||
05 Payload length
|
||||
.. Mifare UID, four bytes.
|
||||
.. Block number, 1 or 2.
|
||||
Resp for Block 1:
|
||||
00 Status byte
|
||||
10 Payload length (1 block)
|
||||
.. "SBSD"
|
||||
00 00 00 00
|
||||
00 00 00 00
|
||||
00 4E C6 22
|
||||
Resp for Block 2:
|
||||
00 Status byte
|
||||
10 Payload length (1 block)
|
||||
.. 00 00 00 00 00 00 xx xx
|
||||
xx xx xx xx xx xx xx xx
|
||||
Description:
|
||||
Probably reads blocks 1 and 2 from Mifare sector 0.
|
||||
Block 0 contains the "vendor information" and UID.
|
||||
Block 1 contents are unknown, probably AiMe DB info.
|
||||
Block 2 last 10 bytes hex are printed on the card ("local unique id").
|
||||
(Block 3 contains encryption keys so is not allowed to be read)
|
||||
|
||||
LED
|
||||
---
|
||||
|
||||
Addr 08 Command 81:
|
||||
Req:
|
||||
03 Payload length
|
||||
ff Red intensity
|
||||
ff Green intensity
|
||||
ff Blue intensity
|
||||
Resp:
|
||||
None! Command is not acknowledged
|
||||
Description:
|
||||
Set LED color
|
44
Arduino-Aime-Reader/tools/DTR-RTS.c
Normal file
44
Arduino-Aime-Reader/tools/DTR-RTS.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <windows.h>
|
||||
|
||||
int main() {
|
||||
HANDLE com;
|
||||
com = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
DCB dcbSerialParams = {0};
|
||||
COMMTIMEOUTS timeouts = {0};
|
||||
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
|
||||
GetCommState(com, &dcbSerialParams);
|
||||
dcbSerialParams.BaudRate = 115200;
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
dcbSerialParams.StopBits = ONESTOPBIT;
|
||||
dcbSerialParams.Parity = NOPARITY;
|
||||
SetCommState(com, &dcbSerialParams);
|
||||
timeouts.ReadIntervalTimeout = 1;
|
||||
timeouts.ReadTotalTimeoutConstant = 1;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 1;
|
||||
timeouts.WriteTotalTimeoutConstant = 1;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 1;
|
||||
SetCommTimeouts(com, &timeouts);
|
||||
EscapeCommFunction(com, SETDTR);
|
||||
EscapeCommFunction(com, SETRTS);
|
||||
|
||||
com = CreateFile("\\\\.\\COM12", GENERIC_READ | GENERIC_WRITE, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
|
||||
GetCommState(com, &dcbSerialParams);
|
||||
dcbSerialParams.BaudRate = 38400;
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
dcbSerialParams.StopBits = ONESTOPBIT;
|
||||
dcbSerialParams.Parity = NOPARITY;
|
||||
SetCommState(com, &dcbSerialParams);
|
||||
timeouts.ReadIntervalTimeout = 1;
|
||||
timeouts.ReadTotalTimeoutConstant = 1;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 1;
|
||||
timeouts.WriteTotalTimeoutConstant = 1;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 1;
|
||||
SetCommTimeouts(com, &timeouts);
|
||||
EscapeCommFunction(com, SETDTR);
|
||||
EscapeCommFunction(com, SETRTS);
|
||||
|
||||
return 0;
|
||||
}
|
BIN
Arduino-Aime-Reader/tools/DTR-RTS.exe
Normal file
BIN
Arduino-Aime-Reader/tools/DTR-RTS.exe
Normal file
Binary file not shown.
137
Arduino-Aime-Reader/tools/ReaderTest/ReaderTest.ino
Normal file
137
Arduino-Aime-Reader/tools/ReaderTest/ReaderTest.ino
Normal file
@ -0,0 +1,137 @@
|
||||
#if defined(__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_ZERO)
|
||||
#pragma message "当前的开发板是 ATmega32U4 或 SAMD_ZERO"
|
||||
#define SerialDevice SerialUSB
|
||||
#define PN532_SPI_SS 10 //32U4 不使用 SPI 时,执行 ReadWithoutEncryption 会失败
|
||||
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#pragma message "当前的开发板是 UNO/NANO/Micro"
|
||||
#define SerialDevice Serial
|
||||
|
||||
#elif defined(ARDUINO_NodeMCU_32S)
|
||||
#pragma message "当前的开发板是 NodeMCU_32S"
|
||||
#define SerialDevice Serial
|
||||
#define PN532_SPI_SS 5
|
||||
|
||||
#else
|
||||
#error "未经测试的开发板,请检查串口和阵脚定义"
|
||||
#endif
|
||||
|
||||
#if defined(PN532_SPI_SS)
|
||||
#pragma message "使用 SPI 连接 PN532"
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
PN532_SPI pn532(SPI, PN532_SPI_SS);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
PN532_I2C pn532(Wire);
|
||||
#endif
|
||||
|
||||
#include "PN532.h"
|
||||
PN532 nfc(pn532);
|
||||
|
||||
typedef union {
|
||||
uint8_t block[18];
|
||||
struct {
|
||||
uint8_t IDm[8];
|
||||
uint8_t PMm[8];
|
||||
union {
|
||||
uint16_t SystemCode;
|
||||
uint8_t System_Code[2];
|
||||
};
|
||||
};
|
||||
} Card;
|
||||
Card card;
|
||||
|
||||
uint8_t AimeKey[6] = {0x57, 0x43, 0x43, 0x46, 0x76, 0x32};
|
||||
uint8_t BanaKey[6] = {0x60, 0x90, 0xD0, 0x06, 0x32, 0xF5};
|
||||
uint8_t MifareKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
#define M2F_B 1
|
||||
uint16_t blockList[4] = {0x8080, 0x8081, 0x8082, 0x8083};
|
||||
uint16_t serviceCodeList[1] = {0x000B};
|
||||
uint8_t blockData[1][16];
|
||||
|
||||
void setup() {
|
||||
SerialDevice.begin(115200);
|
||||
// Wire.setClock(800000);
|
||||
while (!SerialDevice);
|
||||
nfc.begin();
|
||||
while (!nfc.getFirmwareVersion()) {
|
||||
SerialDevice.println("Didn't find PN53x board");
|
||||
delay(500);
|
||||
}
|
||||
SerialDevice.println("START!");
|
||||
nfc.setPassiveActivationRetries(0x10);
|
||||
nfc.SAMConfig();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint8_t uid[4], uL;
|
||||
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, 1, AimeKey)) {
|
||||
SerialDevice.println("Aime card!");
|
||||
SerialDevice.print("UID Value:");
|
||||
nfc.PrintHex(uid, uL);
|
||||
SerialDevice.print("Block 2 Data:");
|
||||
if (nfc.mifareclassic_ReadDataBlock(2, card.block)) {
|
||||
nfc.PrintHex(card.block, 16);
|
||||
}
|
||||
delay(2000);
|
||||
return;
|
||||
}
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, 0, BanaKey)) {
|
||||
SerialDevice.println("Banapassport card!");
|
||||
SerialDevice.print("UID Value:");
|
||||
nfc.PrintHex(uid, uL);
|
||||
SerialDevice.print("Block 2 Data:");
|
||||
if (nfc.mifareclassic_ReadDataBlock(2, card.block)) {
|
||||
nfc.PrintHex(card.block, 16);
|
||||
}
|
||||
delay(2000);
|
||||
return;
|
||||
}
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, M2F_B, 0, MifareKey)) {
|
||||
SerialDevice.println("Default Key Mifare!");
|
||||
if (nfc.mifareclassic_ReadDataBlock(2, card.block)) {
|
||||
SerialDevice.print("Fake IDm:");
|
||||
nfc.PrintHex(card.IDm, 8);
|
||||
SerialDevice.print("Fake PMm:");
|
||||
nfc.PrintHex(card.PMm, 8);
|
||||
}
|
||||
delay(2000);
|
||||
return;
|
||||
}
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL)) {
|
||||
SerialDevice.println("Unknown key Mifare.");
|
||||
SerialDevice.print("UID Value:");
|
||||
nfc.PrintHex(uid, uL);
|
||||
delay(2000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nfc.felica_Polling(0xFFFF, 0x01, card.IDm, card.PMm, &card.SystemCode, 200)) {
|
||||
SerialDevice.println("FeliCa card!");
|
||||
SerialDevice.print("IDm:");
|
||||
nfc.PrintHex(card.IDm, 8);
|
||||
SerialDevice.print("PMm:");
|
||||
nfc.PrintHex(card.PMm, 8);
|
||||
SerialDevice.print("SystemCode:");
|
||||
card.SystemCode = card.SystemCode >> 8 | card.SystemCode << 8;
|
||||
nfc.PrintHex(card.System_Code, 2);
|
||||
|
||||
|
||||
Serial.println("FeliCa Block:");
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 1, &blockList[i], blockData) == 1) {
|
||||
Serial.println(blockList[i], HEX);
|
||||
nfc.PrintHex(blockData[0], 16);
|
||||
} else {
|
||||
Serial.println("error");
|
||||
}
|
||||
}
|
||||
delay(2000);
|
||||
return;
|
||||
}
|
||||
SerialDevice.println("Didn't find card");
|
||||
delay(500);
|
||||
}
|
BIN
Arduino-Aime-Reader/tools/chunihook.dll
Normal file
BIN
Arduino-Aime-Reader/tools/chunihook.dll
Normal file
Binary file not shown.
142
Arduino-Aime-Reader/tools/sg-cmd.c
Normal file
142
Arduino-Aime-Reader/tools/sg-cmd.c
Normal file
@ -0,0 +1,142 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "board/sg-cmd.h"
|
||||
#include "board/sg-frame.h"
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
union sg_req_any {
|
||||
struct sg_req_header req;
|
||||
uint8_t bytes[256];
|
||||
};
|
||||
|
||||
union sg_res_any {
|
||||
struct sg_res_header res;
|
||||
uint8_t bytes[256];
|
||||
};
|
||||
|
||||
static HRESULT sg_req_validate(const void *ptr, size_t nbytes);
|
||||
|
||||
static void sg_res_error(
|
||||
struct sg_res_header *res,
|
||||
const struct sg_req_header *req);
|
||||
|
||||
static HRESULT sg_req_validate(const void *ptr, size_t nbytes)
|
||||
{
|
||||
const struct sg_req_header *req;
|
||||
size_t payload_len;
|
||||
|
||||
assert(ptr != NULL);
|
||||
|
||||
if (nbytes < sizeof(*req)) {
|
||||
dprintf("SG Cmd: Request header truncated\n");
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
req = ptr;
|
||||
|
||||
if (req->hdr.frame_len != nbytes) {
|
||||
dprintf("SG Cmd: Frame length mismatch: got %i exp %i\n",
|
||||
req->hdr.frame_len,
|
||||
(int) nbytes);
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
payload_len = req->hdr.frame_len - sizeof(*req);
|
||||
|
||||
if (req->payload_len != payload_len) {
|
||||
dprintf("SG Cmd: Payload length mismatch: got %i exp %i\n",
|
||||
req->payload_len,
|
||||
(int) payload_len);
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void sg_req_transact(
|
||||
struct iobuf *res_frame,
|
||||
const uint8_t *req_bytes,
|
||||
size_t req_nbytes,
|
||||
sg_dispatch_fn_t dispatch,
|
||||
void *ctx)
|
||||
{
|
||||
struct iobuf req_span;
|
||||
union sg_req_any req;
|
||||
union sg_res_any res;
|
||||
HRESULT hr;
|
||||
|
||||
assert(res_frame != NULL);
|
||||
assert(req_bytes != NULL);
|
||||
assert(dispatch != NULL);
|
||||
|
||||
req_span.bytes = req.bytes;
|
||||
req_span.nbytes = sizeof(req.bytes);
|
||||
req_span.pos = 0;
|
||||
|
||||
hr = sg_frame_decode(&req_span, req_bytes, req_nbytes);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = sg_req_validate(req.bytes, req_span.pos);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = dispatch(ctx, &req, &res);
|
||||
|
||||
if (hr != S_FALSE) {
|
||||
if (FAILED(hr)) {
|
||||
sg_res_error(&res.res, &req.req);
|
||||
}
|
||||
|
||||
sg_frame_encode(res_frame, res.bytes, res.res.hdr.frame_len);
|
||||
printf("req: ");
|
||||
for (uint8_t i = 0; i < req_nbytes; i++)
|
||||
printf("%02X ", req_bytes[i]);
|
||||
printf("\n");
|
||||
printf("res: ");
|
||||
for (uint8_t i = 0; i < res_frame->pos; i++)
|
||||
printf("%02X ", res_frame->bytes[i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void sg_res_init(
|
||||
struct sg_res_header *res,
|
||||
const struct sg_req_header *req,
|
||||
size_t payload_len)
|
||||
{
|
||||
assert(res != NULL);
|
||||
assert(req != NULL);
|
||||
|
||||
res->hdr.frame_len = sizeof(*res) + payload_len;
|
||||
res->hdr.addr = req->hdr.addr;
|
||||
res->hdr.seq_no = req->hdr.seq_no;
|
||||
res->hdr.cmd = req->hdr.cmd;
|
||||
res->status = 0;
|
||||
res->payload_len = payload_len;
|
||||
}
|
||||
|
||||
static void sg_res_error(
|
||||
struct sg_res_header *res,
|
||||
const struct sg_req_header *req)
|
||||
{
|
||||
assert(res != NULL);
|
||||
assert(req != NULL);
|
||||
|
||||
res->hdr.frame_len = sizeof(*res);
|
||||
res->hdr.addr = req->hdr.addr;
|
||||
res->hdr.seq_no = req->hdr.seq_no;
|
||||
res->hdr.cmd = req->hdr.cmd;
|
||||
res->status = 1;
|
||||
res->payload_len = 0;
|
||||
}
|
184
Mai2TouchOK/Mai2TouchOK.ino
Normal file
184
Mai2TouchOK/Mai2TouchOK.ino
Normal file
@ -0,0 +1,184 @@
|
||||
//高敏度低延迟可能串音版本
|
||||
|
||||
|
||||
|
||||
//#define SerialDevice SerialUSB //32u4,samd21
|
||||
#define SerialDevice Serial //esp8266
|
||||
|
||||
// bitWrite 不支持 uint64_t,以下定义来自 https://forum.arduino.cc/t/bitset-only-sets-bits-from-0-to-31-previously-to-15/193385/5
|
||||
#define bitSet64(value, bit) ((value) |= (bit<32?1UL:1ULL) <<(bit))
|
||||
#define bitClear64(value, bit) ((value) &= ~(bit<32?1UL:1ULL) <<(bit))
|
||||
#define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet64(value, bit) : bitClear64(value, bit))
|
||||
#define Threshold 10 //触摸触发阈值
|
||||
|
||||
#include "Adafruit_MPR121.h"//mpr121定义
|
||||
Adafruit_MPR121 mprA, mprB, mprC;
|
||||
#define CLAMP(val) (val < 0 ? 0 : (val > 255 ? 255 : val))
|
||||
uint8_t packet[6];
|
||||
uint8_t len = 0;//当前接收的包长度
|
||||
#define sA1(x) bitWrite(TPD, 0, x)//设置 sensor
|
||||
#define sB1(x) bitWrite(TPD, 8, x)
|
||||
#define sC1(x) bitWrite(TPD, 16, x)
|
||||
#define sD1(x) bitWrite(TPD, 18, x)
|
||||
#define sE1(x) bitWrite(TPD, 26, x)
|
||||
enum {
|
||||
commandRSET = 0x45,//E
|
||||
commandHALT = 0x4C,//L
|
||||
commandSTAT = 0x41,//A
|
||||
commandRatio = 0x72,//r
|
||||
commandSens = 0x6B,//k
|
||||
};
|
||||
|
||||
bool Conditioning = 1;
|
||||
void setup() {
|
||||
SerialDevice.begin(9600);
|
||||
SerialDevice.setTimeout(0);
|
||||
uint8_t TOUCH = 1;//按下敏感度
|
||||
uint8_t RELEASE = 1;//松开敏感度
|
||||
mprA.begin(0x5A, &Wire);
|
||||
mprB.begin(0x5C, &Wire);
|
||||
mprC.begin(0x5B, &Wire);
|
||||
Wire.setClock(800000);
|
||||
// delay(100);
|
||||
// MprSetup(mprA);
|
||||
// MprSetup(mprB);
|
||||
// MprSetup(mprC);
|
||||
// delay(100);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Recv();
|
||||
Conditioning ? void() : TouchSend();//只有不处于设定模式时才发送触摸数据
|
||||
}
|
||||
void MprSetup(Adafruit_MPR121 cap) {//mpr121自定义初始化
|
||||
cap.writeRegister(MPR121_SOFTRESET, 0x63);//MprReset
|
||||
delay(1);
|
||||
cap.writeRegister(MPR121_ECR, 0x0);//MprStop
|
||||
cap.writeRegister(MPR121_MHDR, 1);// 上升最大变化值
|
||||
cap.writeRegister(MPR121_NHDR, 4);//上升幅度
|
||||
cap.writeRegister(MPR121_NCLR, 8);//上升修正样本个数
|
||||
cap.writeRegister(MPR121_FDLR, 0);//修正前等待样本个数
|
||||
cap.writeRegister(MPR121_MHDF, 1);//下降最大变化值
|
||||
cap.writeRegister(MPR121_NHDF, 1);//下降幅度
|
||||
cap.writeRegister(MPR121_NCLF, 4);//下降修正样本个数
|
||||
cap.writeRegister(MPR121_FDLF, 4);//修正前等待样本个数
|
||||
cap.writeRegister(MPR121_NHDT, 0);
|
||||
cap.writeRegister(MPR121_NCLT, 0);
|
||||
cap.writeRegister(MPR121_FDLT, 0);
|
||||
// cap.writeRegister(MPR121_ESI,MPR121_ESI_1MS);/
|
||||
cap.setThresholds(Threshold, Threshold); //设置触发阈值和充放电流时间
|
||||
cap.writeRegister(MPR121_DEBOUNCE, (4 << 4) | 2); //设置采样数,0
|
||||
cap.writeRegister(MPR121_CONFIG1, 16);//0x10
|
||||
cap.writeRegister(MPR121_CONFIG2, 1<<5);
|
||||
cap.writeRegister(MPR121_AUTOCONFIG0, 0x0B);
|
||||
cap.writeRegister(MPR121_AUTOCONFIG1, (1 << 7));
|
||||
cap.writeRegister(MPR121_UPLIMIT, 202);//上限,((Vdd - 0.7)/Vdd) * 256
|
||||
cap.writeRegister(MPR121_TARGETLIMIT, 182);//目标,UPLIMIT * 0.9
|
||||
cap.writeRegister(MPR121_LOWLIMIT, 131);//下限,UPLIMIT * 0.65
|
||||
cap.writeRegister(MPR121_ECR, B01000000 + 12);//MprRun
|
||||
}
|
||||
void cmd_RSET() {//Reset
|
||||
MprSetup(mprA);
|
||||
MprSetup(mprB);
|
||||
MprSetup(mprC);
|
||||
|
||||
|
||||
|
||||
}
|
||||
void cmd_HALT() {//Start Conditioning Mode
|
||||
mprA.writeRegister(MPR121_ECR, 0x0);//MprStop
|
||||
mprB.writeRegister(MPR121_ECR, 0x0);
|
||||
mprC.writeRegister(MPR121_ECR, 0x0);
|
||||
Conditioning = true;
|
||||
}
|
||||
|
||||
void cmd_Ratio() {//Set Touch Panel Ratio
|
||||
SerialDevice.write((byte)'(');
|
||||
SerialDevice.write((byte)packet[1]);//L,R
|
||||
SerialDevice.write((byte)packet[2]);//sensor
|
||||
SerialDevice.write((byte)'r');
|
||||
SerialDevice.write((byte)packet[4]);//Ratio
|
||||
SerialDevice.write((byte)')');
|
||||
}
|
||||
|
||||
void cmd_Sens() {//Set Touch Panel Sensitivity
|
||||
SerialDevice.write((byte)'(');
|
||||
SerialDevice.write((byte)packet[1]);//L,R
|
||||
SerialDevice.write((byte)packet[2]);//sensor
|
||||
SerialDevice.write((byte)'k');
|
||||
SerialDevice.write((byte)packet[4]);//Sensitivity
|
||||
SerialDevice.write((byte)')');
|
||||
}
|
||||
|
||||
void cmd_STAT() { //End Conditioning Mode
|
||||
Conditioning = false;
|
||||
mprA.writeRegister(MPR121_ECR, B10000000 + 12);//MprRun
|
||||
mprB.writeRegister(MPR121_ECR, B10000000 + 12);
|
||||
mprC.writeRegister(MPR121_ECR, B10000000 + 12);
|
||||
}
|
||||
|
||||
void Recv() {
|
||||
while (SerialDevice.available()) {
|
||||
uint8_t r = SerialDevice.read();
|
||||
if (r == '{') {
|
||||
len = 0;
|
||||
}
|
||||
if (r == '}') {
|
||||
break;
|
||||
}
|
||||
packet[len++] = r;
|
||||
}
|
||||
if (len == 5) {
|
||||
switch (packet[3]) {
|
||||
case commandRSET:
|
||||
cmd_RSET();
|
||||
break;
|
||||
case commandHALT:
|
||||
cmd_HALT();
|
||||
break;
|
||||
case commandRatio:
|
||||
cmd_Ratio();
|
||||
break;
|
||||
case commandSens:
|
||||
cmd_Sens();
|
||||
break;
|
||||
case commandSTAT:
|
||||
cmd_STAT();
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
memset(packet, 0, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void TouchSend() {
|
||||
uint64_t TouchData = 0; //触摸数据包
|
||||
// 简单方法,从 mpr.touched() 一次读取 12个触摸点的按下状态,需要正确配置 mpr121 的各种参数值才能获取准确的状态
|
||||
TouchData = (TouchData | mprC.touched()) << 12;
|
||||
TouchData = (TouchData | mprB.touched()) << 12;
|
||||
TouchData = (TouchData | mprA.touched());
|
||||
|
||||
// 高级方法,读取每个触摸点的 baselineData 和 filteredData,可以单独设置敏感度过滤
|
||||
// for (uint8_t i = 0; i < 12; i++) {
|
||||
// bitWrite64(TouchData, i, CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20) > 27);//另外一种检测方法
|
||||
// Serial.print(CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20));
|
||||
// Serial.print(" ");
|
||||
// }
|
||||
// for (uint8_t i = 0; i < 12; i++) {
|
||||
// bitWrite64(TouchData, i+12, CLAMP(mprB.baselineData(i) - mprB.filteredData(i)+20) > 30);//另外一种检测方法
|
||||
//// Serial.print(CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20));
|
||||
//// Serial.print(" ");
|
||||
// }
|
||||
// for (uint8_t i = 0; i < 12; i++) {
|
||||
// bitWrite64(TouchData, i+24, CLAMP(mprC.baselineData(i) - mprC.filteredData(i)+20) > 30);//另外一种检测方法
|
||||
//// Serial.print(CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20));
|
||||
//// Serial.print(" ");
|
||||
// }
|
||||
//Serial.println("");
|
||||
SerialDevice.write((byte)'(');
|
||||
for (uint8_t r = 0; r < 7; r++) {
|
||||
SerialDevice.write((byte)TouchData & B11111);
|
||||
TouchData >>= 5;
|
||||
}
|
||||
SerialDevice.write((byte)')');
|
||||
}
|
0
Mai2TouchOK/高敏度低延迟可能串音版本.txt
Normal file
0
Mai2TouchOK/高敏度低延迟可能串音版本.txt
Normal file
234
README.md
Normal file
234
README.md
Normal file
@ -0,0 +1,234 @@
|
||||
# 自制省钱高性价比maimaiDX控制器$全!$解
|
||||
|
||||
## 第零部分 协议
|
||||
|
||||
### 对于请勿侵犯SEGA以及WAHLAP权益的声明
|
||||
本作仅适用于个人制作游玩,原则上不提倡也不反对制作后发售。若发售或由读者自己的行为造成不当影响和任何纠纷,本教程作者和本教程不负任何责任。请勿侵犯SEGA以及WAHLAP权益。若作者行为或是本教程产生了不良影响,我对我的行为表示抱歉并可修补甚至撤下本教程,希望大家的理解。
|
||||
当大家在展示自己手台效果的时候,不要发布不该发布的东西,让我们一起遵守。
|
||||
|
||||
### 对于协力者,贡献者的感谢
|
||||
|
||||
我的触摸代码部分几乎完全是mai2touch的项目搬来的,然后更改修复了一些mpr121配置上的问题,配置部分借鉴了Arduino-Chunithm-Controller的代码。读卡器使用的也是同作者的Arduino-Aime-Reader。在此对mai2touch,Arduino-Chunithm-Controller,Arduino-Aime-Reader和它们的作者表示衷心的感谢,如果没有mai2touch和Arduino-Chunithm-Controller以及对它们下了很多心血的作者,我的控制器将失去它最重要的灵魂。
|
||||
在此感谢[Sucareto](https://github.com/Sucareto)以及他的项目[Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader),[Arduino-Chunithm-Controller](https://github.com/Sucareto/Arduino-Chunithm-Controller)和[mai2Touch](https://github.com/Sucareto/Mai2Touch)!
|
||||
|
||||
传承开源精神,我将自用的程序开源,但是仅仅用于我手里的硬件测试成功,不同的走线,制作方法,使用的mpr配置等也不一样,不建议照搬。
|
||||
|
||||
### 对于本教程版权的声明
|
||||
|
||||
本教程是由Helloworld_Dk纯手打写出的,思路也是几乎完全自己想的。
|
||||
如果我能给大家的想法产生帮助,我感到非常荣幸,如果您觉得我的方案对您有帮助,希望可以在您的项目发布时,跟上一句"本方案的部分灵感来自Dk"或类似的话,我将不甚感激
|
||||
|
||||
## 第一部分 总览
|
||||
|
||||
本方案是使用导电膜裁切,漆包线引出的触摸部分为核心的低价maimai控制器制作方案。由于被~~逼到无奈~~很多也像制作maimai手台的玩家支持,而写了这样的一个教程。
|
||||
|
||||
### [方案效果展示](https://www.bilibili.com/video/BV1pe4y1m7pr/)
|
||||
### [使用32u4的延迟更新后的展示](https://www.bilibili.com/video/BV1PW4y1E7io/)
|
||||
|
||||
todo: 按键的相关制作教程
|
||||
stat: 延迟的问题已经被消除
|
||||
|
||||
## 第二部分 目录
|
||||
- 第零部分 协议
|
||||
- 对于请勿侵犯SEGA以及WAHLAP权益的声明
|
||||
- 对于协力者,贡献者的感谢
|
||||
- 对于本教程版权的声明
|
||||
- 第一部分 总览
|
||||
- 介绍
|
||||
- 方案效果展示
|
||||
- todo和stat
|
||||
- 第二部分 目录
|
||||
- 目录
|
||||
- 第三部分 触屏制作指导
|
||||
- 第四部分 读卡器个人思路分享
|
||||
- 第五部分 已删除
|
||||
- 第六部分 按键和灯光(未完成)
|
||||
## 第三部分 触屏制作指导
|
||||
**这位更是重量级**
|
||||
|
||||
整个制作是非常的省钱,非常的好用,像是铝箔贴的chuni控制器,纯手作省钱能用就行精神是这样的。
|
||||
|
||||
本教程与之前发布的[专栏](https://www.bilibili.com/read/cv19157015)相互照应,相互补充,建议一起阅读
|
||||
|
||||
```圣经
|
||||
做 手 台 不 试 试 瞎 搞 手 作 便 宜 省 钱 , 就 像 四 大 名 著 不 看 红 楼 梦 , 说 明 这 个 人 文 学 造 诣 和 自 我 修 养 不 足 , 他 理 解 不 了 这 种 内 在 的 阳 春 白 雪 的 高 雅 艺 术 , 他 只 能 看 到 外 表 的 辞 藻 堆 砌 , 参 不 透 其 中 深 奥 的 精 神 内 核 , 他 整 个 人 的 层 次 就 卡 在 这 里 了 , 只 能 度 过 一 个 相 对 失 败 的 人 生。
|
||||
```
|
||||
|
||||
**你需要的材料:**
|
||||
- 触摸部分
|
||||
- 尺寸合适的ito导电膜,一定要买带胶,除非你真的想好了胶怎么办。下面会有为什么要这么做的说明。
|
||||
- 一张较薄的亚克力板或者玻璃板,尺寸至少覆盖圆形屏幕区域。此处感觉玻璃容易碎,亚克力容易划花,大家自行斟酌。本人使用的一张比亚克力优秀的塑料板。
|
||||
- 较细的漆包线
|
||||
- 你超棒的手工能力
|
||||
- 透明胶带
|
||||
- 屏幕部分
|
||||
- 一块跟你触摸板相对应的合适大小的屏幕,本教程应该不适用于小于十寸的屏幕。
|
||||
- 程序和mcu
|
||||
- 本人使用的mai2touch项目,并对其进行修改,相关链接在教程开头协议部分。
|
||||
- Arduino或类似的开发板,我建议使用pro micro,不建议使用使用了ch340串口ic的板子。但是我使用pro micro被喷过和嘲讽过.....别人说它性能太差,可是我真的喜欢。
|
||||
|
||||
**制作过程详解**
|
||||
这部分在专栏讲的很详细,特别是图片详细。
|
||||
统共有以下步骤:
|
||||
### 1\. 打印对照纸
|
||||
说的玄乎,其实就是用一张A4纸或类似的纸,将触摸区块图片打印下来。尺寸要与你目标屏幕显示的大小完全对应。建议打印至少两张。
|
||||
|
||||
<img desc = "打印对照纸">
|
||||
|
||||
### 2\. 裁切
|
||||
把a4纸跟买到的触摸膜贴在一起固定好,然后根据a4纸,裁下每一片触摸区块
|
||||
注意一定要固定好哦,不然剪着剪着位移了剪除奇形怪状的区块可就难办了!
|
||||
|
||||
## 3\.粘贴
|
||||
|
||||
首先你不是打印了两张A4纸吗,一张被剪了,另一张好好的,请规划好位置之后,把A4纸打印面朝向亚克力板或玻璃板粘贴,在另一面应该可以透过亚克力板或者玻璃板,看到另一面清晰的打印的区块。用于之后粘贴位置的对应。
|
||||
|
||||
|
||||
导电膜是这样的结构:
|
||||
不导电面朝上,导电面朝下,依次是:
|
||||
|
||||
0. 一层保护膜
|
||||
1. (如果是带胶的才有)一层透明胶
|
||||
2. 聚酯离型膜,自此间隔,上面称为不导电面,下面称为导电面,不导电面有胶,导电面无胶
|
||||
3. ito导电涂层
|
||||
4. 一层保护膜
|
||||
|
||||
在**粘贴**这一步,我们需要完成的是
|
||||
|
||||
0. 亚克力或玻璃板
|
||||
1. (如果是带胶的自带,没带胶的会让你痛苦到怀疑人生)一层透明胶
|
||||
2. 聚酯离型膜
|
||||
3. ito导电涂层
|
||||
4. 一层保护膜
|
||||
|
||||
假设没有买带胶的膜,就自行点胶(透明的,支持粘贴塑料的,不会腐蚀塑料的,固化不回缩的,粘贴可以调整的)固定每片触摸块到屏幕上。
|
||||
在写这篇教程的时候,我自己搞的胶腐蚀了我的塑料板,导致A5区域透明性下降...**距今已过去十分钟,警钟敲烂**,所以千万别贪便宜买不带胶的!
|
||||
需要撕下不导电面的保护膜。不导电面朝向塑料板粘贴,**请勿将导电面贴到塑料板上**。
|
||||
如果是买的带胶的导电膜,不导电面恰好是带胶面,裁好了可以轻松粘在塑料板上。完全不用经历大力对抗胶水的那一步。
|
||||
~~唉,这个地方别省钱,要不让你感受人间痛苦,宛如晚清十大酷刑。~~
|
||||
|
||||
~~自己搞胶的痛苦,详见专栏图片。~~
|
||||
|
||||
## 4\.引线
|
||||
|
||||
在**引线**这一步,我们需要完成的是
|
||||
|
||||
0. 亚克力或玻璃板
|
||||
1. 一层透明胶
|
||||
2. 聚酯离型膜
|
||||
3. ito导电涂层
|
||||
4. 漆包线
|
||||
5. 单面带胶的透明胶带
|
||||
|
||||
|
||||
之前我说的是
|
||||
```
|
||||
要去漆包线的绝缘漆,
|
||||
撕掉导电面保护膜,
|
||||
用透明胶带初固定,
|
||||
尽力沿着区间缝隙走线,
|
||||
|
||||
评价是先走中心的c区,然后慢慢向外区块做,这个是中心思想,
|
||||
其次是按照从下到上 顺序操作的,先是最底下的区,56那些处理好,慢慢往上处理。
|
||||
这样在处理完一些之后,可以横着贴一张长长的透明胶带把已经完成的区固定好避免之后散掉。
|
||||
```
|
||||
依然可以参照,在此补充操作绝对步骤,引用我教别人的聊天记录
|
||||
```
|
||||
这样
|
||||
先把漆包线准备好,头上刮漆打圈
|
||||
把带胶不导电面贴好
|
||||
然后准备一段透明胶带
|
||||
然后把导电面保护膜解开
|
||||
放漆包线
|
||||
粘胶带
|
||||
一气呵成
|
||||
```
|
||||
这里有关ito的一个特性,是ito遇水,二氧化碳容易变质,影响导电性能和透明性。
|
||||
所以在放上漆包线后,应当尽快用一些方法将导电面全部覆盖隔绝空气。我使用的是透明胶带,虽然不是特别好看但是能用。
|
||||
|
||||
关于导线具体从区块到触摸板边缘的引出方法,详见b站专栏,非常详细!
|
||||
|
||||
```
|
||||
总的说就是先从底下的中间考虑,也就是看下图先处理底下中间红圈再处理绿圈再处理橙圈再贴一张透明胶带上去。再往上一步一步地处理整个触摸面板。
|
||||
|
||||
运用了贪心的思想,中间的区肯定是最需要往外走的,所以需要先考虑,从哪条缝走过去。而边上的很简单就可以引出去,可以在把难搞的安顿好之后再处理。从下往上一是因为可以做一块贴一整块透明胶带,其次是下面不会像上面一样被屏幕挡住无法从边上轻松走线。先把东西往下安顿可以减少后续上面的工作量。
|
||||
|
||||
要点:处理顺序、不要吝啬在圆外面的初固定胶带,周围挡起来游玩看不见,减少线乱飞
|
||||
```
|
||||
|
||||
## 4\.接线
|
||||
详见b站专栏,讲的足够详细,基本没有要补充的。
|
||||
```
|
||||
1.先把arduino跟mpr121的I2C连好。
|
||||
|
||||
2.根据程序确定哪个区接在哪个mpr121的哪个io,如果你的程序不知道是哪个io,把程序写到板子里面,用一根螺丝刀按在每个io上,看游戏测试汇报哪个区被按下。通常是连续的,比如A1到A8是一个mpr的0到7之类的,很好确定,这个是一种办法。另一种是根据你从触摸面板上接出的漆包线的位置,在程序里面规划好哪个接哪个合适不用绕,可以走线不像我一样乱糟糟。
|
||||
|
||||
3.走漆包线。面对从塑料板边缘引出的34根漆包线无从下手是吗?我感觉这样比较好:以横向中轴为开始的地方,从这里向上下处理。
|
||||
|
||||
因为两边的线很容易可以从边上引到中间的mpr121上,而偏上偏下的难搞要绕。所以从中间处理会方便很多。走线原则:从空闲地方走,尽量隔出空隙,不要横跨一张mpr121板子,上面不能直接 绕,绕最好从左右,下面也可以勉强绕一下。
|
||||
|
||||
之前留的漆包线建议足一些,不然这步容易踩坑:要绕一些地方焊接,就需要足够长的线。有时候线发现不够长,这时候如果你发现在透明胶带下走的路径对现在要走的地方不合适,觉得拽回来就可以了,不绕路了,够长了。但是小心!!你一拉那个漆包线,很可能把上面在触摸区域走的打好圈的线拽移位,到其他区或者圈没了。这会让你极其难办。你不得不拆下粘的很牢的透明胶带,把线重新拽回原位打圈放在该在的位置上。透明胶带这种东西撕下来粘第二次透明效果就会很差,所以千万不要乱拽漆包线,返工让你怀疑人生
|
||||
|
||||
但是遇到真的不够长怎么办呢,可以尝试用圆滑的焊接接上一段,做好绝缘应该没什么问题。
|
||||
|
||||
到这里,你的线接好了。
|
||||
|
||||
要点:确定好io对应区,写在之前打印过的A4纸上,对照着纸上面的区块位置接会方便很多。不要拽漆包线。
|
||||
```
|
||||
|
||||
## 5\.程序部分
|
||||
|
||||
我使用的是github上的开源项目mai2Touch。曾遇到过问题如下
|
||||
|
||||
QA1:对于328p编译失败,不支持的开发板:改改上面的宏定义即可。(不建议使用带ch340的328p板子... ~~感觉是延迟的来源,新买的板子还没到...不确定。~~ 就是延迟的来源,不用洗,我promicro已经到了,非常低延迟,爱来自32u4。这条QA仅限于你要用UNO/NANO/MICRO才可能会用到,但是本人非常不建议使用,因为延迟极大
|
||||
|
||||
QA2:Serial.write 歧义 编译失败:在write传入的参数前面强制类型转换为(byte)。如Serial.write('A');改为Serial.write((byte)'A');
|
||||
|
||||
QA3:触摸出现问题,莫名触发,串音,灵敏度错:~~我自己重写了mpr121配置部分代码然后就解决了,某论坛有配置详细教程,这就不发了。~~实际上是从Arduino-Chunithm-Controller搬来的寄存器设定代码并加以改动,我摊牌了。
|
||||
|
||||
## 6\.游戏连接部分
|
||||
|
||||
你好,不可能发游戏的,这里只提一下连接的一些问题
|
||||
|
||||
QA1:怎么连的:串口直连,按照github上的readme走。
|
||||
|
||||
QA2:怎么按下在闪,不是长按:github(截止到写这个专栏)里面教的写错了。**DummyTouchPanel=1应该是0**,1的话是开启了的mai程序自带的调试触摸,然后导致自己的设备和自带的调试对着干,一个说按了一个说没按,就开始闪。设置为0避免程序调试触摸影响。
|
||||
|
||||
QA3: 怎么感觉我的触摸没问题,但是程序里面好像跟无响应一样:~~神奇问题,你插上电脑之后先用ide传一遍程序进去就会好。用rts|dts小工具试过也不行,就是ide传程序可以,非常神奇。仅发生在我手上的ch340的arduino nano上,其他板子也许没问题。传过程序之后,只要不断电,reset arduino 不会影响。断电需要重传程序解决。~~ 听国际友人说好像是ch340在arduino上锁i2c什么的?我英语很差,初中水平,看不懂.....反正避免使用328p+ch340即可解决问题。非要用的话,每次重新上电需要重刷一遍程序。
|
||||
|
||||
~~ 其实我当时这么乱的接线我觉得我必定失败,一定串音,结果上测试程序告诉我静默跟没接一样的一点干扰都没有\(7\-11\),按下能上最高100多的数值\(40\-120\),我超,太美丽了,这必成功,我都不敢相信,但是真的可以!!乱搞万岁 ~~ 删除线挂了,给其它符号转义了也没用,不知道为什么。
|
||||
|
||||
~~至此,已成艺术品~~
|
||||
**至此,触摸部分硬件软件完成,撒花 *★,°*:.☆( ̄▽ ̄)/$:*.°★**
|
||||
|
||||
## 第四部分 读卡器个人思路分享
|
||||
|
||||
在最新一次发布的b站展示视频中,可以看见我的读卡器。他最亮眼的部分是均匀的光。其原理是使用了一块拆机的 **屏幕背光板** 进行光的一个导,视频中并非完成品,要做的更完善,需要使用大一点的背光板,配合侧照的灯,而不是我这粗制滥造的测试机的操作,不过对于全尺寸的灯加上手动侧照已经能达到如此不错的效果,等到完善之后效果应该不言而喻的非常不错。
|
||||
|
||||
目前我看到其他大佬们制作的读卡器,没有使用了本方案的,我觉得这个思路对于光的均匀度方面效果不错,于是就发出来供大家参考。
|
||||
|
||||
关于读卡器的程序
|
||||
使用的是Arduino-Aime-Reader项目。但是注意,这个项目并不原生支持328p。由于~~我家328p奇多~~读卡器并不需要极低的延迟,所以我考虑了使用~~我家奇多~~ 的arduino nano(328p+ch340)制作,因为成本低。在过程中遇到了一些问题并解决了,如下:
|
||||
QA1:程序无法通过编:需要改改宏,这个上面说过了。
|
||||
QA2:程序编译正常,readertest正常,手动发包疑似正常,就是游戏不可以:发现游戏发送初始化命令,发送dts/rts或相关内容的时候会让arduino重启(reset触发),显然不对劲,因为在重启过程中,游戏发包arduino不会给出回应。尝试短接rst与3v3强制禁止其重启,问题解决。
|
||||
```
|
||||
但是usb转串口可以重启arduino不是bug而是一个不错的功能,arduino在下载程序的时候需要重启才可以开始。电脑可以让arduino重启本身是为了方便下载程序而做出的美好设计,但是在此处影响了功能。
|
||||
如果直接短接会造成无法正常下载程序。我的解决方法是在rst跟3v3直接加一个开关,下载程序就断开,当读卡器的时候就闭合。
|
||||
这样也许会?对复位电路产生略微的短路,但是目前使用效果极佳,就先这样用了。
|
||||
```
|
||||
|
||||
## 第五部分 已删除
|
||||
|
||||
## 第六部分 按键和灯光
|
||||
|
||||
直接promicro做成键盘就完事,这个人人都会不用教网上一抓一大把。
|
||||
据说可以把灯光塞进跟按键同一个promicro,但是我没试过(
|
||||
在todo列表中
|
||||
待完成
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
------
|
||||
END SEL DOCUMENT BY HELLOWORLD_DK
|
Loading…
Reference in New Issue
Block a user