로그인 | 회원가입
   이용안내    장바구니    주문조회    마이쇼핑    게시판
상품검색 검색 
아이디  
비밀번호
보안접속 보안접속
회원가입
  아이디찾기
  비밀번호찾기
상품목록
  ARM
  PIC
  AVR
  DSP
  MAXQ
  MSP430
  OTHER
게시판
공지사항
자유게시판
강좌-USB기타
자료실
샘플 기획전
전화: 031-429-0845
팩스: 031-477-1407
운영시간
  09:00 ~ 18:00
 
현재위치: > 게시판 > 강좌-USB기타
강좌-USB기타
USB및 기타자료입니다.


찾기
제목 USB 디바이스와 통신하기 위한 어플리케이션 작성 2/2 0  추천하기
작성자 글쓴이 작성일 2014-10-29 16:22:33 조회수 524
   
   

강좌의 이번 회는 USB 디바이스와 통신하기 위한 윈도우 어플리케이션 작성법에 관한 것이다.

 

본좌는 MFC를 이용해서 Dialog Base의 어플리케이션을 작성하는 방법을 예로 들어 보여줄 것이다.

하지만 앞부분에 설명할

MFC Wizard를 사용해서 프로젝트를 생성하는 절차를 제외한 나머지 부분은

WinAPI로 윈도우 프로그래밍을 하던, 콘솔모드의 프로그램을 짜던

MS 윈도우에서 돌아가는 프로그램이라면 다 동일한 것이므로 알아서 참조하기 바란다.

 

 

먼저 Visual Studio를 실행시킨다. (본좌는 VC++ 6.0을 쓴다.)

 

 

먼저 프로젝트를 생성하기 위해 메뉴의 File → New 를 누르면 다름과 같은 창이 뜬다.

Project 탭을 선택한 후에,

MFC App Wizard(exe)를 선택하고

프로젝트 이름과 저장될 위치를 선택하고

OK 버튼을 누른다.

 

 

Application Type을 Dialog Based로 바꾸고 NEXT 버튼을 누른다.

 

 

About Box의 체크버튼을 해제하고,

( 안 해도 상관은 없다. 쓸데 없는 코드가 추가되는 걸 막기 위해 해제할 뿐이다. )

Dialog Title을 입력한다.

( 그냥 놔둬도 된다. 이 문자열이 프로그램 타이틀 바 좌측에 보여지는 문자열이다. )

NEXT 버튼을 누른다.

 

 

그냥 NEXT 버튼을 클릭한다.

 

 

FINISH 버튼을 누르면 MFC Wizard가 소스코드를 생성한다.

(다음에 나오는 Report 창은 OK를 눌러 그냥 닫는다.)

 

만들어진 프로젝트

 

 

이제 LED를 키고 끌 버튼을 추가해 보자.

먼저 “TODO …”하는 문자열과 “취소” 버튼은 필요 없으므로 지운다.

그리고 "확인" 버튼을 선택하고, 오른버튼을 클릭해서 "Property"에서 이름을 "확인"에서  "종료"로 바꾸어 준다.

 

그리고 버튼을 하나 추가한다.

 

 

버튼을 선택하고 오른버튼→Property를 선택해 버튼 ID와 이름을 바꾸어 주자.

 

 

Property 편집창을 닫은 후에 버튼을 더블 클릭하면

버튼이 눌렸을 때 실행되는 멤버함수를 추가 할 수 있다.

 

 

위에서 OK를 누르면 이제 코딩할 준비가 끝난 것이다.

반전된 주석문은 지워 버리자.

 

 

위에서 파일을 다운받고 압축을 풀어 5개의 다음 파일들을 프로젝트 폴더 안에 복사해 넣는다.

usb100.h

usbdi.h

usbioctl.h

usbiodef.h

wdm.h

 

 

그리고 나서 위에서 복사한 파일들을 Project에 추가해 준다.

 

 

그리고, 메뉴의 File→New를 눌러 Files 탭에서 “C/C++ Header Files”를 선택하고,

