.

Вот долгожданная вторая часть статьи о декодирования штрих-кода полиса ОМС. В этой публикации я хочу рассмотреть непосредственно работу со сканером  и использование теории, которую я описал в первой части.

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

  1. Установите драйвера для сканера. На две наиболее распространенные модели можете скачать на этом сайте, в разделе загрузки. Качаем. Распаковываем архив. И запускаем с правами админа install.bat.
  2. Ищем в мануале к сканеру штрих-код программирующий сканер на «эмуляцию com-порта». Над штрих-кодом иногда пишут эмуляция RS232 (это и есть com-порт:).
  3. Сканер после сканирование пикнет. После отключаем и подключаем его снова, и в диспетчере устройств видим следующую картинку.
Эмуляция com-порта сканером
Вот так выгляди диспетчер устройств при эмуляции com-порта сканером

Красным выделено сканер, который подключен к com-порту, хотя физически он висит на USB-порту.



Компонент для работы с com-портами...

Поясню сразу, я писал данную программу и работал с com-портами через компонент. Перед тем как отрывать исходники советую установить компонент. Скачать его можно здесь. Установка компонента происходит следующим образом.

1. Пропишем путь к сорцам компонента. Переходим в раздел  "Tools-Environment Options...".
2. Переходим во вкладку "Library". Напротив поля "Library path" нажимаем на кнопку "...".
3. В открывшемся диалоге нажимаем на кнопку "...". И указываем папку где лежит компонент.
4. После чего нажимаем на кнопку "Add".
5. Все пути прописали переходим к установке.

6. Переходите в раздел "File-Open". Открываем файл (для Delphi 7 -это BComPortD7.dpk).
7. Последовательно нажимаем кнопки "Compilet" и затем "Install".
Вот и все, теперь можете открывать исходники программы.

Оболочка работы со сканером…

Перейдем непосредственно к программированию. И так, я набросал небольшую форму для работы с библиотекой. Пройдемся по интерфейсу.

Фото программы декодирование штрих-кода
Фото программы декодирование штрих-кода

Поле 1 "Порт" : Список всех подключенных в системе com-портов. Обратите внимание, я выбрал COM10 Ведь именно этот com –порт написан в диспетчере устройств и на нем подключен сканер. У вас будет другой. Какой - смотрите в диспетчере устройств.

Поле 2 "Скорость " :  Скорость соединения. Честно говоря в мануале я описание скорости не находил, да и отсылки именно к этому значению тоже. Оно получено путем экспериментов. Скорость влияет на качество принимаемых данных. Если скорость изменить это может отрицательно повлиять на работу. В своем основном проекте я ее просто по умолчанию выставляю на это значение. (Если скорость низкая - приходится долго ждать пересылку данных со сканера в компьютер. Если выставить скорость выше - наблюдается неустойчивое чтение.)

Кнопка "Подключить" : Открываем соединение с com-портом. И начинаем принимать данные. В данном случае, мы обрабатываем данные только в тот момент, когда сканер их передал в com-порт.

Пример кода:

procedure TForm1.btnConnectClick(Sender: TObject);
begin
  BComPort2.Port := cbPort.Text; //Название порта
  BComPort2.BaudRate := TBaudRate(cbBaudRate.ItemIndex); //Скорость
  if BComPort2.Open then //Открываем порт
  begin
    btnConnect.Enabled := False; //Отключаем все кнопки если комп порт
    cbPort.Enabled := False; // удачно удалось открыть порт
    Disconnect.Enabled := True;
  end;
end;

Кнопка "Обновить" : Процедура получает список com-портов доступных в системе и перечисляет их в списке.

Пример кода:

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
 EnumComPorts(cbPort.Items); //Получение списка портов
  cbPort.ItemIndex := 0; //Выставляем на первый элемент списка
  cbBaudRate.ItemIndex := 3; ///Выставляем скорость
end;

Кнопка "Отключить" : Закрываем соединение с портом.

Пример кода:

if BComPort2.Close then //Закрываем порт
  begin
  btnConnect.Enabled := True;//Активируем кнопки если удачно удалось закрыть соединение
  cbPort.Enabled := True;
  Disconnect.Enabled := False;
  end;

Поле 6 : Текстовое поле - сюда выводится информация полученная со штрих-кода.

Библиотеку я писал на Delphi XE, и как я уже не однократно отмечал, она работает со строками в UTF-8. Помимо этого, при обмене данными между dll и основной программой, во избежание ошибок обработки данных, их лучше передавать в массиве байт.
Итак перейдем непосредственно к коду:

type
  TByteArr = array of byte;

type TBARCODE = Record  //Структурная переменная к которую будет записаны все данные
  PolicyString : WideString;
  FirstName : WideString;
  LastName : WideString;
  Patronymic : WideString;
  Sex : WideString;
  Data : WideString;
  Data_End : WideString;
end;

