В этом топике я хотел бы поделиться своим опытом «борьбы» с одним китайским девайсом. На работе поступил приказ и было принято поменять старые кардридеры на новые. Суть в том, что старые ридеры были активные, т.е. в бесконечном цикле пытались считать карту, а вот новые уже были пассивными — работать не будут, пока не подашь на них команду. Модель аппарата CR501AU V3 (вдруг кому пригодиться). Китайский девайс, документации никакой нет (только на китайском). И всё что у меня было на руках это коробочка с этикеткой модели и кое-какой исходник. Исходник, к слову, был из другого нашего отдела, который был написан на 1С. Но, так как штат программистов у нас в конторе обновился, не осталось тех людей, которые работали над этими старыми исходниками, поэтому пришлось разбираться. Поначалу всё было просто. В исходный код 1С был вставлен кусок скрипта на Visual Basic, который отвечал полностью за работу с ридером. Ничего под рукой для работы с VB не было, поэтому воспользовался Excel-евский компилятором.

Function ReedCard()
MSComm1.CommPort = 1 'Выставляем порт
MSComm1.Settings = "19200,N,8,1" 'Выставляем настройки
MSComm1.InputLen = 0 
On Error Resume Next
MSComm1.PortOpen = True

MSComm1.Output = Chr(&HAA) & Chr(&HBB) & Chr(&H6) & Chr(&H0) & Chr(&H0) & Chr(&H0) & Chr(&H1) & Chr(&H2) & Chr(&H52) & Chr(&H51)  'Вот это строка для общения с ридером. Первая нужна для "пробуждения" ридера. Отправляем символы в hex виде
sleep (0.1) 'Спим немного, чтоб не бомбить девайс(иногда не работает корректно без сна)
Answer = MSComm1.Input
MSComm1.Output = Chr(&HAA) & Chr(&HBB) & Chr(&H5) & Chr(&H0) & Chr(&H0) & Chr(&H0) & Chr(&H2) & Chr(&H2) & Chr(&H0) 'Вторая команда пришлет нам ответ. Это то, что нам нужно — код карты. Правда, пока только ASCII-символами
sleep (0.1) 
Answer = MSComm1.Input

Dim ReadPort As String

If Len(Answer) > 10 Then 'Если при попытке считать карта была на ридере, то ответом на предыдущую команду будет строка из 14-ти символов. Если на ридер были отправлены команды на считывание, но карты не было на месте, то в ответ будет возвращено 5 символов. Поэтому, если символов >10, то обрабатываем карту

Dim a: a = s2a(Answer) 'StringToArray-функция. Просто переводит нашу строку из 14 символов в массив[14]
Dim i
For i = 0 To UBound(a)
    a(i) = Right(0 & Hex(Asc(a(i))), 2) 'В каждом элементе массива "а" у нас хранился какой-то ASCII-символ. Этот цикл пробегается по каждому символу, берет его ascii-код и переводит его в hex
Next
    ReadPort = Join(a)
    MSComm1.Output = Chr(170) & Chr(187) & Chr(6) & Chr(0) & Chr(0) & Chr(0) & Chr(6) & Chr(1) & Chr(7) & Chr(0) 'А эта команда нужна только для того, чтобы "пикнуть" :)  Т.е. ридер просто издаст звук(это для того, чтоб было понятно, что ридер считал карту)
    
