# Настройка декодирования для Mifare (подробно)

1\. У тебя есть читалка (допустим z-2) и читалка турникета (matrix)  
2\. Главная задача это привести треки получаемые со считалок в один единый вид (в 10 формате)  
3\. Если  
3.1 Mifare  
3.1.1 Скачиваешь утилиту Putty  
3.1.2 Подключаешься через Putty к читалке  
3.1.3 Сканируешь карту и получаешь трек **Mifare\[A1B2C3D4\] (какая то номерная последовательность, которая совершенно не интересна нам) &lt;терминальные символы&gt;**  
3.1.4 Открываешь version.txt из каталогов TCPCardReader и decodercards (лежит в сборке в UTILS)  
3.1.5<span style="text-decoration: line-through;"> <del>Начинаешь читать и разбираться какие параметры нужны</del></span>  
3.1.6 Итак, сперва, чтобы настроить декодирование в TCPCardRead нам нужно отделить искомую последовательность от остальной информации. В данном случае необходимо вытащить UID из трека Mifare\[**A1B2C3D4**\] (какая то номерная последовательность, которая совершенно не интересна нам) &lt;терминальные символы&gt; **(выделено жирным, без скобок !)**.  
3.1.7 Открываем TcpCardReader.ini удаляем от туда секцию \[TCPCARDREADER\] (если есть (мы её не используем))  
3.1.8 Смотрим секции типа \[READER1\], \[READER2\], ... \[READERN\] - эти секции отвечаю за каждую свою подключённую читалку. Если нам нужна 1 читалка, то делаем секцию \[READER1\], если две, то записываем секцию \[READER2\] и т.д.  
3.1.9 Итак, настроим, например, только 1 считыватель. Смотрим секцию \[READER1\]

```
[READER1]
COMPORT=9
COMPORTPARAMS=baud=4800 data=8 parity=N stop=1
;Параметр Prefix задаёт строку, которая передаётся клиентам перед первым прочтенным символом
Prefix=
;Параметр Postfix задаёт строку, которая передаётся клиентам после последнего прочтенного символа
Postfix=

;Использовать decodecards.dll
useDecodeCards=0
StartTermChars=;
FinishTermChars=?#13;#10;#0;

;Файл логирования треков
TrackLogFile=
ConvertTrackLog=0
IncludeTypeStartTermChar=0
IncludeStartTermChar=0
NeedCheckAndReopenCom=1

```

3.1.10 Смотрим параметры из version.txt ( например, через NotePad++ )

{  
**COMPORT=9** - номер порта берется из диспетчера устройств. (диспетчер устройств -&gt; порты)  
**COMPORTPARAMS=baud=4800 data=8 parity=N stop=1** (параметры подключения) практически некогда не меняется (берется из свойств порта. см. диспетчер устройств)  
}  
;Параметр Prefix задаёт строку, которая передаётся клиентам перед первым прочтенным символом  
**Prefix=**

<p class="callout info">(строка №7 из version.txt) (";Параметр Prefix задаёт строку, которая передаётся клиентам перед первым прочтенным символом") Это означает, что передаваемый трек клиентам будет начинаться с установленного префикса. Например, если предположим, что декодирование настроено, то пусть наш трек выглядит так 1200. Мы хотим передавать трек с префиксом ;, то устанавливаем в параметр Prefix=; При передаче трека клиентам (abonementmanager, connecter, ...) передастся трек ;1200 . Если мы хотим передать трек с префиксом mrgreen, то ставим в параметрах Prefix=mrgreen. Соответственно при передаче трека клиентам, они получат mrgree1200</p>

  
;Параметр Postfix задаёт строку, которая передаётся клиентам после последнего прочтенного символа  
**Postfix=**