파일 이름으로 UniFullUsr를 입력한 후에 OK 버튼을 누르면

프로젝트에 헤더파일이 하나 추가된다.

이 파일이 어플리케이션과 드라이버가 합의한 인터페이스를 정의할 헤더 파일이 되겠다.

 

 

여기에 다음 내용을 복사해 집어 넣자.

#ifndef _UNIFULL_USR_H

#define _UNIFULL_USR_H

 

#include <initguid.h>

#include <winioctl.h>

 

// {1CC20EBB-27D8-4a87-8E44-4EE11340A74D}

DEFINE_GUID( GUID_CLASS_UNIFULL_TEST, 0x98001a9a, 0x12e3, 0x4e8c, 0xad, 0x55, 0x26, 0xa8, 0xb9, 0x23, 0x9b, 0xc3);

 

#define DEFAULT_CONTROL_PIPE    NULL

 

#define UNIFULL_IOCTL_INDEX     0x0000

 

#define IOCTL_UNIFULL_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN, UNIFULL_IOCTL_INDEX, METHOD_BUFFERED, FILE_ANY_ACCESS )

#define IOCTL_UNIFULL_RESET_DEVICE          

 

CTL_CODE(FILE_DEVICE_UNKNOWN, UNIFULL_IOCTL_INDEX+1, METHOD_BUFFERED, FILE_ANY_ACCESS )

#define IOCTL_UNIFULL_RESET_PIPE            CTL_CODE(FILE_DEVICE_UNKNOWN, UNIFULL_IOCTL_INDEX+2, METHOD_BUFFERED, FILE_ANY_ACCESS )

#define IOCTL_UNIFULL_LED_ON                CTL_CODE(FILE_DEVICE_UNKNOWN, UNIFULL_IOCTL_INDEX+4, METHOD_BUFFERED, FILE_ANY_ACCESS )

#define IOCTL_UNIFULL_LED_OFF               CTL_CODE(FILE_DEVICE_UNKNOWN, UNIFULL_IOCTL_INDEX+5, METHOD_BUFFERED, FILE_ANY_ACCESS )

 

 

typedef struct _CONTROL_REQUST

{

    USHORT usValue;

    USHORT usIndex;

    USHORT usLength;

    USHORT Reserved;

        PVOID pvBuffer;

    UCHAR ulBufferLength;

} CONTROL_REQUST, *PCONTROL_REQUST;

 

#endif

DEFINE_GUID… 요 부분이 드라이버의 “이름”이오,

#define IOCTL_UNIFULL_LED_ON/OFF… 이 부분이 “목록”이다.

LED_”ON/OFF”를 제외한 나머지 IOCTL_UNIFULL_는 이번에 작성할 UniFull Test Application에서는 지원하지 않을 내용이다.

지우기 귀찮아서 그냥 냅뒀다.

 

 

UniFullUsr.h를 다 작성했으면

이제 UniFullDlg.cpp에 코드를 추가해야 한다.

추가하는 코드는 몽조리 다 디바이스의 Handle을 얻기 위한 OpenFile을 호출하기 위한 코드 들이다.

( OpenFile에서 궁극적으로 CreateFile을 호출한다는 말을 본좌가 했었나? 응?. 흠~ 치매다. )

 

 

OpenFile()에서 호출하는 다음 함수들의 원형을 UniFullDlg.cpp의 앞부분에 추가해 준다.

위치는 대충

#ifdef _DEBUG

#endif

뒤 쪽에다 넣으시라.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Copy Code From Here for Driver Interface (Get Device Handle)                                          */

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

HANDLE OpenFile(IN PCHAR pcPipeName);

BOOL GetUsbDeviceFileName(LPGUID pGuid, PCHAR pszName);

HANDLE OpenUsbDevice(LPGUID pGuid, PCHAR pszName);

HANDLE OpenOneDevice(IN HDEVINFO HardwareDeviceInfo, IN PSP_INTERFACE_DEVICE_DATA DeviceInfoData, IN PCHAR pszDevName);

 