'''' Тут дальше идет мой код, который просто переводит хексовую строку в число. Например: AA BB CC DD -> 2864434397. Тут много кода, но вам он не нужен — вы и сами сможете его написать.
End If
MSComm1.PortOpen = False
End Sub

 Function s2a(s)
        ReDim a(Len(s) - 1)
        Dim i
        For i = 0 To UBound(a)
            a(i) = Mid(s, i + 1, 1)
        Next
        s2a = a
    End Function
    
    Sub sleep(sk)
        PauseTime = sk
        Start = Timer
        Do While Timer < Start + PauseTime
        Loop
    End Sub

Не так уж и сложно. Но проблема заключалась в том, что этот код на VB мне нужно было перенести на Pascal в MS-DOS. Несколько дней бился с этим, но скармливая эти команды в Com-порт ридер не подавал признаков жизни. Тогда я решил сначала реализовать это на своём «родном» языке — C#. Так же пришлось попотеть, но в итоге понял в чем кроется разгадка!

serialPort1.Open();
serialPort1.Write(((char)0xAA) + "" + ((char)0xBB) + "" + ((char)0x6) + "" + ((char)0x0) + "" + ((char)0x0) + "" + ((char)0x0) + "" + ((char)0x6) + "" + ((char)0x1) + "" + ((char)0x7) + "" + ((char)0x0));
serialPort1.Close();

Код выше неправильный. Я какое-то время над ним экспериментировал, но он никак не хотел работать. И кавычки убирал. И .ToString() добавлял. И посимвольно писал в порт. Ничего. И потом как вдруг дошло:

serialPort1.Open();
byte[] ar = new byte[10];
ar[0] = 170;
ar[1] = 187;
ar[2] = 6;
ar[3] = 0;
ar[4] = 0;
ar[5] = 0;
ar[6] = 6;
ar[7] = 1;
ar[8] = 7;
ar[9] = 0;
serialPort1.Write(ar, 0, ar.Length);
serialPort1.Close();

И всё заработало! Осталось только перенести это в паскаль:
var
ar: array of Byte[10];
begin
OpenCom (ComNo, B_19200, Bits_8+Stops_1+Parity_No, 2048);
ar[0]:=170;
ar[1]:=187;
ar[2]:=6;
ar[3]:=0;
ar[4]:=0;
ar[5]:=0;
ar[6]:=6;
ar[7]:=1;
ar[8]:=7;
ar[9]:=0;

for i:=0 to 10 do begin
WriteCom(ComNo,ar[i]);
end;

Код выше заставляет ридер «пикнуть». Дальше переделать всё под себя очень просто.

P.S. Информации по этой проблеме в ру-сегменте не нашел совсем, на англоязычных же есть, но крупицы. От себя информацию по работе с RS232 на примере китайского кардридера собрал. Надеюсь кому-нибудь поможет. Удачи!
Поделиться с друзьями
-->

Комментарии (16)


  1. Genoik
    22.02.2017 19:39
    +1

    Стесняюсь спросить, а о чем вообще статья?
    Для вас стало открытием, что через Com-порт нужно пересылать Byte, а не char? Мне кажется, что любой человек, более-менее работавший с железом через Com-порт в курсе этого.
    Содержание статьи даже не соответствует заголовку, имхо. Разве в ней описано общение? По-моему, вы просто описали проблему, с которой встретились лично вы, и написали ее решение. Конкретно к картридеру эта проблема не имеет никакого отношения. На его месте могла бы быть любая железка. Точно с такими же проблемами, вы бы столкнулись, если бы писали не на Паскале и C#, но и при работе с Qt, например.


    1. Votming
      24.02.2017 05:39

      Не мог решить проблему несколько дней. Провёл небольшой ресерч. Решил поделиться с интернетом, может кто-нибудь из таких же новичков как я наткнётся на такую проблему. Эта статья же не мой дипломный проект. И не диссертация. Я всего лишь написал в песочницу, за что такой хейт. Если вы за справедливость, то не подскажете мне, как стоило назвать сей топик? Я бы сменил его, чтоб не нервировать старожилов :)


      1. Genoik
        24.02.2017 22:41
        +2

        Я могу ошибаться, но такие вещи обычно не в статьях пишутся, а максимум на форумах решаются.
        Если перефразировать вас, то эта статья выглядит примерно так:
        «Есть код:
        int a = 10;
        int b = 3;
        float c = a / b;

        Несколько дней не могу решить проблему, все время неправильно вычислялось значение. И мне пришло в голову написать так: float c = (float) a / (float)b.

        Решил написать статью, может поможет новичкам.»

        Вы ведь не будете спорить, что это частая ошибка новичка.

        Я не против статей, но в последнее время Хабр становится похож на личные блоги с заметками.


  1. golf2109
    22.02.2017 21:11

    а автору запретили во время работы использовать любые терминальные программы?


  1. ElijahCapricorn
    22.02.2017 21:21

    Странно, что автор не знает, что в его «родном» C# строки кодируются в utf и каждый символ занимает по два байта.


    1. ColdPhoenix
      22.02.2017 22:59

      хранение в данном случае не имеет значения.
      кодировка по умолчанию для строковых операций SerialPort это ASCII, итого все что выше кода 127 обрезано в знак вопроса.
      косяк автора в попытке применять строки вместо байт.


    1. Votming
      24.02.2017 05:43

      Вы цепляетесь к словам:) Хотя я и так выделил кавычками слово «родной». Просто он мне ближе других языков, пользуюсь им около двух ле. Я же не написал, что у меня пятнадцатилетний стаж в программировании на шарпе. А про кодировку utf спасибо — буду знать


  1. Zapped
    23.02.2017 03:24
    +2

    ar[0]=170;
    

    ну, это же не Pascal )))
    вот Pascal:
    ar[0] := 170;
    

    к слову, идентично
    ar[0] := $AA;
    

    команды и данные таких протоколов удобнее для понимания писать в шестнадцатиричной форме


    1. Votming
      24.02.2017 05:47

      Спасибо, что поправили. Не было под рукой ничего, поэтому вписал в статью код «от руки». А на паскале не пишу, поэтому синтаксис в голове не «закрепился». Вот и забыл про присвоение


  1. aamonster
    23.02.2017 12:20

    Без обид, но это одна из классических ошибок новичка, никак не связанных с кардридерами и ком-портами. Если у вас было в институте/школе программирование — то там наверняка упоминали текстовые и бинарные файлы, и запись в них, возможно, даже производилась разными функциями. Вот это оно самое (работать с бинарным файлом, как с текстовым — и так испортить его).


    А в сети вы не нашли информацию просто потому, что искали в применении к RS232. А кто работает с RS232 — обычно уже давно на эти грабли не наступает.


    1. Votming
      24.02.2017 05:32

      Да, вы правы, это ошибки новичка. С ком-портами до этого не работал(только с виртуальными). В институте было упоминание про бинарники, но тогда была одна лабораторная на 1ом курсе, где надо было записать и считать данные в\из бинарного файла. Подумал, может тоже у кого будут проблемы похожие: новички, которые не могут разобраться и найти информацию. Уже даже не знаю, нужно ли было писать этот топик


      1. aamonster
        24.02.2017 10:02

        Да нормально, мир не из одних зубров состоит, и на эти грабли новички регулярно наступают (правда, обычно им везёт больше, чем вам — пишут в файл, а не в устройство, и могут посмотреть, что же записалось, так что ошибку видят почти сразу). Если б ещё заголовок придумать такой, чтобы отражал суть проблемы...


  1. DCNick3
    24.02.2017 05:28

    Скорее всего проблема в том, что у c# нативные строки (ну и char тоже) — юникодовые (UCS-2). Поэтому карт-ридеру это и не нравится. Но я-бы для начала попробовал пообщатся с ним через какой-нибудь терминал для COM портов. И мучиться не надо, колдуя над строками, и сразу видно что отвечает…


  1. Shyster
    24.02.2017 05:29

    мне нужно было перенести на Pascal в MS-DOS.

    как будто окунулся, лет на 20 с хвостиком. Когда на Поиск1 читал первые карточки ISO7816 через LPT, с помощью паскаля.


    1. Votming
      24.02.2017 05:49

      У нас сейчас половина машин на предприятии работает на досе. Забавно понимать, что ломаешь голову над теми проблемами, которые волновали людей 20 лет назад


  1. barker
    24.02.2017 15:21

    Статья не про RS232, а про serial port вообще.
    Хотя и не про сериал порт, а про ввод-вывод вообще.
    Да и не про ввод-вывод, а про базовый уровень понимания предмета)