<p class="callout info">(строка №9 из version.txt) (";Параметр Postfix задаёт строку, которая передаётся клиентам после последнего прочтенного символа") По аналогии с суффиксом. Это означает, что передаваемый трек клиентам, оканчивается на установленный суффикс. Например, хотим передать суффикс ?, то Postfix=?. Клиенты получат трек 1200?. Если хотим передать суффикс `?#, то ставим Postfix=`?#. Клиенты получат трек 1200@?#.  
Таким образом, если установлены параметры Prefix=; и Postfix=?, то клиенты получат трек ;1200?</p>

<span style="text-decoration: underline;">**;Использовать decodecards.dll**</span>  
**useDecodeCards=0**

<p class="callout info">(строка №27 из version.txt) использовать= 1 - не использовать=0 decodecards.dll для извлечения номера. По умолчанию 0 - не использовать.</p>

**StartTermChars=;**

<p class="callout info">(строка №28 из version.txt) "Стартовые символы. Используются, если useDecodeCards=1" Стартовые символы или управляющие. Это символ(ы), с которого идет наш необработанный трек, передаваемый в decodercards.</p>

  
**FinishTermChars=?#13;#10;#0;**

<p class="callout info">(строка №29 из version.txt) Терминальные символы. Используются, если useDecodeCards=1. Это символ(ы), с которого идет наш не обротанный трек, передаваемый в decodercards.</p>

Т.е.  
Допустим Трек **Mifare\[A1B2C3D4\] (какая то номерная последовательность, которая совершенно не интересна нам) &lt;терминальные символы&gt;**