CHAR szCompleteDeviceName[256];

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Copy Code To Here                                                                                                             */

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 

그리고 이 함수들을 위해서는 이전에 프로젝트 폴더에 추가했던 헤더파일도 including 시켜야 한다.

맨 앞부분 include… 뒤에 다음의 코드를 추가해 준다.

#include "usbdi.h"

#include <setupapi.h>

 

 

그 외에 메뉴의 “Project”->”Settings”->”Link” 탭을 클릭해서,

“Object/Library Modules”항목에 “setupapi.lib”를 추가해 주어야 한다.

이 setupapi.lib 파일 역시

프로젝트 내에서 호출하는 함수들을 위한 라이브러리 이다.

빨간 선으로 표시한 부분이 본좌처럼 “Win32 Debug”로 되어 있다면,

이 것을 “Win32 Release” 또는 “All Configurations”로 바꾸어 준 뒤

“Object/Library Modules”항목에 “setupapi.lib”를 추가해 주는 정도의 센.스.는 있어야 하겠다.

안 그럼 릴리즈 버전의 EXE파일을 생성할 때,

링크에러가 떵 하니 나타나버리고 말 것이기 때문이다.

 

 

그 아래에 전역변수

CHAR szCompleteDeviceName[256];

추가를 추가 해 주어라.

이 역시 디바이스의 Handle을 얻기 위해 필요한 변수이다.

 

 

그리고 마우스를 쭉 끌어 맨 밑으로 가서

위에 선언한 함수원형에 해당하는 함수 본체들을복사해 준다.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Copy Code From Here for Driver Interface (Get Device Handle)                                             */

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

HANDLE OpenFile(IN PCHAR pcPipeName)

{

    INT Success = 1;

    HANDLE h;

 

    if ( !GetUsbDeviceFileName( (LPGUID) &GUID_CLASS_UNIFULL_TEST, szCompleteDeviceName) ) return INVALID_HANDLE_VALUE;

 

    if( pcPipeName )

    {

        strcat ( szCompleteDeviceName, "\\" );

 

        strcat ( szCompleteDeviceName, pcPipeName );

    }

 

    h = CreateFile ( szCompleteDeviceName,

                    GENERIC_WRITE | GENERIC_READ,

                    FILE_SHARE_WRITE | FILE_SHARE_READ,

                    NULL,

                    OPEN_EXISTING,

                    0,

                    NULL );

 

    return h;

}

 

BOOL GetUsbDeviceFileName(LPGUID pGuid, PCHAR pszName)

{

    HANDLE hDev = OpenUsbDevice ( pGuid, pszName );

 

    if ( hDev != INVALID_HANDLE_VALUE )

    {

        CloseHandle( hDev );

        return TRUE;

    }

 

    return FALSE;

}

 

HANDLE OpenUsbDevice(LPGUID pGuid, PCHAR pszName)

