#include<windows.h>
#define ID_WRITE 100
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
DWORD WINAPI MechaRead(LPVOID NotUse);

HINSTANCE g_hInst;
HWND HWndMain;
LPCTSTR lpszClass=TEXT("메카트로닉스");
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
           ,LPSTR lpszCmdParam,int nCmdShow)
{
  HWND hWnd;
  MSG Message;
  WNDCLASS WndClass;
  g_hInst = hInstance;

  WndClass.cbClsExtra=0;
  WndClass.cbWndExtra=0;
  WndClass.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
  WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
  WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  WndClass.hInstance=hInstance;
  WndClass.lpfnWndProc=WndProc;
  WndClass.lpszClassName=lpszClass;
  WndClass.lpszMenuName=NULL;
  WndClass.style=CS_HREDRAW | CS_VREDRAW;
  RegisterClass(&WndClass);

  hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
    NULL,(HMENU)NULL,hInstance,NULL);
  ShowWindow(hWnd,nCmdShow);

  while(GetMessage(&Message,NULL,0,0)){
    TranslateMessage(&Message);
    DispatchMessage(&Message);
  }
  return (int)Message.wParam;
}
//위 까지는 기본적인 API 메인 부분이다
HWND  PrintWnd,WriteWnd,WriteWnd2;//각종 컨트롤들의 제어를 위한 핸들러
HANDLE  hComm;//통신을 위해 사용할 포트 핸들러를 저장할 변수
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
  HDC        hdc;
  PAINTSTRUCT    ps;
  DWORD      dwWritten;//포트를 열고 읽을 때 사용할 변수로 얼마나 읽고 썼는지를 담을 변수
  DCB        sPState;//시리얼 통신포트 설정을 위한 구조체
  const char    *ucpData = "TEST ";//테스트용으로 사용할 전송 메시지
  DWORD      ThreadID;//스레드 생성시 얻어지는 아이디
  static HANDLE  hThread;//스레드 핸들러
 
COMMTIMEOUTS  cTime; //타임아웃 구조체(통신의 지연시간 대기시간 등등)
  TCHAR Buff[256];//버퍼로 사용할 공간
  int len;//문자열의 길이를 담을 변수
  switch(iMessage)
  {
  case WM_CREATE:
    HWndMain = hWnd;

//전송이나 수신에 사용할 에디터창을 생성하고 핸들러를 리턴 받고있다.
    CreateWindow(TEXT("static"),TEXT("전송받은 문자"),WS_CHILD|WS_VISIBLE,30,10,100,25,hWnd,(HMENU)-1,g_hInst,NULL);
    CreateWindow(TEXT("static"),TEXT("수신한 문자"),WS_CHILD|WS_VISIBLE,260,10,100,25,hWnd,(HMENU)-1,g_hInst,NULL);
    CreateWindow(TEXT("static"),TEXT("수신할 문자"),WS_CHILD|WS_VISIBLE,330,260,100,25,hWnd,(HMENU)-1,g_hInst,NULL);
    PrintWnd  = CreateWindow(TEXT("edit"), NULL, WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
      20, 40, 200, 200, hWnd, (HMENU)-1, g_hInst, NULL);
    WriteWnd2  = CreateWindow(TEXT("edit"), NULL, WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
      260, 40, 200, 200, hWnd, (HMENU)-1, g_hInst, NULL);
    WriteWnd  = CreateWindow(TEXT("edit"), NULL, WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
      20,260, 300, 25, hWnd, (HMENU)ID_WRITE, g_hInst, NULL);
//포트를 열고 핸들러를 리턴 받는다.
    hComm = CreateFile(TEXT("COM7"),GENERIC_READ | GENERIC_WRITE, 0 , NULL, OPEN_EXISTING, 0,0);
//오픈시 에러를 검출하고 있다. 에러라면 INVALID_HANDLE_VALUE(-1)이 리턴 된다.
    if(INVALID_HANDLE_VALUE == hComm)
    {
      MessageBox(hWnd, TEXT("포트 열 수 없음"), TEXT("ERROR"), MB_OK);
      DestroyWindow(hWnd);
      return 0;
    }
//4096 입력 버퍼 크기, 3096 츨력 버퍼 크기
    if(0 == SetupComm(hComm, 4096, 3096))         {
      MessageBox(hWnd, TEXT("버퍼 설정 에러"), TEXT("ERROR"), MB_OK);
      DestroyWindow(hWnd);
      return 0;
    }

//모든 출력을 중단하고 출력 버퍼 클리어 
    if( 0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))      {
      MessageBox(hWnd, TEXT("버퍼 초기화 에러"), TEXT("ERROR"), MB_OK);
      DestroyWindow(hWnd);
      return 0;
    }
