Перейти к содержанию
UID и номер карты: форматы, Wiegand и преобразование

UID и номер карты: форматы, Wiegand и преобразование

Почему UID считывателя не совпадает с номером на карте, как работают прямой и обратный порядок байтов, десятичные номера и Wiegand, и как выполнить преобразование вручную или в ODRFID и ODNFC.

UID, номер на корпусе карты и номер в СКУД — не обязательно одно и то же. Считыватель получает последовательность байтов или поля протокола, а затем прошивка, конфигуратор или прикладная программа выбирает, как их показать. Поэтому одна карта может одновременно иметь несколько правильных номеров.

Почему напечатанный номер отличается

На карту могут нанести:

  • UID в HEX, слитно или с разделителями;
  • тот же UID с обратным порядком байтов;
  • UID как одно десятичное число;
  • пару Facility Code + Card Number для конкретного формата Wiegand;
  • только Card Number без Facility Code;
  • номер, назначенный производителем, эмитентом или базой СКУД и вообще не вычисляемый из UID.

Надпись сама по себе не определяет алгоритм. Две одинаково выглядящие карты могут быть выпущены с разными правилами нумерации. Для проверки нужны как минимум напечатанный номер и исходные байты, прочитанные без преобразования.

Что именно читает устройство

НосительИсходный идентификаторЧто важно учитывать
MIFARE, NTAG и другие ISO/IEC 14443UID длиной обычно 4, 7 или 10 байт7- и 10-байтовый UID нельзя без потерь поместить в Wiegand 26
EM-Marine EM41005 байт идентификаторана карте часто печатают последние байты как десятичное число или пару полей
HID Proxзакодированный профиль с полями, например H10301Facility Code и Card Number уже являются частью выбранного профиля
UHF EPC Gen2EPC, а отдельно может быть TIDEPC и TID — не NFC UID; правило печати задаёт поставщик метки
Смартфон или WalletUID, PAN или токен — в зависимости от сценариязначение может отличаться от номера пластиковой карты и меняться

UID удобен как идентификатор, но не является паролем или криптографическим доказательством подлинности. Ограничения смартфонов и мобильных кошельков разобраны в статье «Телефон вместо пропуска».

Один UID в разных форматах

Возьмём четырёхбайтовый UID 7A 40 3A B9.

ПредставлениеПравилоРезультат
HEX, прямой порядокбайты выводятся в порядке чтения7A403AB9
HEX с разделителямименяется только оформление7A:40:3A:B9
HEX, обратный порядокпорядок байтов разворачиваетсяB93A407A
Десятичное big-endian0x7A403AB9 как одно число2051029689
Десятичное little-endian0xB93A407A как одно число3107602554
Десятичные байтыкаждый байт переводится отдельно122 64 58 185
Wiegand 26, поляFC = 0x3A, CN = 0x407A058,16506
Wiegand 26, данные одним числом0x3A407A без битов паритета3817594

Схема преобразования UID 7A403AB9 в обратный десятичный номер и поля Wiegand 26

Ведущие нули являются частью отображаемого формата: 058,16506 и 58,16506 содержат те же числовые поля, но могут не совпасть при текстовом импорте. Разделитель — запятая или точка — также относится только к текстовому представлению.

Длинные UID

Для UID 04A1B2C3D4E5F6 прямое десятичное представление равно 1303689068602870, а после разворота байтов — 69495546249912580. Обычный 32-битный тип данных для таких значений мал. В JavaScript требуется BigInt, а в контроллере с ограниченной арифметикой безопаснее хранить UID как байты или HEX-строку.

Если старая СКУД принимает только Wiegand 26, длинный UID придётся усечь, свернуть по согласованному алгоритму или сопоставить с отдельным номером в базе. Любой такой вариант может создать совпадения между разными UID.

Wiegand: интерфейс и формат данных

Словом Wiegand называют сразу две разные вещи:

  1. электрический интерфейс с линиями D0 и D1;
  2. битовый профиль передаваемого номера.

Например, распространённый H10301 содержит 26 бит:

P | Facility Code: 8 бит | Card Number: 16 бит | P

Крайние биты — контроль чётности, а полезные данные занимают 24 бита. Запись 058,16506 показывает два полезных поля. По проводам передаётся битовый кадр без запятой, точки и десятичных символов.

Кроме Wiegand 26 применяются 34-, 35-, 37-битные и пользовательские профили. У них отличаются ширина и положение полей, правила чётности, а иногда Facility Code отсутствует. Совпадение длины кадра ещё не гарантирует одинаковую интерпретацию: например, разные 37-битные профили могут делить данные на поля по-разному.

Пример профиляВсего битПолезные поля
H1030126Facility Code 8 бит + Card Number 16 бит
H1030634Facility Code 16 бит + Card Number 16 бит
Corporate 100035Company bit 1 бит + Facility Code 12 бит + Card Number 20 бит
H1030237Card Number 35 бит, без Facility Code
H1030437Facility Code 16 бит + Card Number 19 бит

H10302 и H10304 имеют одинаковую длину. Считывателю или контроллеру нужно заранее сообщить, какой именно 37-битный профиль используется.

Проверка совместимости со СКУД

До массовой регистрации карт зафиксируйте:

  1. длину кадра в битах;
  2. ширину и положение Facility Code и Card Number;
  3. какие байты UID используются и какие отбрасываются;
  4. порядок байтов и порядок битов;
  5. правила чётности;
  6. требуемые ведущие нули и текстовый разделитель при импорте;
  7. поведение для 7- и 10-байтовых UID.

