티스토리 뷰

Hardware

IN Setup & 버튼(메시지) 받기

알 수 없는 사용자 2008. 4. 1. 01:16

출처 : http://muosys.egloos.com/193127

 

오늘은 Default Control Pipe를 이용하는 마지막 예제를 디벼보고, 버튼입력을 받는 것을 연습해 보자.

그 전에 잠깐. 이전에 다운 받은 예제 중에 UniHigh Application v2.1/v2.2내의 OnButtonLEDBllink()함수에서 파라메터(sizeof(PCONTROL_REQUEST))가 잘못 사용되었다.
이를 수정하여 다시 올렸으니 다운 받으시던지 아니면 그냥 아래의 정정된 예제를 참조하시든지 하시라.

이전 강의 Control Endpoint의 DATA stage 활용 - IN편에서는 IN Data Stage를 이용해서 디바이스로부터 호스트로 데이터를 전송하는 것을 설명하였었다.

이 예제들을 실험하기 위해서는 드라이버를 또 업데이트 해 주어야 한다.
바로 이전 강의를 참조하여 드라이버를 아래의 것으로 업데이트 해 주자.
UniHigh Driver v2.4

UniHigh App 소스코드의 Unihighusr.h에 보면 추가된 control code들을 볼 수 있다.

UniHigh Application v2.3 - Setup Stage를 이용한 IN Tranfer
UniHigh Application v2.4 - Button & Message 받기(IN Interrupt Transfer)

UniHigh Firmware v2.3
UniHigh Firmware v2.4

v2.4는 v2.3의 코드에 새 코드를 추가한 것이므로, v2.4만 다운받아도 된다.

v2.3은 이전 v1.3예제처럼 어플리케이션으로부터 두 값을 입력 받아서 이 값들의 곱을 FX2에서 계산 한 다음 IN Data Stage에 실어 다시 어플리케이션으로 값을 반환하는 예제이다.

OnButtonCalculate() 함수에서 모든 처리가 일어나는데, 이전의 DeicceIoControl의 사용과는 다른 점이 데이터를 받기 위해 다섯 번째와 여섯 번째 인자, 즉, LPVOID lpOutBuffer,와 DWORD nOutBufferSize,를 세팅해 주고 있다는 것이다.

그 이외에는 이전과 특별히 다른 점이 없으므로 행자들이 직접 코드를 디벼보면 별 어려움 없이 이해가 될 것이다.

다음은 디바이스에 있는 버튼이 눌렸을 때, 이를 어플리케이션으로 알리는 v2.4예제.
마찬가지로 UniHigh1.4.zip을 unihigh.sys에 맞추어 바꾼 것이다.

펌웨어는 이전과 마찬가지로 VID, PID만 바뀌었고, 회로도 이전 강의(버튼입력을 받아보자)과 같게 꾸미면 된다.
그 회로에서는 앞서 사용하던 LED 하나가 빠져 있는데, LED를 그냥 두고, 버튼회로만 추가해도 된다.

새로운 드라이버(UniHigh Driver v2.4)는 행자들이 이미 설치했을 것이고, 쫌 설명을 해야 할 것은 UniHigh Application v2.4이다.

기억을 거슬러 올라가서, 이전 강의(버튼입력을 받아보자)에서 우리가 버튼 입력을 받기 위해서 펌웨어 다운로드 -> Get Pipe버튼 누름 -> Pipe 0 선택 -> “Bulk/Int”버튼을 누름 이런 절차를 밟았다.
그런데 -> “Bulk/Int”버튼을 누르면 우리가 UniHigh 디바이스에 달린 버튼을 눌러서, 그 메시지가 EZ-USB Control Panel에 도착하기 전까지 어플리케이션이 잠시 얼어있는 것처럼 보이는데, 그 이유는 어플리케이션의 메인 쓰레드에서 버튼입력을 기다리기 때문이라고 설명 했었다.
기억 나시남?

버튼 입력을 받기 위해 메인 쓰레드를 홀딩 시킬 수는 없으므로, 우리는 이 기능을 위한 쓰레드를 하나 더 생성해야 한다.
UniHigh Application v2.4 프로젝트를 열어 보시라.
UniHighDlg.cpp의 마지막 부분에 있는 GetMsgThread(…)가 바로 버튼(메시지)입력을 받기 위한 쓰레드 본체이다.

OnInitDialog()에서 쓰레드를 시작하고,
m_bMsgThreadWorking = TRUE;
m_pGetMsgThread = AfxBeginThread( GetMsgThread, (LPVOID)this );

프로그램이 종료될 때 호출되는 OnClose에서 쓰레드를 종료한다.
m_bMsgThreadWorking = FALSE;

그리고, CUniHighDlg의 멤버함수인 MsgArrived는 디바이스로부터 버튼입력(메시지)이 도착했을 때 GetMsgThread에서 호출하는 함수이다.

GetMsgThread 내부를 살펴보면 이전의 DeviceIoControl과는 다르게 마지막 인자에 OVERLAPPED 구조체의 주소를 주고 있다.

이것은 이 쓰레드가 메시지가 도착하기 전까지는 pending 되어 있다가, 메시지가 도착했을 때, 이를 알려줄 이벤트를 위한 것이다.

Windows 프로그램을 잘 모르는 행자들를 위해 자세히 설명하려니 양도 만만치 않은게 본 강좌가 윈도우 프로그래밍강좌로 변질 될 것 같고, Windows 프로그램을 잘 아는 행자들을 위해 설렁설렁 설명하려니 다 아는거 리바이벌 밖에 더 되겠낭?

따라서 이 쓰레드 함수의 내부에 대한 설명은 생략한다. ㅋㅋㅋ
난 Windows 프로그램을 잘 모르는데 그래도 꼭 알아야 되겠다 라는 행자들은 Overlapped I/O에 관해 데브파이의 Visual C++ “강좌와 Tip”란을 디벼 보시거나 구글링 하시라.

UniHigh Application v2.4는 종료 시 쓰레드 땜에 메모리 leak이 날지도 모르겠다.
나중에 시간 나면 잡고, 안 나면 말자.
테스트하는 데는 별 지장 없다.

UniHigh Firmware v2.4를 살펴 보면 이전에 본좌가 얘기 했듯이 SendMessage 함수를 디버깅 용도로 사용한 예가 있다.

TD_Poll()함수를 잘 찾아 보시라.
이제 디버깅을 위한 LED 깜빡 신공으로부터 해방이닷.