{

   ULONG NumberDevices;

   HANDLE hOut = INVALID_HANDLE_VALUE;

   HDEVINFO                 hardwareDeviceInfo;

   SP_INTERFACE_DEVICE_DATA deviceInfoData;

   ULONG                    i;

   BOOLEAN                  done;

   PUSB_DEVICE_DESCRIPTOR   usbDeviceInst;

   PUSB_DEVICE_DESCRIPTOR   *UsbDevices = &usbDeviceInst;

 

   *UsbDevices = NULL;

   NumberDevices = 0;

 

   // Open a handle to the plug and play dev node.

   // SetupDiGetClassDevs() returns a device information set that contains info on all

   // installed devices of a specified class.

   hardwareDeviceInfo = SetupDiGetClassDevs ( pGuid,

                                              NULL, // Define no enumerator (global)

                                              NULL, // Define no

                                              (DIGCF_PRESENT | // Only Devices present

                                              DIGCF_INTERFACEDEVICE)); // Function class devices.

 

   // Take a wild guess at the number of devices we have;

   // Be prepared to realloc and retry if there are more than we guessed

   NumberDevices = 4;

   done = FALSE;

   deviceInfoData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);

 

   i=0;

   while ( !done )

   {

      NumberDevices *= 2;

 

      if ( *UsbDevices )

      {

         *UsbDevices = (PUSB_DEVICE_DESCRIPTOR) realloc ( *UsbDevices, (NumberDevices * sizeof (USB_DEVICE_DESCRIPTOR)) );

      }

      else

      {

         *UsbDevices = (PUSB_DEVICE_DESCRIPTOR) calloc ( NumberDevices, sizeof (USB_DEVICE_DESCRIPTOR) );

      }

 

      if ( NULL == *UsbDevices )

      {

 

         // SetupDiDestroyDeviceInfoList destroys a device information set

         // and frees all associated memory.

         SetupDiDestroyDeviceInfoList ( hardwareDeviceInfo );

         return INVALID_HANDLE_VALUE;

      }

 

      usbDeviceInst = *UsbDevices + i;

 

      for ( ; i < NumberDevices; i++ )

      {

 

         // SetupDiEnumDeviceInterfaces() returns information about device interfaces

         // exposed by one or more devices. Each call returns information about one interface;

         // the routine can be called repeatedly to get information about several interfaces

         // exposed by one or more devices.

         if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,

                                         0, // We don't care about specific PDOs

                                         pGuid,

                                         i,

                                         &deviceInfoData))

         {

 

            hOut = OpenOneDevice (hardwareDeviceInfo, &deviceInfoData, pszName);

            if ( hOut != INVALID_HANDLE_VALUE )

            {

               done = TRUE;

               break;

            }

         }

         else

         {

            if ( ERROR_NO_MORE_ITEMS == GetLastError() )

            {

               done = TRUE;

               break;

            }

         }

      }

   }

 

   NumberDevices = i;

 

   // SetupDiDestroyDeviceInfoList() destroys a device information set

   // and frees all associated memory.

   SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);

   free ( *UsbDevices );

   return hOut;

}

 

HANDLE OpenOneDevice(IN HDEVINFO HardwareDeviceInfo, IN PSP_INTERFACE_DEVICE_DATA DeviceInfoData, IN PCHAR pszDevName)

{

    PSP_INTERFACE_DEVICE_DETAIL_DATA     functionClassDeviceData = NULL;

    ULONG                                predictedLength = 0;

    ULONG                                requiredLength = 0;

    HANDLE                               hOut = INVALID_HANDLE_VALUE;

 

    //

    // allocate a function class device data structure to receive the

    // goods about this particular device.

    //

    SetupDiGetInterfaceDeviceDetail ( HardwareDeviceInfo,

                                      DeviceInfoData,

                                      NULL, // probing so no output buffer yet

                                      0, // probing so output buffer length of zero

                                      &requiredLength,

                                      NULL ); // not interested in the specific dev-node

 

 

    predictedLength = requiredLength;

    // sizeof (SP_FNCLASS_DEVICE_DATA) + 512;

 

    functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc (predictedLength);

    functionClassDeviceData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);

 

    //

    // Retrieve the information from Plug and Play.

    //

    if (! SetupDiGetInterfaceDeviceDetail ( HardwareDeviceInfo,

                                           DeviceInfoData,

                                           functionClassDeviceData,

                                           predictedLength,

                                           &requiredLength,

                                           NULL) )

    {

        free ( functionClassDeviceData );

        return INVALID_HANDLE_VALUE;

    }

 

    strcpy ( pszDevName,functionClassDeviceData->DevicePath ) ;

 

    hOut = CreateFile ( functionClassDeviceData->DevicePath,

                        GENERIC_READ | GENERIC_WRITE,

                        FILE_SHARE_READ | FILE_SHARE_WRITE,

                        NULL, // no SECURITY_ATTRIBUTES structure

                        OPEN_EXISTING, // No special create flags

                        0, // No special attributes

                        NULL ); // No template file

 

    free ( functionClassDeviceData );

    return hOut;

}

 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Copy Code To Here                                                                                         */

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