Проверьте несколько реальных карт, включая номера с нулями в начале полей. Если контроллер уже хранит карты, сначала получите его эталонный результат и подберите преобразование считывателя под него.

Преобразование вручную

Для примера 7A403AB9:

  1. Разбейте UID на байты: 7A 40 3A B9.
  2. Для обратного порядка переставьте байты целиком, не отдельные символы: B9 3A 40 7A.
  3. Для десятичного little-endian переведите B93A407A из HEX: получится 3107602554.
  4. Для принятого в этом примере отображения Wiegand 26 возьмите 3A 40 7A: 0x3A = 58, 0x407A = 16506.
  5. Дополните поля нулями до 058,16506.

Преобразования вручную через Google Таблицы и Excel

Формулы ниже рассчитаны ровно на восемь HEX-символов в A1. В русской локали используется ;; если таблица ожидает запятые между аргументами, замените разделители функций.

РезультатФормула
Прямое десятичное число=HEX2DEC(A1)
HEX с обратным порядком байтов=MID(A1;7;2)&MID(A1;5;2)&MID(A1;3;2)&MID(A1;1;2)
Десятичное little-endian=HEX2DEC(MID(A1;7;2)&MID(A1;5;2)&MID(A1;3;2)&MID(A1;1;2))
Facility Code=HEX2DEC(MID(A1;5;2))
Card Number=HEX2DEC(MID(A1;3;2)&MID(A1;1;2))
058,16506=TEXT(HEX2DEC(MID(A1;5;2));"000")&","&TEXT(HEX2DEC(MID(A1;3;2)&MID(A1;1;2));"00000")
Данные Wiegand 26 одним числом=HEX2DEC(MID(A1;5;2)&MID(A1;3;2)&MID(A1;1;2))

UID, десятичный номер и поля Wiegand 26 в Google Таблицах

Автоматически: строка форматирования

ODRFID и программируемые ODNFC могут выполнить распространённые преобразования до передачи результата. Наличие конкретного кода зависит от модели и версии прошивки.

Для UID 7A403AB9 используются такие строки:

СтрокаРезультат
HU*7A403AB9
HU~B93A407A
Ur3107602554
Uc058,16506
Ud058.16506
HU2:03A407A

Uc и Ud рассчитаны на четырёхбайтовый UID и реализуют именно показанное выше деление на 8-битный Facility Code и 16-битный Card Number. Для другой длины UID или другого профиля используйте собственный код на ODNFC.

Для меток 125 кГц предусмотрены отдельные сокращения: e выводит Card Number HID Prox или компактный десятичный номер EM-Marine, E — поля Facility Code.Card Number, а D — объединённое десятичное значение профиля HID или расширенный десятичный номер EM-Marine. Семантика этих кодов зависит от протокола метки, модели и прошивки, поэтому после настройки проверьте результат на нескольких известных картах.

Строку можно задать в ODRFIDConfig, веб-интерфейсе, настройке rfid-format или AT-командой:

AT+F=Uc
AT+P

Полный синтаксис, экранирование символов и чтение блоков описаны в справочнике строки форматирования.

Lua на ODNFC

Встроенный модуль может сразу вернуть нужный вариант:

local uid_hex = mfrc522.scan("HU*")
local uid_dec = mfrc522.scan("Ur")
local wiegand = mfrc522.scan("Uc")

Для собственного профиля запросите байты UID и соберите поля в программе:

local function format_w26(...)
    local b = {...}
    if #b ~= 4 then
        return nil, "для этого правила нужен UID из 4 байт"
    end

    local facility = b[3]
    local card = b[2] * 256 + b[1]
    return string.format("%03d,%05d", facility, card)
end

local result
mfrc522.scan(function(...)
    result = format_w26(...)
end)

В рабочей программе лучше передавать результат из callback сразу в Modbus, OSDP или сетевой обработчик, а не полагаться на глобальную переменную.

MicroPython или серверная обработка

Если UID уже получен как HEX-строка:

uid = bytes.fromhex("7A403AB9")

direct_hex = uid.hex().upper()
reverse_hex = uid[::-1].hex().upper()
direct_decimal = int.from_bytes(uid, "big")
reverse_decimal = int.from_bytes(uid, "little")

payload = uid[2::-1]       # 3A 40 7A — правило именно этого примера
facility = payload[0]
card_number = int.from_bytes(payload[1:], "big")
wiegand_text = f"{facility:03d},{card_number:05d}"

В ODNFC на MicroPython строка из настройки передаётся в RFID.read(fmt=...); нестандартное преобразование можно выполнить после чтения. Для обмена между системами полезно передавать одновременно исходный UID и вычисленный номер: это упрощает диагностику и смену формата.

Какой формат выбрать

  • Для новой системы храните исходный UID или EPC без потерь и отдельно — правило отображения.
  • Для существующей СКУД повторите её длину Wiegand, поля, порядок и чётность.
  • Для HID-клавиатуры выберите строку, которую ожидает Excel, 1С или форма.
  • Для Modbus, OSDP и сетевого API передавайте сырые байты, если преобразование удобнее выполнять централизованно.
  • Не смешивайте в одном поле NFC UID, PAN, UHF EPC и произвольный номер из базы без явного указания типа идентификатора.

Если номер на карте не получается ни одним известным преобразованием, это, скорее всего, отдельный номер эмитента. Его нужно импортировать как соответствие исходный идентификатор → напечатанный номер, а не пытаться восстановить неизвестную формулу.