<p class="callout info">(**терминальный символ зависит от прошивки/настройки устройства**, он передается вместе с данными, **как правило это перевод на новую строку и возврат каретки** и -<span style="text-decoration: underline;"> №10 и №13 символы таблицы ASCII</span> [https://ru.wikipedia.org/wiki/ASCII](https://ru.wikipedia.org/wiki/ASCII) ; получаемая последовательность со считывателя в TPCCardReader или Putty выглядит наподобие Mifare\[A1B2C3D4\] (....) &lt;LF&gt;&lt;CR&gt;). </p>

Если сделаем **StartTermChars=**i и **FinishTermChars=?#13;#10;#0;** то будет следующее:  
1\. В треке находиться начальный символ, указанный в **StartTermChars**, это **i**. В нашем случае M **i** fare\[A1B2C3D4\] (....) &lt;LF&gt;&lt;CR&gt;  
2\. Затем ищется окончание (последний символ), указанные в **FinishTermChars** (можно указывать несколько подряд).  
Т.е. смотрим на Mifare\[A1B2C3D4\] (....) &lt;LF&gt;&lt;CR&gt;,  
<span style="text-decoration: underline;">есть ли в данном треке символ "?" - нету</span>  
<span style="text-decoration: underline;">есть ли символ #13;</span> (синтаксис 13 элемента в таблице в TCPCardReader - это &lt;CR&gt; возврат каретки), есть Mifare\[A1B2C3D4\] (....) &lt;LF&gt; **&lt;CR&gt;**  
Ага, <span style="text-decoration: underline;">**последовательность найдена**</span> и <span style="text-decoration: underline;">**результат будет**</span> : **fare\[A1B2C3D4\] (....) &lt;LF&gt;** и **он уже передается на обработку в decodercards.dll**

;Файл логирования треков  
TrackLogFile=  
ConvertTrackLog=0  
(строка №107 из version.txt)

> Если TrackLogFile определен, то используется дополнительный параметр ConvertTrackLog.  
> Он определяет, каким образом логировать невизуальные символы. По умолчанию ConvertTrackLog=0 (не конвертировать).  
> Если ConvertTrackLog=1, то невизуальные символы конвертируются в их код.

**IncludeTypeStartTermChar=0** - (строка №126 из version.txt)

> 1.1. IncludeTypeStartTermChar - тип обработки стартового символа  
> Имеет смысл, если useDecodeCards=1, IncludeStartTermChar=1 и UseOriginalTrack=0  
> Если IncludeTypeStartTermChar=0 (по умолчанию), то стартовый символ НЕ передается в decodecards, а подставляется перед истинным номером как дополнительный префикс  
> Если IncludeTypeStartTermChar=1 , то стартовый символ передается в decodecards и участвует в извлечении истинного номера

Обычно используем по умолчанию

**NeedCheckAndReopenCom=1** - (строка №135 из version.txt)

> Если NeedCheckAndReopenCom=1 (по умолчанию), то постоянно контролируется состояние соединения. Если связь потеряна, то происходит попытка переподключиться.  
> NeedCheckAndReopenCom=0 можно устанавливать, если устройство подключается не к USB, а к COM-порту.

Оставляем 1.  
3.1.11 <span style="text-decoration: underline;">Смотря пункт 3.1.10</span>, составляем следующую конфигурацию в секции **\[READER1\]**

```
COMPORT=9
COMPORTPARAMS=baud=4800 data=8 parity=N stop=1
;Параметр Prefix задаёт строку, которая передаётся клиентам перед первым прочтенным символом
Prefix=;
;Параметр Postfix задаёт строку, которая передаётся клиентам после последнего прочтенного символа
Postfix=?

;Использовать decodecards.dll
useDecodeCards=1
StartTermChars=i
FinishTermChars=?#13;#10;#0;

```

3.1.12 Итак, получили на входе в decodercards.dll трек на обработку **fare\[A1B2C3D4\] (....) &lt;LF&gt;**  
3.1.13 Разбираемся с декодированием. Открываем ini из сборки и видим

```
[frf]
fsUnit=fsdecodecard.upas

[general]
usemask=1
TrackResultLog=

[mask]
  card = 05015005*
  card2= 778=12345678=*
  cardfile=file://cards.txt

[cards]
  CardPrefix   = 05015005
;                 05015005280507210
  CardPrefix   = 750=
  CardPrefix   = 778=999999999=
  CardPrefix   = 778=123456789=
  StaffCardPrefix        =  778=87121234=
  StaffCardPrefix        = 778=201050001
  RegularCardPrefix = 778=444444444=
  PDSCardPrefix   = 811q

[cards.cardREPLACECARDNO]
  ExcludedPrefix=
  code=2
  CardDecodeType = REPLACECARDNO
  NewCardNo = 5678956

[cards.ARRAYOFBYTES]
  CardDecodeType = MASK
  mask=*cccc*
  bitmask=$7FFFFFFF
  MaskType=ARRAYOFBYTES
  code=2

[cards.Card2]
ExcludedPrefix=778=12345678=
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=2

;  CardDecodeType = LAST8
;  CardDecodeType = LAST9

;CardDecodeType = MASK
mask=hhhhhhhh*
bitmask=$7FFFFFFF

[cards.Card]
ExcludedPrefix=05015005
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=2

;  CardDecodeType = LAST8
;  CardDecodeType = LAST9

CardDecodeType = MASK
mask=ddd
;mask=hhhhhhhh*
bitmask=$FFFFFFFF

DecodeTypeEx = 0

[cards.RegularCard]
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=22

[cards.StaffCard]
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=21

[cards.PDSCard]
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=24
```

3.1.14 Разберем по секциям

```
[frf]
fsUnit=fsdecodecard.upas 

```

  
Эта секция отвечает подключение файла со скриптом (FastScript). Можно написать свой алгоритм для обработки трека.

```
[general]
usemask=1
TrackResultLog=

```

  
TrackResultLog= - имя файла, в котором будет результат обработки трека. (если надо делаем, обычно убираем)

**usemask=1**

> (version.txt строка 41)
> 
> Если usemask=1, то секция \[cards\] игнорируется  
> Если usemask=1, тогда при декодировании проверяется, какой маске соответствует считанный трек.  
> После этого происходит обращение к секции \[cards.ИМЯ МАСКИ\]

Ставим единичку и создаем секцию \[mask\] (если нет), в ней прописываем  
**card\_mi (произвольное имя) = (маска, по которой смотрим в какую секцию отправить на обработку трек)**  
В наем примере сделаем так:

<p class="callout info">card\_mi = fare\* (fare\* берется из трека fare\[A1B2C3D4\] (....) &lt;LF&gt;, \* - любой символ)</p>

Таким образом, **все треки, которые содержат <span style="text-decoration: underline;">fare</span> будут определяться и направляться на обработку в секцию <span style="text-decoration: underline;">card\_mi</span>**

**Также в этом случае необходимо создать секцию \[cards.card\_mi\], если её нет !**

В этой секции могу содержаться различные параметры (см. version.txt), но рассмотрим под наш случай.  
Нужно будет для обработки трека полученного **fare\[A1B2C3D4\] (....) &lt;LF&gt;** использовать следующие параметры: **ExcludedPrefix**, **code**, **CardDecodeType**, **mask**.

**ExcludedPrefix-Отрезаем от трека префикс.**  
Для того, чтобы корректно обработать наш трек fare\[**A1B2C3D4**\] (....) &lt;LF&gt; , необходимо **удалить fare\[**.  
Тогда необходимо прописать в параметре **ExcludedPrefix** следующее: **ExcludedPrefix=fare\[**  
Таким образом, мы получим внутри decodercards следующую последовательность трека **A1B2C3D4**\] (....) &lt;LF&gt;, где жирным указано интересующая нас последовательность в шестнадцатеричной системе.

Далее используется параметр **CardDecodeType - этот параметр определяет алгоритм декодирования**. [Существуют несколько вариантов](https://docs.shelter.ru/books/rabota-so-schityvatelyami/page/algoritmy-dekodirovaniya), например, <span style="text-decoration: underline;">LAST8, LAST9, MASK, FastScript и т.п.</span>  
**В нашем случае** мы используем **MASK** (накладываем маску и сравниваем с нашим треком) **CardDecodeType = MASK**  
<span style="text-decoration: underline;">**далее необходимо добавить параметр mask**</span>, который собственно, и определяет её.

> Из version.txt строка 32 описание следующее
> 
> mask=\*\*hh\* - взять 3-й и 4-й символ как цифры в шестнадцатеричном формате  
> или  
> mask=\*\*dd\* - взять 3-й и 4-й символ как цифры в десятичном формате

Поскольку нам из трека **A1B2C3D4** \] (....) &lt;LF&gt; интересна лишь последовательность A1B2C3D4, то наша маска выглядит следующим образом: **mask = hhhhhhhh**. Т.е. берем символы с 1 по 8 в шестнадцатеричном формате и <span style="text-decoration: underline;">преобразуем в конечный вариант в десятичный формат (DEC)</span>.

Остается для обработки добавить лишь параметр **code** - он отвечает за тип карты.  
code=2 (*фичи с ним на обучении только, либо сами*)

На выходе при треке **A1B2C3D4** <span style="text-decoration: underline;">**<ins>должны получить</ins>**</span> **2712847316**

3.1.15 Таким образом **получаем следующую конфигурацию decodercards.ini при TCPCardReader**

```
[frf]
fsUnit=fsdecodecard.upas

[general]
usemask=1

[mask]
  card_mi = fare*

[cards.card_mi]
ExcludedPrefix=fare[
code=2
CardDecodeType = MASK
mask=hhhhhhhh
```

3.1.16 Можно проверить правильность настроек **с помощью теста** в **TCPCardReader**. В поле слева от кнопки тест, <span style="text-decoration: underline;">**вводиться трек, который должен передаться в decodercards.dll**</span>

  
![](http://tracker.shelter.ru/attachments/download/808674/1.png)[![image-1632989091163.png](https://docs.shelter.ru/uploads/images/gallery/2021-09/scaled-1680-/image-1632989091163.png)](https://docs.shelter.ru/uploads/images/gallery/2021-09/image-1632989091163.png)

<span style="text-decoration: underline;">**В отображение вы должны получить последовательность отправки символов клиентам (трек).** </span>

<p class="callout danger"><span style="text-decoration: underline;">**Если вместо этого получаете :**   
**CHR OUT&gt; ;**  
**CHR OUT&gt; 0**  
**CHR OUT&gt; ?**  
**Вы <u>неправильно</u> настроили декодирования - повторяете изучение материала с 1 пункта** </span></p>

3.1.16 Можно также убедиться по логам decodercards, при использовании декодировании в логах TCPCardReader можно увидеть только информацию отправляемую клиентам.

**Лог правильно настроенного TCPCardReader**:

```
22.09.2021 18:05:35 581059359 2C74> CALL extractcardnoexp_int64: track=fare[F2D1BF1F] 191,53746 1K (0004,08) ; term0= , term1= 
22.09.2021 18:05:35 581059359 2C74> CALL extractcardnoex: track=fare[F2D1BF1F] 191,53746 1K (0004,08) ; term0= , term1= 
22.09.2021 18:05:35 581059359 2C74> UseMask2: UseMask=1
22.09.2021 18:05:35 581059359 2C74> CALL extractcardnoex2: track=fare[F2D1BF1F] 191,53746 1K (0004,08) ; term0= , term1= 
22.09.2021 18:05:35 581059375 2C74> EXIT extractcardnoex2: result=4073832223 , cardcode=2 , ExtractWithoutPrefix2=F2D1BF1F] 191,53746 1K (0004,08), ci=card_mi 
22.09.2021 18:05:35 581059375 2C74> EXIT extractcardnoexp_int64: result=4073832223 , cardcode=2 

```

<p class="callout success">CALL extractcardnoexp\_int64: track=fare\[F2D1BF1F\] 191,53746 1K (0004,08) ; term0= , term1= | **- прилетел трек**</p>

<p class="callout success">EXIT extractcardnoex2: result=4073832223 , cardcode=2 , ExtractWithoutPrefix2=F2D1BF1F\] 191,53746 1K (0004,08), ci=card\_mi | **ci - имя секции, по которой трек обрабатывается;**</p>

<p class="callout success">ExtractWithoutPrefix2=F2D1BF1F\] 191,53746 1K (0004,08) - **результат после исключения из трека префикса,** | result=4073832223 -**результат декодирования**  
<span style="text-decoration: underline;">**EXIT extractcardnoexp\_int64: result=4073832223 , cardcode=2**</span> | **результат на выходе из decodercards.dll !!!**</p>

3.1.17 **После правильного настроенного TCPCardReader**, **необходимо настроить decodercards.ini при abonementmanager или при коннекторе, или при gkhostconnect.**  
Рассмотрим простой и стандартный вариант- это Abonementmanager  
3.1.18 Открываем decodercards.ini и видим

```
[frf]
fsUnit=fsdecodecard.upas

[general]
usemask=1
TrackResultLog=

[mask]
  card = 05015005*
  card2= 778=12345678=*
  cardfile=file://cards.txt

[cards]
  CardPrefix   = 05015005
;                 05015005280507210
  CardPrefix   = 750=
  CardPrefix   = 778=999999999=
  CardPrefix   = 778=123456789=
  StaffCardPrefix        =  778=87121234=
  StaffCardPrefix        = 778=201050001
  RegularCardPrefix = 778=444444444=
  PDSCardPrefix   = 811q

[cards.cardREPLACECARDNO]
  ExcludedPrefix=
  code=2
  CardDecodeType = REPLACECARDNO
  NewCardNo = 5678956

[cards.ARRAYOFBYTES]
  CardDecodeType = MASK
  mask=*cccc*
  bitmask=$7FFFFFFF
  MaskType=ARRAYOFBYTES
  code=2

[cards.Card2]
ExcludedPrefix=778=12345678=
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=2

;  CardDecodeType = LAST8
;  CardDecodeType = LAST9

;CardDecodeType = MASK
mask=hhhhhhhh*
bitmask=$7FFFFFFF

[cards.Card]
ExcludedPrefix=05015005
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=2

;  CardDecodeType = LAST8
;  CardDecodeType = LAST9

CardDecodeType = MASK
mask=ddd
;mask=hhhhhhhh*
bitmask=$FFFFFFFF

DecodeTypeEx = 0

[cards.RegularCard]
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=22

[cards.StaffCard]
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=21

[cards.PDSCard]
;  CardDecodeType = ANGSTREMCARD
;  CardDecodeType = ANGSTREMBRASLET
code=24

```

3.1.18 Приводим к этому виду, удалив и почистив почти все

```
[general]
usemask=1

[mask]
card_all = *

[cards.card_all]
code=2

[cards.Card]
code=2

[cards.RegularCard]
code=22

[cards.StaffCard]
code=21

[cards.PDSCard]
code=24

```

Подробнее

```
[mask]
card_all = *

```

  
Как и по аналогии с TCPCardReader делаем настройку по маске.  
**card\_all = \* | \* - все получаемые треки**. Поскольку abonementmanager подключается к TCPCardRead, на стороне которого происходят все преобразования треков, получаемых со считывателей, в абонемент manager прилетает TCP <span style="text-decoration: underline;">**только трек в десятичном формате**</span>. Т.е. исходя из выше обработанного <span style="text-decoration: underline;">к нам прилетает</span> **2712847316**. Соответственно, мы уже получили почти готовый трек.  
Создаем секцию **\[cards.card\_all\]**  
И устанавливаем "физический" тип карты **code=2.**

<p class="callout warning">**Также для того, чтобы корректно отрабатывалось определение физического типа рекомендуется использовать во всех клиент с decodercards.dll данные секции:**</p>

<p class="callout warning">\[cards.Card\] - гостевая  
code=2</p>

<p class="callout warning">\[cards.RegularCard\] - постоянная  
code=22</p>

<p class="callout warning">\[cards.StaffCard\] - карта персонала  
code=21</p>

<p class="callout warning">\[cards.PDSCard\] - ПДС  
code=24</p>

Соответственно, **при прикреплении карты в базу будет прикрепляться трек с <span style="text-decoration: underline;">физическим типом 2</span>**. **При наличии служебных секций он определится, как <span style="text-decoration: underline;">гостевой</span>**

3.1.19 Осталось настроить декодирование при gkhostconnect

3.1.20 При использовании **GKHOST в GKHOSTCONNECT** на основе выше перечисленного трека прилетают карты вида **CARD A1 B2 D3 C4** !

<p class="callout warning">На конце обычно еще бывает F (\*CARD A1 B2 D3 C4\*FF ...) <span style="text-decoration: underline;">зависит от прошивки считывателя</span></p>

3.1.21 Открываем decodercards.ini при gkhostconnect и удаляем все, оставляя только необходимое и приводим к следующему виду

```
[frf]
fsUnit=fsdecodecard.upas

[general]
usemask=1
TrackResultLog=

[mask]
  card = *

[cards.card]
  code=2
  CardDecodeType = MASK
  mask=hhhhhhhh

```

<p class="callout info">Поскольку к нам прилетает карта сразу HEX значении. А при передаче в decodercards элементы #### CARD откидываются автоматически, остается лишь преобразовать hex в dec. И поставить корректный тип карты в нашем случае это 2.</p>

4\. Готово.<span style="text-decoration: line-through;"> <span style="text-decoration: underline;">(отходим и нервно курим в сторонке)</span></span>

##### Дополнительные материалы

[Настройка\_decodecards\_.txt](https://docs.shelter.ru/attachments/55)

[version (decodercards).txt](https://docs.shelter.ru/attachments/56)

[version (TCPCardReader).txt](https://docs.shelter.ru/attachments/57)