Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > ОС и железо
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 14.10.2012, 06:28
firmwares firmwares вне форума
Прохожий
 
Регистрация: 30.06.2010
Сообщения: 6
Репутация: 10
Сообщение Работа со считывателем БСК MF-RW-USB

Всем доброго времени суток.

Суть вот в чем:
1. Есть считыватель БСК MF-RW-USB, который создает виртуальный COM порт средствами FT232.
2. Для общения со считывателес используется DLL библиотека, которая содержит в себе все необходимое.
3. Обмен данными со считывателем осуществляется с использованием проверки контрольных сумм по FCS алгаритму.

Функция W_IO: обмен данными со считывателем
Код:
function W_IO(Address, Cmd: char; BodyLen: integer; const CmdBody; var ReplyLen: integer; var Reply-Buffer): char; 
char W_IO(char Address, char Cmd, int BodyLen, void *CmdBody, int *ReplyLen, void *ReplyBuffer);
Описание:
Address адрес считывателя (0..3F)
Cmd команда
BodyLen длина дополнительных данных для команды
CmdBody буфер, содержащий дополнительные данные
ReplyLen длина данных, полученных от считывателя
ReplyBuffer буфер, в который будут помещены полученные данные.
При вызове функции в ReplyLen должен быть записан размер области памяти, отведенной под Reply-
Buffer. На выходе в ReplyLen будет записана длина фактически полученных данных.
Возвращаемое значение – код возврата, см. раздел «Константы» REPLY_XXXXX.

Пример из мануала к библиотеке:
Код:
procedure ReadEventLog;
var
  Ret: char;
  RL: integer;
  Event: TEvent;
