RFID Протокол записи¶
Концепция¶
Backend формирует готовый бинарный blob, MCU записывает на метку по универсальному алгоритму.
Архитектура¶
Уровень A: Содержимое blob¶
Backend выбирает формат по технологии: - NDEF Type 2 (NTAG/Ultralight) - TLV с page 4 - NDEF Type 5 (ISO15693) - CC в block 0 - Vendor-format (MIFARE Classic)
Уровень B: Параметры записи¶
Backend передает инструкции:
- tech: тип технологии
- chunkSize: размер записи (4/8/16 байт)
- startAddr: стартовый адрес
- needsAuth: требуется аутентификация
- auth: ключи (только для MIFARE Classic)
Технологии¶
| Параметр | Type 2 (NTAG) | MIFARE Classic | ISO15693 |
|---|---|---|---|
| Чанк | 4 байта (страница) | 16 байт (блок) | 4 байта (SLIX2) |
| Auth | Нет | Да, посекторно | Нет |
| NDEF | Type 2 | Не поддерживает | Type 5 |
| Ридер | RC522 | RC522 | PN5180 |
Алгоритм записи¶
void writeTag(const WritePacket& packet) {
uint8_t blob[MAX_SIZE];
size_t len = base64_decode(packet.blobBase64, blob);
switch (packet.tech) {
case TECH_TYPE2_NTAG:
writeType2(blob, len, packet.startAddr);
break;
case TECH_MIFARE_CLASSIC:
writeMifareClassic(blob, len, packet.auth.keys);
break;
case TECH_ISO15693:
writeISO15693(blob, len, packet.tagInfo.blockSize, packet.startAddr);
break;
}
}
Формат WritePacket¶
interface WritePacket {
tech: 'type2_ntag' | 'mifare_classic_1k' | 'nfcv_iso15693';
write: {
chunkSize: number;
startAddr: number;
totalSize: number;
};
auth?: {
keyType: 'A' | 'B';
keys: { [sector: string]: string };
};
tagInfo?: {
model: string;
blockSize: number;
totalBlocks: number;
};
format: 'ndef_type2' | 'ndef_type5' | 'raw' | 'openprinttag';
blobBase64: string;
}
Примеры¶
NTAG215¶
{
"tech": "type2_ntag",
"write": { "chunkSize": 4, "startAddr": 4, "totalSize": 492 },
"format": "ndef_type2",
"blobBase64": "AwAA1QEBVRgBaHR0cHM6Ly9pZHJ5ZXI..."
}
ISO15693 (SLIX2)¶
{
"tech": "nfcv_iso15693",
"tagInfo": { "model": "ICODE_SLIX2", "blockSize": 4, "totalBlocks": 80 },
"write": { "chunkSize": 4, "startAddr": 0, "totalSize": 316 },
"format": "ndef_type5",
"blobBase64": "4UAAQAMADVEBVRgBaHR0cHM6Ly9pZHJ5ZXI..."
}
Примечание:
- для ICODE SLIX2 в проекте используется геометрия 80 блоков по 4 байта;
- последний блок зарезервирован под системный счётчик, поэтому полезная ёмкость для данных составляет 79 * 4 = 316 байт;
- startAddr = 0 означает полный бинарный образ, включающий Type 5 CC в первом пользовательском блоке.
Безопасность¶
MIFARE Classic: Ключи хранятся только на MCU, Backend передает номера секторов без ключей.
Workflow¶
- MCU определяет тег → отправляет тип Backend
- Backend отвечает с возможностями
- Пользователь выбирает катушку для записи
- Backend формирует WritePacket
- MCU записывает и подтверждает
Ограничения¶
- Фрагментированные кадры не интегрированы в MCU
- MQTT команда
write_rfidне реализована - Результаты
verifyещё не вынесены в отдельные backend/result-коды, хотя сама проверка чтением после записи в прошивке уже есть