//포트설정 구조체의 크기
    sPState.DCBlength = sizeof(sPState);
 //시리얼 포트 상태를 조사한다.
    if(0 == GetCommState(hComm, &sPState))       {
      MessageBox(hWnd, TEXT("시리얼 상태 읽기 에러"), TEXT("ERROR"), MB_OK);
      DestroyWindow(hWnd);
      return 0;
    }

//타임아웃 구조체를 설정 하고 있다.

//한문자를 수신한후 다음 문자가 수신될때까지 기다리는 시간 이시간이 지나면 버퍼를 리턴한다.
    cTime.ReadIntervalTimeout      = MAXDWORD;

    cTime.ReadTotalTimeoutMultiplier  = 0;//한문자를 수신하는데 걸리는 시간

//읽을 바이트수에 ReadTotalTimeoutMultiplier 값을 곱한 값에 ReadTotalTimeoutConstant값을 더해

//총 타임아웃시간을 구할수 있다.
    cTime.ReadTotalTimeoutConstant    = 0; 
    cTime.WriteTotalTimeoutMultiplier  = 0;
    cTime.WriteTotalTimeoutConstant    = 0;
    SetCommTimeouts(hComm, &cTime);
//보우율,전송비트,페리티모드,스탑비트등을 설정 한다.
    sPState.BaudRate  = CBR_115200;
    sPState.ByteSize  = 8;
    sPState.Parity    = NOPARITY;
    sPState.StopBits  = ONESTOPBIT;
//설정한 포트 값을 적용 시킨다.
    if( 0 == SetCommState(hComm, &sPState))   //시리얼 포트 상태를 조사
    {
      MessageBox(hWnd, TEXT("시리얼 상태 설정 에러"), TEXT("ERROR"), MB_OK);
      DestroyWindow(hWnd);
      return 0;
    }

//스레트를 생성한다. MechaRead 함수는 아래 정의 되어 있는 수신용 함수다
    hThread = CreateThread(NULL, 0, MechaRead, NULL, 0, &ThreadID);
    return 0;

  case WM_PAINT:
    hdc = BeginPaint(hWnd,&ps);
    EndPaint(hWnd,&ps);
    return 0;
  case WM_COMMAND:
    switch(LOWORD(wParam))//컨트롤에서 메시지가 오면
    {
    case ID_WRITE://전송 부분의 컨트롤의 메시지였다면
      switch(HIWORD(wParam))
      {
      case EN_CHANGE://에디트창의 문자열에 변화가 있었을 경우
        len = GetWindowText(WriteWnd,Buff,sizeof(Buff));//에디트창의 문자열을 읽어 들인다
        if (Buff[len-1]=='\n')//문자열의 마지막이 엔터일때까지 기다리다 엔터라면 전송을 시작한다.
        {
          Buff[len] = '\0';
          WriteFile(hComm, Buff,lstrlen(Buff),&dwWritten,0);//버퍼의 내용을 전송한다.
          if (!dwWritten)
          {
            MessageBox(hWnd,TEXT("전송 실패"),TEXT("실패"),MB_OK);
          }
          SetWindowText(WriteWnd,TEXT(""));//전송후 에디트창의 값을 리셋한다.

          //전송후 전송한 메시지를 다른 에디터창에 나타낸다.
          SendMessage(WriteWnd2, EM_REPLACESEL, (WPARAM)TRUE,(LPARAM)Buff);
        }
        break;
      }
      break;
    }
    return 0;
  case WM_LBUTTONDOWN:

//마우스 왼쪽 클릭시 테스트용 메시지를 전송한다.
    WriteFile(hComm, ucpData, (DWORD)strlen(ucpData),&dwWritten,0);
    return 0;

  case WM_DESTROY:
    CloseHandle(hThread);//생성한 스레드는 반드시 닫아준다
    CloseHandle(hComm);//오픈한 포트 역시 닫아 주어야 한다.
    PostQuitMessage(0);
    return 0;
  }
  return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
//스레드 함수의 원형은 반드시 아래와 같아야 한다.
DWORD WINAPI MechaRead(LPVOID NotUse)
{
  TCHAR  tt[3]={};
  DWORD  dwRead;

  while(1)
  {
    Sleep(50);//스레드 함수에서 과도한 CPU의 점유를 막기위해 잠시 잠들어 있게 한다.

//포트를 통해 전송된 문자를 읽어 들인다. 읽어들인 문자가 없어도 블러킹 되어 있지 않고 리턴한다.

//위에서 타임아웃 구조체를 설정해 주었기 때문에 블러킹 되지 않는것이다.
    ReadFile(hComm, tt,2,&dwRead,NULL);
    if(0 != dwRead)//전송된 문자가 있었다면
    {

//에디터창에 수신된 문자열을 출력한다.
      SendMessage(PrintWnd, EM_REPLACESEL, (WPARAM)TRUE,(LPARAM)tt);
    }
  }
}
 

Posted by 응이

Dream come true.
응이

달력

태그목록