begin
// до вызова этой функции должна быть вызвана функция W_SetPortParams
// читаем считыватель с адресом 3F
  repeat
    Ret := W_IO(#$3F, #$10, 0, '', RL, Event);
    if Ret = REPLY_OK then begin
//    Успешно прочитали событие, обрабатываем его…
      Ret := W_IO(#$3F, #$11, 0, '', RL, Event);
      if Ret <> REPLY_ACK then begin
//      Ошибка удаления последнего события – обрабатываем…
      end;
    end else begin
//    Ошибка чтения события – обрабатываем…
    end;
  until Ret <> REPLY_ACK; // выход из цикла чтения при ошибке
end;

Скажите пожалуйста, как сформировать запрос таким образом, чтобы ответ полученный от считывателя вписывался в Edit.
В Edit необходимо вывести данные из ReplyBuffer.

Еще было бы не плохо выкинуть настройки порта в ini
Код:
 t.Port:= 1;
 t.BaudRate:= 9600;
 t.WaitPortTimeout:= 200;
 t.ReadTotalTimeout:= 100;
 t.ReadNextByteTimeout:= 50;
 t.RecordSize:= 21;

Прошу, не пинайте, в работе с портами я ноль, а сделать необходимо.
Всем заранее огромное спасибо за помощь.
Вложения
Тип файла: rar DLL.rar (237.8 Кбайт, 9 просмотров)
Ответить с цитированием
  #2  
Старый 14.10.2012, 19:50
Аватар для cotseec
cotseec cotseec вне форума
Активный
 
Регистрация: 16.07.2008
Сообщения: 353
Версия Delphi: D7,TDE06,RAD09
Репутация: 1443
По умолчанию

Цитата:
Скажите пожалуйста, как сформировать запрос таким образом, чтобы ответ полученный от считывателя вписывался в Edit.
В Edit необходимо вывести данные из ReplyBuffer
от вида запроса вывод данных в Edit не зависит, чтобы вывести в Edit то, что пришло необходимо обрабатывать ReplyBuffer, заполненный после
Код:
char W_IO(char Address, char Cmd, int BodyLen, void *CmdBody, int *ReplyLen, void *ReplyBuffer);
если железка использует ASCII - выводить напрямую, иначе преобразовывать в необходимый вид (чаще HEX)
настройки порта в ini - это работа с ini, перед открытием порта читаем из ini, перед закрытием программы пишем в ini
__________________
Понять, что хочет заказчик - бесценно, ведь он платит MasterCard
Ответить с цитированием
  #3  
Старый 14.10.2012, 20:53
firmwares firmwares вне форума
Прохожий
 
Регистрация: 30.06.2010
Сообщения: 6
Репутация: 10
По умолчанию

Тоесть получается, что
Код:
function W_IO(Address, Cmd: char; BodyLen: integer; const CmdBody; var ReplyLen: integer; var Reply-Buffer): char;
Это сам запрос к считывателю, а
Код:
char W_IO(char Address, char Cmd, int BodyLen, void *CmdBody, int *ReplyLen, void *ReplyBuffer);
Это непосредственно обработчик ответа?

на данный момент код выглядет так:
Код:
unit Main_form;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, SyncObjs, ExtCtrls;

type
  TMain = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    function LinkProc(ProcName: string):Pointer;
    procedure Read;
    procedure PortSetup;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

  type
  PComInfo = ^ TComInfo;
  TComInfo = record
  RecordSize: DWORD; // Размер структуры, байт
  Port: BYTE; // Номер порта. 1 - COM1 и т.д.
  BaudRate: DWORD; // Скорость обмена
  WaitPortTimeout: DWORD; // Время ожидания доступности порта, мс
  ReadTotalTimeout: DWORD; // Время ожидания ответа считывателя, мс
  ReadNextByteTimeout: DWORD; // Время ожидания поступления очередного
                              // байта при условии, что обнаружено начало
                              // валидного кадра, мс.
  end;

  type
  PProtocolInfo = ^ TProtocolInfo;
  TProtocolInfo = record
  DisableAddress: BOOLEAN; // Размер структуры, байт
  CheckMode: INTEGER; // Режим проверки контрольной суммы
  end;


// Описываем константы...
  const
// Коды ответа оборудования
REPLY_OK = #$00;       //Команда выполнена успешно, получены данные
REPLY_ACK_NACK = #$2A; //Признак кадра ACK/NACK, вне библиотеки не используется
REPLY_ACK = #$55;      //Получен ответ ACK
REPLY_NACK1 = #$01;    //Получен ответ NACK1
REPLY_NACK2 = #$02;    //Получен ответ NACK2
REPLY_NACK3 = #$03;    //Получен ответ NACK3
REPLY_NACK4 = #$04;    //Получен ответ NACK4
REPLY_NACK5 = #$05;    //Получен ответ NACK5
REPLY_NACK6 = #$06;    //Получен ответ NACK6

// Коды ошибок при работе с портом
REPLY_MISS =	#$FF;             //Ответ не получен (отсутствует считыватель)
REPLY_ERR_OPENPORT =	#$FE;     //Ошибка открытия порта
REPLY_ERR_WRITEPORT =	#$FD;     //Ошибка записи в порт
REPLY_ERR_READPORT =	#$FC;     //Ошибка чтения из порта
REPLY_ERR_LOCKPORT =	#$FB;     //Истек таймаут при попытке захватить порт
REPLY_ERR_PORTNOTSET =	#$FA;   //Параметры порта не установлены
REPLY_ERR_INVALIDANSWER =	#$F9; //Ответ не удалось правильно интерпретировать
REPLY_ERR_CRC =	#$F8;           //Ошибка контрольной суммы
REPLY_ERR_INVALIDFRAME = #$F7;  //Неверный идентификатор кадра

// Методы расчета контрольной суммы кадра
CHECK_NONE = #$00;  //Не проверять контрольную сумму кадра
CHECK_SUM =	#$01;   //Использовать суммирование (1 байт)
CHECK_CRC16 = #$02;	//Использовать CRC16 (2 байта)
CHECK_FCS = #$03;	  //Использовать FCS (2 байта)

var
  Ret: char;
  ReplyLen: integer;
  ReplyBuffer: char;
  Main: TMain;
  t: TComInfo;
  p: TProtocolInfo;
  W_SetPortParams: procedure(PortCfgPtr: PComInfo); stdcall;
  W_SetProtocolParams: procedure(ProtocolInfoPtr: PProtocolInfo); stdcall;
  W_IO: function (Address, Cmd: char;
                 BodyLen: integer;
                 const CmdBody;
                 var ReplyLen: integer;
                 var ReplyBuffer): char; stdcall;
  LibHandle: THandle;

 implementation

uses StrUtils;

{$R *.dfm}

{ TForm1 }

function TMain.LinkProc(ProcName: string): Pointer;
begin
  result:= GetProcAddress(LibHandle,PChar(ProcName));
end;
// Устанавливаем параметры порта...
procedure TMain.PortSetup;
begin
 t.Port:=3;                 // Номер порта. 1 - COM1 и т.д.
 t.BaudRate:=115200;        // Скорость обмена
 t.WaitPortTimeout:= 200;   // Время ожидания доступности порта, мс
 t.ReadTotalTimeout:= 100;  // Время ожидания ответа считывателя, мс
 t.ReadNextByteTimeout:= 50;// Время ожидания поступления очередного
                            // байта при условии, что обнаружено начало
                            // валидного кадра, мс.
 t.RecordSize:= 21;         // Размер структуры, байт
end;

// Подключаем библиотеку...
procedure TMain.FormCreate(Sender: TObject);
begin
 LibHandle:= LoadLibrary('dll/ProX232.dll');
 W_SetPortParams:= LinkProc('W_SetPortParams');
 W_SetProtocolParams:= LinkProc('W_SetProtocolParams');
 W_IO:= LinkProc('W_IO');
end;

//Формируем запрос...
procedure TMain.Read;
begin
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
if Ret = REPLY_OK then begin
 Edit1.Text:='Команда выполнена успешно, получены данные';
 Edit2.Text:=(ReplyBuffer);
end;
if Ret= REPLY_ACK then begin
 Edit1.Text:='Получен ответ ACK';
 Edit2.Text:=(ReplyBuffer);
end;
if Ret= REPLY_NACK6 then begin
 Edit1.Text:='Получен ответ NACK6';
 Edit2.Text:=(ReplyBuffer);
end;
 end;

// Создаем подключение, Устанавливаем параметры протакола и отправляем запрос...
procedure TMain.Button1Click(Sender: TObject);
begin
 PortSetup;
 W_SetPortParams(@t);
 W_SetProtocolParams(@t);
 read;
end;

// Закрываем программу...
procedure TMain.Button2Click(Sender: TObject);
begin
close;
end;

end.

При таком раскладе программа корректно отправляет запрос, в сниффере видно, что ответ от ридера есть.
В Edit1 все вписывается, так, как должно ( «Константы» REPLY_XXXXX определяются верно и ответ выводится верно), вот только в Edit2 вписывается 1.
А вот с ответом в Edit1 у меня проюлемы.
Я так понимаю, что необходимо использовать
Код:
char W_IO(char Address, char Cmd, int BodyLen, void *CmdBody, int *ReplyLen, void *ReplyBuffer);
но как его использовать и где его необходино прикрутить, я понять не могу.
Общение со считывателем осуществляется в щеснадцатиричной кодировке.
С ini я вроде разобрался, спасибо.
Ответить с цитированием
  #4  
Старый 14.10.2012, 21:21
Аватар для cotseec
cotseec cotseec вне форума
Активный
 
Регистрация: 16.07.2008
Сообщения: 353
Версия Delphi: D7,TDE06,RAD09
Репутация: 1443
По умолчанию

у вас все вделано верно, почти
Цитата:
Код:
//Формируем запрос...
procedure TMain.Read;
begin
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
if Ret = REPLY_OK then begin
 Edit1.Text:='Команда выполнена успешно, получены данные';
 Edit2.Text:=(ReplyBuffer);
end;
if Ret= REPLY_ACK then begin
 Edit1.Text:='Получен ответ ACK';
 Edit2.Text:=(ReplyBuffer);
end;
if Ret= REPLY_NACK6 then begin
 Edit1.Text:='Получен ответ NACK6';
 Edit2.Text:=(ReplyBuffer);
end;
 end;
только необходимо задать значения ReplyLen и выделить память под ReplyBuffer, потом соответственно выводить ReplyBuffer и освобождать память, вы просто объявили эти переменные, необходимо их теперь иннициализировать, что-то типа
Код:
var
...
   ReplyBuffer: Pointer;
...

begin
// выделяем память
    ReplyLen:=255;
    ReplyBuffer:=GetMem(ReplyLen);
    Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
// теперь по адресу ReplyBuffer находится массив полученного ответа
//далее  по тексту
..
//вывод в Edit2 для начала можно так (см. коментарий в конце ответа)
  Edit2.Text:=PChar(ReplyBuffer);


  FreeMem(ReplyBuffer,ReplyLen);
end;
 

т.к.
Цитата:
Общение со считывателем осуществляется в щеснадцатиричной кодировке.
(соответсвенно он и отвечает в НЕХ), то в ответе просто набор байт, который находится в ReplyBuffer, а выводя его не вариант, что получаются читабельные символы, необходимо дополнительно их преобразовывать в читабельный вид
__________________
Понять, что хочет заказчик - бесценно, ведь он платит MasterCard

Последний раз редактировалось cotseec, 14.10.2012 в 21:33.
Ответить с цитированием
  #5  
Старый 14.10.2012, 23:14
firmwares firmwares вне форума
Прохожий
 
Регистрация: 30.06.2010
Сообщения: 6
Репутация: 10
По умолчанию

Если запрос сформировать так:
Код:
procedure TMain.Read;
 begin
 ReplyLen:=255;
 ReplyBuffer:=GetMem(ReplyLen);
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
if Ret = REPLY_OK then begin
 Edit1.Text:='Команда выполнена успешно, получены данные';
 Edit2.Text:=PChar(ReplyBuffer);
end;
 FreeMem(ReplyBuffer);
 end;
то компилятор ругается на
Код:
 ReplyBuffer:=GetMem(ReplyLen);
[Error] Main_form.pas(138): Incompatible types

Если сделать таким образом:
Код:
procedure TMain.Read;
 begin
 ReplyLen:=255;
 ReplyBuffer:=GetMemory(ReplyLen);
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
if Ret = REPLY_OK then begin
 Edit1.Text:='Команда выполнена успешно, получены данные';
 Edit2.Text:=PChar(ReplyBuffer);
end;
 FreeMemory(ReplyBuffer);
 end;
То все компилируется, но вылетает ошибка и в Edit2 ничего не вписывает.
Что я опять сделал не так?



Привел запрос к следующму виду
Код:
procedure TMain.Read;
 begin
 ReplyLen:=255;
 ReplyBuffer:=GetMemory(ReplyLen);
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
if Ret = REPLY_OK then begin
 Edit1.Text:='Команда выполнена успешно, получены данные';
 Edit2.Text:=PChar(GetMemory(ReplyLen));
end;
 //FreeMemory(ReplyBuffer);
  end;
И теперь в Edit2 вписывает - "-6E"
Если езменить ReplyLen:=25;, то вписывает - "TK•", но это не то, что мне необходимо вывести.
В Edit2 должно выводиться примерно следующее - "31 33 20 4D 48 7A 20 52 65 61 64 65 72"

При включении FreeMemory(ReplyBuffer);, программа при первом же запросе падает в ошибку, а при отключении при втором.

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

При выполнении запроса в цикле ошибка не выскакивает, программа ререстает отвечать, хотя со считывателем общается.
Код:
procedure TMain.Read;
 begin
 repeat
 ReplyLen:=25;
 ReplyBuffer:=GetMemory(ReplyLen);
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
if Ret = REPLY_OK then
 Edit1.Text:='Команда выполнена успешно, получены данные';
 Edit2.Text:=PChar(GetMemory(ReplyLen));
 until Ret = REPLY_ACK; // выход из цикла чтения при ошибке
 end;
Изображения
Тип файла: jpg error.JPG (10.5 Кбайт, 6 просмотров)

Последний раз редактировалось firmwares, 15.10.2012 в 07:16.
Ответить с цитированием
  #6  
Старый 15.10.2012, 10:38
Аватар для cotseec
cotseec cotseec вне форума
Активный
 
Регистрация: 16.07.2008
Сообщения: 353
Версия Delphi: D7,TDE06,RAD09
Репутация: 1443
По умолчанию

начнем сначала
прототип функции (в С)
Цитата:
Код:
char W_IO(char Address, char Cmd, int BodyLen, void *CmdBody, int *ReplyLen, void *ReplyBuffer);
аргументы такие:
Цитата:
Address:byte;
Cmd:byte;
BodyLen:integer;
CmdBody:Pointer;
ReplyLen:Pinteger;
ReplyBuffer:Pointer
соответственно прототип в Delphi:
Код:
function W_IO(Adress:byte;Cmd:byte;BodyLen:integer; CmdBody:Pointer;ReplyLen:Pinteger;ReplyBuffer:Pointer):byte;stdcall
т.е. функции нужны:
адрес устройства,
команда для устройства,
размер буфера аргументов команды для устройства,
указатель на буфер с аргументами команды для устройства,
указатель на длину буфера для приема,
указатель на сам буфер для приема
работа с функцией:
Код:
...
var
...
   ReplyLen:integer;
   ReplyBuffer:Pointer;
...
begin
//определяем размер буфера и выделяем под него память
   ReplyLen:=$FF;
   ReplyBuffer:=GetMemory(ReplyLen);
//если нужен цикл, то начало цикла тут
// начало цикла
...
   Ret := W_IO(#$1, #$00, 0, '', @ReplyLen, ReplyBuffer);
   if Ret = REPLY_OK then
   begin
      Edit1.Text:='Команда выполнена успешно, получены данные';
      Edit2.Text:=PChar(ReplyBuffer);// PChar(GetMemory(ReplyLen));как у вас - бред, пытаемся просто отбразить только что выделеную память
   end;
...
// тут конец цикла
...
   FreeMemory(ReplyBuffer);// в конце освобождаем память
end;
после вызова этой функции и передачи ей необходимых параметров, функция кушает адрес устройства, команду и аргументы команды (согласно размеру буфера аргументов), отправляет все это на устройство и закидывает по адресу буфера ответа пришедший ответ от устройства (видимо еще проводит проверку на достаточность длины буфера) и в своем результате показывает результат выполнения, т.е. REPLY_OK и т.п., т.е. после вызова этой функции и проверки возвращаемого результата необходимо смотреть в буфере ответа ответ от устройства
для того, чтобы этот результат был в виде
Цитата:
31 33 20 4D 48 7A 20 52 65 61 64 65 72
необходимо "расшифровывать" буфер

З.Ы. как вариант функция сама определяет ReplyBuffer и ReplyLen и все выделения памяти в программе не нужны, тогда как dll освобождает память после ее использования?
З.Ы.Ы. или закручено еще круче: функция после своей работы выбрасывает по адресу ReplyLen длину необходимого ей буфера, а при следующем своем вызове заполняет его (или какой-то другой функцией), но это из области фантазий - нужно смотреть докуметацию или коментарии к библиотеке, если таковые есть
З.Ы.Ы.Ы а может проще написать свой класс работы с СОМ портом, тем более протокол известен, кто знает какие там ошибки в dll а так, если не работает - сам дурак
__________________
Понять, что хочет заказчик - бесценно, ведь он платит MasterCard

Последний раз редактировалось cotseec, 15.10.2012 в 10:42.
Ответить с цитированием
  #7  
Старый 16.10.2012, 01:33
firmwares firmwares вне форума
Прохожий
 
Регистрация: 30.06.2010
Сообщения: 6
Репутация: 10
По умолчанию

Уважаемый cotseec,
Скажите пожалуйста, в чем может быть проблема?
Читая в очередной раз жоки на протакол и библиотеку, я наткнулся на следующее
Методы расчета контрольной суммы кадра
CHECK_NONE - 0х00 //Не проверять контрольную сумму кадра
CHECK_SUM - 0х01 //Использовать суммирование (1 байт)
CHECK_CRC16 - 0х02 //Использовать CRC16 (2 байта)
CHECK_FCS - 0х03 //Использовать FCS (2 байта)
И тут я нашел свою первую ошибку, в следствии чего программа падает в ошибку. Найти нашел, но как исправить не пойму.

изначально W_SetProtocolParams(@t); у меня ссылался на TComInfo;, а должен на TProtocolInfo;
со следующей структурой.
Структура TProtocolInfo:
DisableAddress - BOOLEAN //Размер структуры, байт
CheckMode - INTEGER //Режим проверки контрольной суммы
Добавилв код следующее:
Код:
procedure TForm1.Button2Click(Sender: TObject);
var Prot: TProtocolInfo;
begin
// Prot.DisableAddress:='Это в коментах потому что не могу сообразить, как правильно заполнить'; // Размер структуры, байт
Prot.CheckMode:=03; // Режим проверки контрольной суммы
W_SetProtocolParams(@Prot)
end;
При таком раскладе, программа падает в ошибку при нажитии на эту кнопку и параметры протакола не устанавливаются.

Сейчас переписал все заново и разбил все по кускам (вывел в отдельные кнопки каждую часть - подключение. установку протакола и сам запрос)
Теперь код такой:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, SyncObjs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    function LinkProc(ProcName: string):Pointer;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  type
  PComInfo = ^ TComInfo;
  TComInfo = record
  RecordSize: DWORD; // Размер структуры, байт
  Port: BYTE; // Номер порта. 1 - COM1 и т.д.
  BaudRate: DWORD; // Скорость обмена
  WaitPortTimeout: DWORD; // Время ожидания доступности порта, мс
  ReadTotalTimeout: DWORD; // Время ожидания ответа считывателя, мс
  ReadNextByteTimeout: DWORD; // Время ожидания поступления очередного
                              // байта при условии, что обнаружено начало
                              // валидного кадра, мс.
  end;

  type
  PProtocolInfo = ^ TProtocolInfo;
  TProtocolInfo = record
  DisableAddress: BOOLEAN; // Размер структуры, байт
  CheckMode: INTEGER; // Режим проверки контрольной суммы
  end;

var
  Form1: TForm1;

// набор импортируемых функций
  W_SetPortParams: procedure(PortCfgPtr: PComInfo); stdcall;
  W_SetProtocolParams: procedure(ProtocolInfoPtr: PProtocolInfo); stdcall;
  W_IO: function(Address, Cmd: char;
                 BodyLen: integer;
                 const CmdBody;
                 var ReplyLen: integer;
                 var ReplyBuffer): char; stdcall;

  LibHandle: THandle;
  implementation

{$R *.dfm}

{ TForm1 }

{ TForm1 }

function TForm1.LinkProc(ProcName: string): Pointer;
begin
 try
  result:= GetProcAddress(LibHandle,PChar(ProcName));
  Win32Check(Assigned(Result))
 except end
end;

// Подключаем DLL....
procedure TForm1.FormCreate(Sender: TObject);
begin
  LibHandle:= LoadLibrary('dll/ProX232.dll');
  Win32Check(LibHandle<>0);
  W_SetPortParams:= LinkProc('W_SetPortParams');
  W_IO:= LinkProc('W_IO');
end;

// Устанавливаем параметры порта и создаем подключение....
procedure TForm1.Button1Click(Sender: TObject);
var
  t: TComInfo;
begin
  t.Port:= 3;
  t.BaudRate:= 115200;
  t.WaitPortTimeout:= 200;
  t.ReadTotalTimeout:= 100;
  t.ReadNextByteTimeout:= 50;
  t.RecordSize:= 21; // dword = 4 байтам
  W_SetPortParams(@t)
 end;

 // Устанавливаем параметры протакола....
procedure TForm1.Button2Click(Sender: TObject);
var
  Prot: TProtocolInfo;
begin
//Prot.DisableAddress:=00; // Размер структуры, байт
  Prot.CheckMode:=03; // Режим проверки контрольной суммы
  W_SetProtocolParams(@Prot)
end;

// Формирем и отправляем запрос....
procedure TForm1.Button3Click(Sender: TObject);
// Описываем константы....
Const
 REPLY_OK = #$0;
 REPLY_ACK = #$55;
var
// Выводим переменные....
   Ret:char;
   ReplyLen:integer;
   ReplyBuffer:Pointer;
begin
//определяем размер буфера и выделяем под него память....
   ReplyLen:=$FF;
   ReplyBuffer:=GetMemory(ReplyLen);
// Формируем и отправляем запрос....
   Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
   if Ret = REPLY_OK then
   begin
// Выводим ответ от считывателя...
      Edit1.Text:='Команда выполнена успешно, получены данные';
      Edit2.Text:=PChar(ReplyBuffer);// PChar(GetMemory(ReplyLen));
   end;
// Освобождаем память...
   FreeMemory(ReplyBuffer);
end;

end.

Не пойму несколько вещей.
1. Как правильно настроить параметры установки протакола
2. Почему при нажатии Button2 программа падает в ошибку"access violation at address"
3. Почему раньше параметры устанавливались, но как и сейчас прорамма падала в ошибку.

Последний раз редактировалось firmwares, 16.10.2012 в 01:46.
Ответить с цитированием
  #8  
Старый 16.10.2012, 03:06
firmwares firmwares вне форума
Прохожий
 
Регистрация: 30.06.2010
Сообщения: 6
Репутация: 10
По умолчанию

Привел обработчик Button2 к следующему виду.
Код:
 // Устанавливаем параметры протакола....
procedure TForm1.Button2Click(Sender: TObject);
var
  Prot: TProtocolInfo;
begin
  Prot.DisableAddress:=true; // Размер структуры, байт
  Prot.CheckMode:=03; // Режим проверки контрольной суммы
  W_SetProtocolParams(@Prot)
end;
Теперь параметрами можно спокойно управлять....

Вопрос по поводу "access violation at address" все еще открыт.
Не могу догнать почему это происходит.

И еще!
Если в запросе поставить
Код:
 Ret := W_IO(#$1, #$00, 0, '', @ReplyLen, ReplyBuffer);
А не
Код:
 Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
То компилятор ругается
[Error] Unit1.pas(120): Types of actual and formal var parameters must be identical


Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, SyncObjs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    function LinkProc(ProcName: string):Pointer;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  type
  PComInfo = ^ TComInfo;
  TComInfo = record
  RecordSize: DWORD; // Размер структуры, байт
  Port: BYTE; // Номер порта. 1 - COM1 и т.д.
  BaudRate: DWORD; // Скорость обмена
  WaitPortTimeout: DWORD; // Время ожидания доступности порта, мс
  ReadTotalTimeout: DWORD; // Время ожидания ответа считывателя, мс
  ReadNextByteTimeout: DWORD; // Время ожидания поступления очередного
                              // байта при условии, что обнаружено начало
                              // валидного кадра, мс.
  end;

  type
  PProtocolInfo = ^ TProtocolInfo;
  TProtocolInfo = record
  DisableAddress: BOOLEAN; // Размер структуры, байт
  CheckMode: INTEGER; // Режим проверки контрольной суммы
  end;
var
  Form1: TForm1;
// набор импортируемых функций
  W_SetPortParams: procedure(PortCfgPtr: PComInfo); stdcall;
  W_SetProtocolParams: procedure(ProtocolInfoPtr: PProtocolInfo); stdcall;
  W_IO: function(Address, Cmd: char;
                 BodyLen: integer;
                 const CmdBody;
                 var ReplyLen: integer;
                 var ReplyBuffer): char; stdcall;
  LibHandle: THandle;

  implementation

  {$R *.dfm}

{ TForm1 }

{ TForm1 }

function TForm1.LinkProc(ProcName: string): Pointer;
begin
  result:= GetProcAddress(LibHandle,PChar(ProcName));
end;

// Подключаем DLL....
procedure TForm1.FormCreate(Sender: TObject);
begin
  LibHandle:= LoadLibrary('dll/ProX232.dll');
  W_SetPortParams:= LinkProc('W_SetPortParams');
  W_SetProtocolParams:= LinkProc('W_SetProtocolParams');
  W_IO:= LinkProc('W_IO');
end;

// Устанавливаем параметры порта и создаем подключение....
procedure TForm1.Button1Click(Sender: TObject);
var
  t: TComInfo;
begin
  t.Port:= 3;
  t.BaudRate:= 115200;
  t.WaitPortTimeout:= 200;
  t.ReadTotalTimeout:= 100;
  t.ReadNextByteTimeout:= 50;
  t.RecordSize:= 21; // dword = 4 байтам
  W_SetPortParams(@t)
 end;

 // Устанавливаем параметры протакола....
procedure TForm1.Button2Click(Sender: TObject);
var
  Prot: TProtocolInfo;
begin
  Prot.DisableAddress:=true; // Размер структуры, байт
  Prot.CheckMode:=03; // Режим проверки контрольной суммы
  W_SetProtocolParams(@Prot)
end;

// Формирем и отправляем запрос....
procedure TForm1.Button3Click(Sender: TObject);
// Описываем константы....
Const
  REPLY_OK = #$0;
  REPLY_ACK = #$55;
var
// Выводим переменные....
  Ret:Char;
  ReplyLen:integer;
  ReplyBuffer:Pointer;
begin
//определяем размер буфера и выделяем под него память....
  ReplyLen:=255;
  ReplyBuffer:=GetMemory(ReplyLen);
// Формируем и отправляем запрос....
  Ret := W_IO(#$1, #$00, 0, '', @ReplyLen, ReplyBuffer);
 if Ret = REPLY_OK then
begin
// Выводим ответ от считывателя...
  Edit1.Text:='Команда выполнена успешно, получены данные';
  Edit2.Text:=PChar(ReplyBuffer);
end;
// Освобождаем память...
  FreeMemory(ReplyBuffer);
end;

end.
Ответить с цитированием
  #9  
Старый 16.10.2012, 20:01
Аватар для cotseec
cotseec cotseec вне форума
Активный
 
Регистрация: 16.07.2008
Сообщения: 353
Версия Delphi: D7,TDE06,RAD09
Репутация: 1443
По умолчанию

Цитата:
Вопрос по поводу "access violation at address" все еще открыт.
могу только пофантазировать...
судя по этому
Цитата:
Код:
type
  PProtocolInfo = ^ TProtocolInfo;
  TProtocolInfo = record
  DisableAddress: BOOLEAN; // Размер структуры, байт
  CheckMode: INTEGER; // Режим проверки контрольной суммы
  end;
и по тому, что хейдеры даны в С, типу bool в С соответсвует тип BOOL в Delphi и SizeOf(BOOL)>SizeOf(boolean) применяемому у вас, поэтому в dll происходила попытка чтения из невыдленной памяти при обращении к переменной типа TProtocolInfo (с учетом, что остальные типы членов структуры по крайней мере требуемого размера), как то так

Цитата:
И еще!
Если в запросе поставить
Код:1
Код:
Ret := W_IO(#$1, #$00, 0, '', @ReplyLen, ReplyBuffer);
А не
Код:1
Код:
Ret := W_IO(#$1, #$00, 0, '', ReplyLen, ReplyBuffer);
То компилятор ругается
[Error] Unit1.pas(120): Types of actual and formal var parameters must be identical
конечно он будет ругаться, ведь у вас функция определена как
Код:
  W_IO: function(Address, Cmd: char;
                 BodyLen: integer;
                 const CmdBody;
                 var ReplyLen: integer;
                 var ReplyBuffer): char; stdcall;
а вы пытаетесь закинуть ей параметры согласно моего определения, компилятор и выражает вам свое фи, дословно "типы актуальных и формальных параметров должны быть идентичны"
по поводу констант
Цитата:
Методы расчета контрольной суммы кадра
CHECK_NONE - 0х00 //Не проверять контрольную сумму кадра
CHECK_SUM - 0х01 //Использовать суммирование (1 байт)
CHECK_CRC16 - 0х02 //Использовать CRC16 (2 байта)
CHECK_FCS - 0х03 //Использовать FCS (2 байта)
это как раз константы одного члена структуры (записи) TProtocolInfo, а именно CheckMode: INTEGER;

З.Ы. задача по выводу ответа железки решена?
__________________
Понять, что хочет заказчик - бесценно, ведь он платит MasterCard

Последний раз редактировалось cotseec, 16.10.2012 в 20:07.
Ответить с цитированием
  #10  
Старый 16.10.2012, 20:29
firmwares firmwares вне форума
Прохожий
 
Регистрация: 30.06.2010
Сообщения: 6
Репутация: 10
По умолчанию

Цитата:
З.Ы. задача по выводу ответа железки решена?
К сожалению да. с "access violation at address" так и не разобрася.

Уважаемый cotseec, вы говорили, что
Цитата:
З.Ы.Ы.Ы а может проще написать свой класс работы с СОМ портом, тем более протокол известен, кто знает какие там ошибки в dll а так, если не работает - сам дурак

Не могли бы Вы рассказать об том поподробнее, может хоть с так получится.
Дело вот в чем:
Мне необходимо написать программу, которая будет висеть в трее или работать как служба.
Программа просто опрашывает считыватель на предмет поиска карты и как только видит карту считывает ее код.
Считав код, программа вписывает его там, где стоит курсор.

С эмуляцией клавиатуры думаю проблем не возникнет, а вот со считыванием даллых с ридера...... это проблема.
Я с этим считывателем долблюсь хрен знает сколько и ничего не получается.
Ответить с цитированием
  #11  
Старый 16.10.2012, 22:12
Аватар для cotseec
cotseec cotseec вне форума
Активный
 
Регистрация: 16.07.2008
Сообщения: 353
Версия Delphi: D7,TDE06,RAD09
Репутация: 1443
По умолчанию

проверьте личную почту на форуме
__________________
Понять, что хочет заказчик - бесценно, ведь он платит MasterCard
Ответить с цитированием
Этот пользователь сказал Спасибо cotseec за это полезное сообщение:
firmwares (19.10.2012)
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 16:46.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter