![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
|||
|
|||
|
Всем доброго времени суток.
Суть вот в чем: 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; Прошу, не пинайте, в работе с портами я ноль, а сделать необходимо. Всем заранее огромное спасибо за помощь. |
|
#2
|
||||
|
||||
|
Цитата:
Код:
char W_IO(char Address, char Cmd, int BodyLen, void *CmdBody, int *ReplyLen, void *ReplyBuffer); настройки порта в ini - это работа с ini, перед открытием порта читаем из ini, перед закрытием программы пишем в ini |
|
#3
|
|||
|
|||
|
Тоесть получается, что
Код:
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
|
||||
|
||||
|
у вас все вделано верно, почти
Цитата:
Код:
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;
т.к. Цитата:
Последний раз редактировалось cotseec, 14.10.2012 в 21:33. |
|
#5
|
|||
|
|||
|
Если запрос сформировать так:
Код:
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); Если сделать таким образом: Код:
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; Что я опять сделал не так? Привел запрос к следующму виду Код:
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; Если езменить 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; Последний раз редактировалось firmwares, 15.10.2012 в 07:16. |
|
#6
|
||||
|
||||
|
начнем сначала
прототип функции (в С) Цитата:
Цитата:
Код:
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;
для того, чтобы этот результат был в виде Цитата:
З.Ы. как вариант функция сама определяет ReplyBuffer и ReplyLen и все выделения памяти в программе не нужны, тогда как dll освобождает память после ее использования? З.Ы.Ы. или закручено еще круче: функция после своей работы выбрасывает по адресу ReplyLen длину необходимого ей буфера, а при следующем своем вызове заполняет его (или какой-то другой функцией), но это из области фантазий - нужно смотреть докуметацию или коментарии к библиотеке, если таковые есть З.Ы.Ы.Ы а может проще написать свой класс работы с СОМ портом, тем более протокол известен, кто знает какие там ошибки в dll а так, если не работает - сам дурак ![]() Последний раз редактировалось cotseec, 15.10.2012 в 10:42. |