type
  TForm1 = class(TForm)
    BComPort1: TBComPort;
    GroupBox1: TGroupBox;
    Label3: TLabel;
    Label1: TLabel;
    cbPort: TComboBox;
    cbBaudRate: TComboBox;
    BitBtn1: TBitBtn;
    btnConnect: TBitBtn;
    Disconnect: TBitBtn;
    Memo1: TMemo;
    procedure btnConnectClick(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
    procedure DisconnectClick(Sender: TObject);
    procedure BComPort2RxChar(Sender: TObject; Count: Integer);

  private
    { Private declarations }
    function StrToByte(const Value: String): TByteArr;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  BarCode:TBARCODE;  ///Переменная типа TBARCODE

implementation

{$R *.dfm}

procedure TForm1.BComPort2RxChar(Sender: TObject; Count: Integer);
var
  S:String; //Строка получаемая со сканера
  xByte2: TByteArr; //Массив байт
  I: integer;
  DLLRoutine: function (xByte: TByteArr):TBARCODE; //Описание функции вызываемой в dll
  DLLHandle: THandle;
  pa : string; //Путь до Scan.dll
begin
  BComPort2.ReadStr(S, Count);
  S := S + #10;  ////  строки со сканера
  xByte2 := StrToByte(s);//перекодируем
  pa :=ExtractFilePath(Application.ExeName)+'Scan.dll'; //Dll лежит обычно рядом с exe
  DLLHandle := LoadLibrary(pchar(pa)); //Адрес в памяти, в загруженной библиотеке

  try
   DLLRoutine := GetProcAddress(DLLHandle, 'Decode_Scan'); //Вызываем функцию из dll
   if Assigned(DLLRoutine) then
    barcode:=DLLRoutine (xByte2)  //Передаем массив байт в dll, результат запишем в структурную переменную
   else
   MessageDlg('Процедура не найдена в DLL.', mtInformation,
                   [mbOK], 0);
  finally
          FreeLibrary(DLLHandle);
  end;
   //За обертку вызова dll, огромное спасибо моему товарищу и учителю Format_C_eft (ЧЕРЕДНИЧЕНКО О.Г.)

  Memo1.Lines.Add(barcode.PolicyString);
  Memo1.Lines.Add('-------------------');
  Memo1.Lines.Add(barcode.FirstName+' '+barcode.LastName+' '+barcode.Patronymic);
  Memo1.Lines.Add('-------------------');
  Memo1.Lines.Add(barcode.Sex);
  Memo1.Lines.Add('-------------------');
  Memo1.Lines.Add(barcode.Data);
  Memo1.Lines.Add('-------------------');
  Memo1.Lines.Add(BarCode.Data_End);
  Memo1.Lines.Add('-------------------');

  //xByte := StrToByte(s);  //Это просто пример вывода массива байт в текстовое поле
 // Memo1.Lines.Add(IntToStr(Length(xByte2)));
//  for I := 0 to 17 do
//  begin
//  Memo1.Lines.Add(IntToStr(xByte2[I]));
//  end;
end;

Вот собственно результат сканирование полиса:

результат

Да, не забываем размещать ссылку на сайт при использовании материала. И конечно комментируйте.  Есть еще идея выложить видео с разъяснением как использовать программу и вообще как все происходит показать наглядно - но это пока наметки. В комментариях пишите мнение на эту тему. Спасибо за внимание и пользуйтесь на здоровье. С уважением, ваш Shinobi.
Все исходники можете скачать здесь.

P.S. Нравится материал. Длитесь в твитере, лайкайте в контакте и так далее. Хочется выразить благодарность кликай по рекламе. Все спасибо))

13 комментариев


  1. При написании ПО на другом языке, невозможно подключить описанный компонент. Я настроил сканер на работу с СОМ-портом вместо эмулятора клавиатуры, но получить (перехватить) данные программы никак не получается или пока не получается. В скаченных программах все работает замечательно, но все они выводят дамп в свое окно, если эти данные выгрузить в свой bin-файл или hex-код в текстовый, то все легко можно загрузить в свою программу и заняться расшифровкой. А а нельзя создать на Delphi программку, которая, скажем, будет «висеть» в трее и при сканировании загонять код в bin-,hex- или в буфер?

    Ответить
  2. admin_shinobi

    Не вопрос. Леонид, поймите меня — изначально идея была просто разложить все до самых мелочей в первой части. Во второй — показать как все работает вместе. Я часто сталкивался с проблемой: прочтешь статью, копируешь код, а он не работает потому, что автор забыл, например, указать какие библиотеки надо дополнительно прописать или компоненты. И у меня как новичка это вызывало панику. Хорошо, я выложу статью с исходниками: тоже самое только раскодированные данные будут складываться в строчку с разделителем «|» и записываться в буфер системы.

    Ответить

    • Я во многом пытаюсь разобраться самостоятельно, по примерам. Действительно, порой в статьях процесс описывается так, что по описанию трудно понять что и как сделать. Ладно, если это нужно только тебе, можно посерфить интернет, задать вопросы на форумах, ну или накрояняк сделать кучу ненужных операций, но результат получить. А вот когда хочешь сделать что то полезное еще и другим, тут ищешь все более тщательно, чтобы не тратить свое время на мелочи, создавая нечто большое, вот так я нашел и этот сайт. Конечно можно обойтись без сервисов, заставив пользователя, в своем ПО, вбивать тот же номер полиса ручками, но зачем, если есть возможность облегчить работу медикам хотя бы даже в этом и если это уже кто то сделал зачем изобретать паровоз заново?

      Ответить
      • admin_shinobi

        Да я с вами полностью согласен. Мне нравится экспериментировать и находить оригинальные подходы о которых еще мало кто писал. И вообще просто разбирать сложные задачки… Я не привык задавать вопросы на форумах. Мои инструмент: гугл, эксперименты и анализ. По образованию я инженер-механик, а в душе и реальности программист.
        Был у нас предмет ТММ, в шутку называли его «Тут Моя Могила», на самом деле это было «Теория Машин и Механизмов». Жесткий предмет, для тех кто поймет это сравнимо с Сопраматом. Преподавал нам его один старик. Башка у него варила что надо. И вот там меня научили: «анализ и синтез — есть основа всего». Это мой девиз. Мало на гуглить нужной инфы, ее нужно уметь проанализировать. Но даже имея набор готовых функций и процедур — нужно владеть способностями к синтезу. Собрать из пазлов цельную картинку.

        Ответить
  3. Oleg

    Добрый день
    Спасибо за библиотеку. Еще не пробовал её внедрять, но из загрузок попробовал запустить Project1. Сканирует, Получает номер полиса, фио, а дальше всё. И вылетает с ошибкой.
    Примерный результат (ЕС):

    0856540889000022
    ——————-
    ФАМИЛИЯ ИМЯ ОТЧЕСТВО ЕС
    ——————-
    ——————-
    01.01.1900
    ——————-
    01.01.1900
    ——————-
    ——————-
    ——————-
    ——————-
    ——————-
    ——————-

    Ответить
  4. Oleg

    Хотя попробовал еще раз — прочитала нормально. Скажите, а в штрих коде нету огрн или еще каких нибудь данных для определения страховой компании? Ну например как в электронном полисе — там есть терриотрия страхования + огрн. В первом сообщение — ЕС — это что то еще выходящее при сканировании

    Ответить
    • admin_shinobi

      В штрих-коде, при бумажном полисе ОМС, нет необходимости в ОГРН — страховые компании ставят свои отметки на его обратной стороне (специально отведено место). В случае пластикового полиса (или УЭК) — ОГРН хранится в чипе. На пластик ведь печать не поставишь 🙂 Пластиковые полисы присылают в конверте… В этом же конверте идет бумага с PIN кодами и на ней есть тот же штрих-код, что и на бумажном полисе. Иногда еще рядом присутствует маленький квадратик штрих-кода в формате DataMatrix. Я не работал над ним в плотную, но есть подозрение, что там возможно зашито первоначальное ОГРН страховой, которая заказывала. Но он есть не на всех полисах.

      Ответить
  5. Oleg

    Большое вам спасибо! Очень помогли разобраться в данной проблеме )

    Ответить
  6. texnix

    shinobi а новую статью на тему как считать электронный полис вы напишите?

    Ответить
    • admin_shinobi

      Да пытаюсь работать в этом русле…Правда пока не очень получается.
      P.S.Сегодня (28.12) сильно продвинулся в этой теме…Хотел уже все бросить и разработать на Си++,но нашел не плохой материал именно под Delphi. Осталось дело за малым правильно составить команду для чтения данных с карты…Так надеюсь после новогодних ждите статью на эту тему))

      Ответить
      • racinghart

        День добрый!
        Ну так что? Продвижения после новогодних праздников последовало? Очень интересно разобраться с УЭК. Имеется и карт-ридер, и карта.. Но вот как все это использовать?! Не так уж много требуется. Считать паспортные данные, данные полиса. Цифровая подпись мало интересует. Есть какие-нибудь наработки? Или может ссылочки полезные, исходники))

        Ответить
        • admin_shinobi

          Добрый день,racinghart. Да материальчик у меня наработанный есть, правда не по УКЭ. Есть по ластиковым картам (электронным полисам) или еще можно их назвать смарт-картами. Поскольку я хотел чуть позже выложить его, но раз вас мучает этот вопрос то на выходных я выложу материал на эту тему. Дата орентировачно 28 февраля и 1 марта. Подписывайтесь на обновление по почте.

          Ответить

  7. C# — там все то же самое (единственная неточность — параметр Size в атрибуте StructLayout для BARCODE_T1 — там должно быть 220, а не 203 — к счастью, . А где Вы взяли пример считанного штрих кода полиса?

    Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *