В этом топике я хотел бы поделиться своим опытом «борьбы» с одним китайским девайсом. На работе поступил приказ и было принято поменять старые кардридеры на новые. Суть в том, что старые ридеры были активные, т.е. в бесконечном цикле пытались считать карту, а вот новые уже были пассивными — работать не будут, пока не подашь на них команду. Модель аппарата 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[9];
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[8] = 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 на примере китайского кардридера собрал. Надеюсь кому-нибудь поможет. Удачи!
Автор: Votming