파일을 다운받고 5개의 파일들을 프로젝트 폴더 안에 복사해 넣는것부터 시작하는 이 일련의 절차들은

행자들이 디바이스를 제어하는 어플리케이션을 작성하기 위해서는

기계적으로 Copy&Paste 신공을 구사해야 하는 대상이다.

이해? 이런 거 필요 없다.

딱 5초 준다. 존내 클릭하는 거다.

 

그래서 본좌가

같다 붙이기 쉬우라고

szCompleteDeviceName 전역변수와 네 개의 함수들을

멤버변수와 멤버함수로 안 만들고

기냥 같다 붙인 것이다.

 

본좌는

위의 변수와 함수들을 하나로 묶어 하나의 클래스로 만들어 쓰지만

클래스가 뭐시어라?

하는 행자들도 분명히 있을 것이기에

기냥 평범한 함수로 같다 붙였다.

(이러나 저러나 모냥만 다를 뿐, 하는 일은 같으므로 신경 쓰지 말자.)

 

본좌도 예전에 위 함수들이 어떤 동작을 하는지

한번 분석해 보고 난 뒤,

그 이후부터는 그냥 기계적으로 복사해서 쓴다.

이젠 이 함수들이 어떤 짓을 하는지 기억조차 안난다.

시간이 남아도는 행자들은 MSDN Library를 참조해서 코드를 함 분석해 보고,

귀차니즘을 추구하는 행자들은 냅따 Copy&Paste 하시라.

 

 

이제까지 OnButtonLED()에서 디바이스의 Handle을 얻기 위해 호출할 OpenFile()을 위해

이것 저것 잡다구레한 일을 마쳤으니,

OpenFile()을 호출해서 Handle을 얻고,

DeviceIoControl()을 호출해 디바이스에게 작업을 내려 보내고,

작업이 끝났으면 CloseHandle()을 호출해서 Handle을 반환할 차례이다.

이 것들이 바로 OnButtonLED()에 들어 있는 다음 내용이다.

    BOOL bRet = FALSE;

    HANDLE hFile = INVALID_HANDLE_VALUE;

    DWORD dwBytesReturned=0;

    static LONG lLed = IOCTL_UNIFULL_LED_OFF;

 

    lLed = (lLed == IOCTL_UNIFULL_LED_OFF)? IOCTL_UNIFULL_LED_ON : IOCTL_UNIFULL_LED_OFF;

 

    hFile = OpenFile( DEFAULT_CONTROL_PIPE );

 

    if( INVALID_HANDLE_VALUE != hFile )

    {

        bRet = DeviceIoControl( hFile,

                               lLed,

                               NULL,

                               0,

                               NULL,

                               0,

                               &dwBytesReturned,

                               NULL );

 

        CloseHandle( hFile );

    }

 

요기까지가 바로 앞 강의에서 다운 받았던 UniFull App v1.0을 만들었던 절차이다.

행자들 스스로 Application을 작성할 때 참조하길 바란다.

댓글달기 회원에게만 댓글 작성 권한이 있습니다. 회원가입하여 정보공유를 하면 좋겠습니다.
첨부파일
답변
  스팸신고 스팸해제
글쓰기
 
이전글 USB 디바이스와 통신하기 위한 어플리케이션 작성 1/2
다음글 UniFull 펌웨어 v1.1 - Default Control Endpoint 를 이용한 LED On/Off
 
 
| 회사소개 | 이용약관 | 개인정보취급방침 | 이용안내
Copyright ⓒ 2010 KitKorea All rights reserved.
전화 : 031-429-0845 FAX : 031-477-1407
Contact open@kitkorea.com for more information.
법인명(상호):인터전자 주식회사 주소:14120 경기도 안양시 동안구 흥안대로 112-1 (호계동)
사업자 등록번호 안내 [138-81-28277] / 통신판매업 신고 제 안양 1753호 [사업자정보확인]
개인정보보호책임자 :홍성호(open@kitkorea.com) / 대표자(성명):홍성호
cafe24