§ 32. WoodmanUSB. Программа на Delphi и С++ WinAPI
|
Дмитрий Иванов, 09 Декабря 2013
|
|
Файлы к статье скачать
|
Имя: KA032.zip (ZIP архив) |
Размер: 317 КБ |
|
Здесь мы рассмотрим написание программы из прошлой статьи на языках Delphi и С++ но в чистом WinAPI варианте. Начнем, пожалуй, с Delphi. За основу я взял уже готовый проект для работы с портом PORTA модуля и добавил туда работу с потоками с учетом специфики Delphi. Внешне окно программы теперь имеет вид:

Обращаем внимание к коду, а именно к заголовку программы, где проводим подключение новых функций из библиотеки WUSBdrv.dll. Также проводим объявление потокой функции ThreadCalc(), в рамках которой будет "крутится" задача отправки данных в модуль.
function WUSB_SetupPortB(params: Byte):Longint; cdecl; external 'WUSBdrv.dll';
function WUSB_WritePortB(buf: Pointer; bufsize: Longword; dwWrite: Pointer):Longint; cdecl; external 'WUSBdrv.dll';
function ThreadCalc(P : Pointer) : LongInt; stdcall;
Объявляем две глобальные переменные, назначение которых нам знакомо из прошлой статьи - одна для управления процессом запуска / остановки записи данных, другая - счетчик записанных байт данных.
var
Form1: TForm1;
Terminate: Boolean;
ByteCounter: LongInt;
Переходим сразу к обработчику на нажатие кнопки Write. Проводим сброс счетчиков и с помощью Win API функции CreateThread() запускаем новый программный поток, который будет выполняться в рамках потоковой функции ThreadCalc(), адрес на которую мы и передаем в качестве одного из параметров для CreateThread().
procedure TForm1.Button5Click(Sender: TObject);
var
hThread: THandle;
ThreadId : DWord;
begin
Terminate := FALSE;
ByteCounter := 0;
Label6.Caption := '0';
hThread := CreateThread(nil,0,@ThreadCalc,nil,0,ThreadId);
end;
А вот и код потоковой функции. Сначала проводим инициализацию режима работы порта PORTB. В качестве параметра передаем HEX значение 0x1D - именно такому числу соответсвует ASYNC_MODE (см. файл WUSBdrv.h). Если операция не удалась (схему, напрмер, к USB не подключили) получим соответсвующее предупрежедение (и "упавшую программу", т.к. дальнейший обработки такой ошибки я в этой тестовой программе не провожу). Затем заполняем буфер данными. Стартуем "бесконечный" цикл. В нем проводим запись данных с помощью функции WUSB_WritePortB(). Проверяем код возврата и если он "не хороший", обрываем цикл. В конце каждого прохода цикла обновляем значение записанных байт данных.
function ThreadCalc(P : Pointer) : LongInt; stdcall;
var
status: Longint;
buf:array[0..255] of ShortInt;
dwWrite: Longword;
i: Longint;
begin
status := WUSB_SetupPortB($1D);
if status = 0 then
begin
MessageDlg('Setup Error', mtInformation, [mbOK], 0);
end;
for i := 0 to 255 do
buf[i]:= i;
while Terminate = FALSE do
begin
status := WUSB_WritePortB(@buf, 256, @dwWrite);
if status = 0 then
begin
MessageDlg('Write Error', mtInformation, [mbOK], 0);
Terminate := TRUE;
end;
if status = 2 then
begin
MessageDlg('TIME_OUT Event', mtInformation, [mbOK], 0);
Terminate := TRUE;
end;
ByteCounter := ByteCounter + dwWrite;
end;
end;
Ну и наконец, простенький обработчик кнопки Stop. Устанавливаем флаг остановки записи в активное состояние и показываем на окне число записанных байт данных за текущую сессию.
procedure TForm1.Button6Click(Sender: TObject);
begin
Terminate := TRUE;
Label6.Caption := IntToStr(ByteCounter);
end;
А теперь рассмотрим реализацию записи данных на языке С++, но в чистом WinAPI варианте.
В этом примере я позволю себе немного его упростить и убрать работу с портом PORTA а реализовать только операции открытия устройства и запуска / остановки записи данных. Управляющие элементы для запуска тех или иных операций реализованы в виде пунктов меню. Окно программы имеет следующий вид:

Код, пожалуй, комментировать не буду и представлю его as it is (как есть), ибо все процедуры я уже несколько раз объяснял для двух предыдущих программ, а здесь нового ни чего не прибавилось, кроме некоторой API специфики, но к операции записи данных она имеет отдаленное отношение.
#include <windows.h>
#include "resource.h"
#include <stdio.h>
#include "WUSBdrv.h"
DWORD WINAPI WriteRoutine(void* param);
int ByteCounter;
bool Terminate;
//***************************************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR szCmdLine, int iCmdShow)
{
char szAppName[]="MyProc";
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.lpszClassName = szAppName;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = (LPCSTR)IDR_MENU1;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
RegisterClassEx(&wndclass);
hwnd = CreateWindow(szAppName, "Test WUSB", WS_OVERLAPPEDWINDOW,
100, 100, 300, 200, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
int wmId, wmEvent;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case ID_OPEN:
{
//***************************************************
//******************** WUSB *************************
int status = WUSB_Open();
if(status == WUSB_ERROR)
{
MessageBox(NULL, "ERROR! Can`t open WodmanUSB device", "Info", MB_ICONERROR);
}
else
{
MessageBox(NULL, "Open OK", "Info", MB_ICONINFORMATION);
}
//***************************************************
break;
}
case ID_START:
{
//***************************************************
//******************** WUSB *************************
HANDLE hThread;
DWORD dwIDThread;
ByteCounter = 0;
Terminate = false;
hThread = CreateThread(NULL, 0, WriteRoutine, NULL, 0, &dwIDThread);
//***************************************************
break;
}
case ID_STOP:
{
//***************************************************
//******************** WUSB *************************
Terminate = true;
char str[20];
sprintf(str, "Write: %d byte", ByteCounter);
MessageBox(NULL, str, "Info", MB_ICONINFORMATION);
//***************************************************
break;
}
}
break;
case WM_PAINT:
{
hdc=BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//***************************************************
//******************** WUSB *************************
DWORD WINAPI WriteRoutine(void* param)
{
WUSB_SetupPortB(ASYNC_MODE);
char buf[256];
for(int i = 0; i < sizeof(buf); i++)
{
buf[i] = i;
}
unsigned int dwWrite;
int status;
while(!Terminate)
{
status = WUSB_WritePortB(buf, sizeof(buf), &dwWrite);
if(status == WUSB_ERROR)
{
MessageBox(NULL, "Write Error!", "", MB_ICONERROR);
break;
}
else if(status == WUSB_TIMEOUT)
{
MessageBox(NULL, "TIMEOUT", "", MB_ICONERROR);
break;
}
ByteCounter += dwWrite;
}
return 0;
}
//***************************************************
На этом рассмотрение основ записи данных из ПК в модуль WoodmanUSB в асинхронном режиме я пожалуй закончу. В дальнейшем нас еще ждет знакомство с другими режимами записи и получение максимальных скоростей передачи. А пока, переходим к основам чтения данных из модуля в ПК. Именно этому будет посвящены ряд следующих статей.
© Дмитрий Иванов
09 Декабря 2013 года
http://www.kernelchip.ru