Интернет-магазин

Просмотр корзины
В корзине:

товаров - 0 шт.



§ 32. WoodmanUSB. Программа на Delphi и С++ WinAPI

Дмитрий Иванов, 09 Декабря 2013

Файлы к статье скачать
Имя: KA032.zip (ZIP архив)
Размер: 317 КБ

Здесь мы рассмотрим написание программы из прошлой статьи на языках Delphi и С++ но в чистом WinAPI варианте. Начнем, пожалуй, с Delphi. За основу я взял уже готовый проект для работы с портом PORTA модуля и добавил туда работу с потоками с учетом специфики Delphi. Внешне окно программы теперь имеет вид:

программирование USB

Обращаем внимание к коду, а именно к заголовку программы, где проводим подключение новых функций из библиотеки 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 а реализовать только операции открытия устройства и запуска / остановки записи данных. Управляющие элементы для запуска тех или иных операций реализованы в виде пунктов меню. Окно программы имеет следующий вид:

программирование USB

Код, пожалуй, комментировать не буду и представлю его 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



© KERNELCHIP 2006 - 2023