Click here to Skip to main content
14,327,148 members
Rate this:
Please Sign up or sign in to vote.
I have written a Win API application. To read the Serial port Data. It was Work Fine in Console application without any trouble. When i try it on win32 gui application its dosent work fine some time it reads few chars only some time its read complete buffer...
Why its happens...

Those data i am sending from arduino by using "Serial.println("NM0");"
my code is written for the like below fromat:-
To read: 4(this is bytes to be read) -> NM0(This is data)

my out put shows like below

To read: 4 -> NM0

To read: 1 ->


To read: 4 -> NM1

To read: 1 ->


To read: 4 -> NM1

To read: 1 ->


To read: 2 -> NM

To read: 3 -> 0


To read: 4 -> NM0

To read: 1 ->


To read: 1 -> N

To read: 4 -> M0


To read: 1 -> N

To read: 4 -> M1


To read: 1 -> N

To read: 4 -> M1


To read: 4 -> NM0

To read: 1 ->


To read: 4 -> NM1

To read: 1 ->

What I have tried:

//----------------------Reading Port file..----------------------------

#pragma once

#include "stdafx.h"
#include <istream>
#include<ios>
#include <Windows.h>
#include <string>
#include <vector>
#include "myMonitor.h"
#include <sstream>

HANDLE hComm; // handel for the serial port
bool quit = false;
BOOL ConfigureSerialPort()
{
	// Setup Com Time Outs
	COMMTIMEOUTS TimeOuts = { 0 };
	TimeOuts.ReadIntervalTimeout = 1000; // Set Read Timeouts
	TimeOuts.ReadTotalTimeoutMultiplier = 500;
	TimeOuts.ReadTotalTimeoutConstant = 5000;
	TimeOuts.ReadIntervalTimeout = 1000;
	TimeOuts.WriteTotalTimeoutConstant = 2000; // Set Write Time Outs
	TimeOuts.WriteTotalTimeoutMultiplier = 500;

	if (!SetCommTimeouts(hComm, &TimeOuts))// Set Time Outs
	{
		myMonitor::sendTxt("\nERROR: Set Com time out faild.");
	};
	DCB dcb;

	if (!GetCommState(hComm, &dcb))
	{
		myMonitor::sendTxt("\nERROR: Get Comm state faild");
	}
	dcb.BaudRate = 9600; // Baud Rates
	dcb.ByteSize = 8;	// 8 bit per byte
	dcb.Parity = NOPARITY; // No Parity Bits
	dcb.StopBits = TWOSTOPBITS; //Two Stop Bits

	if (!SetCommState(hComm, &dcb))
	{
		myMonitor::sendTxt("\nERROR: Set Com State faild.");
		return true;
	}
	else
	{
		return false;
	}

	if (!PurgeComm(hComm, PURGE_TXCLEAR | PURGE_RXCLEAR))
	{
		myMonitor::sendTxt("\nERROR:  Comm Purge Faild.");
	}



}

BOOL OpenSerialPort(int portNo, int baud)
{
	hComm = CreateFile("\\\\.\\COM9", // COM Port
		GENERIC_READ | GENERIC_WRITE, // Configure for read and write
		0,
		NULL,
		OPEN_EXISTING, // Open existing without creating new 
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //Synchrnous Mode.
		NULL);
	if (hComm == (HANDLE)-1)
	{
		myMonitor::sendTxt("\nPort opend");
		return 0;
	}
	else
	{
		ConfigureSerialPort();
		return 1;
	}

}

BOOL  ReadSerialPort()
{
	char lpBuffer[256];
	DWORD dwBytesRead = 256; // read bytes
	COMSTAT ComStat;
	DWORD dwErrorFlag;
	OVERLAPPED m_osRead;
	stringstream ss;

	stringstream st;
	memset(&m_osRead, 0, sizeof(OVERLAPPED));
	m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	ClearCommError(hComm, &dwErrorFlag, &ComStat);
	dwBytesRead = min(dwBytesRead, (DWORD)ComStat.cbInQue);

	if (!dwBytesRead)return FALSE;

	BOOL bReadStatus;

	bReadStatus = ReadFile(hComm, lpBuffer, dwBytesRead, &dwBytesRead, &m_osRead);

	ss <<"To read: "<< (size_t)ComStat.cbInQue<<" -> ";

	for (size_t i = 0; i < (size_t)ComStat.cbInQue; i++)
	{
		if (i < sizeof(lpBuffer)) 
		{
			//printf("/n%c", lpBuffer[i]);
			ss << lpBuffer[i];
		}
	}
	
	myMonitor::sendTxt(ss.str());

	if (!bReadStatus) // if the Read File returns False
	{
		if (GetLastError() == ERROR_IO_PENDING)
		{
			WaitForSingleObject(m_osRead.hEvent, 2000);
			PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
			return dwBytesRead;
		}
		return 0;
	}
	PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

	memset(lpBuffer, 0, sizeof(lpBuffer));
	return dwBytesRead;
}


void readPort()
{
	while (!quit)
	{
		ReadSerialPort();
	}
}


///--------------------------------------------------------------------------------------
//----------------------Serial GUI app ------------------------------------------
// SerialHUB.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "SerialHUB.h"
#include <Windows.h>
#include "Init.h"
#include "myMonitor.h"
#include "Port.h"

#define MAX_LOADSTRING 100
#define IDC_BUTTION_OPEN_COMM 20003
#define IDC_BUTTION_CLOSE_COMM 20004
#define IDC_BUTTION_REFRESH 20005
#define IDC_CMBOX_PORT 20006
#define IDC_TXTBOX 20007
#define IDC_LBL_STATUS 20008

#define WNDOW_WIDTH 1000
#define WNDOW_HEIGHT 600
#define BTN_GAP (WNDOW_WIDTH-500)


HWND buttion_ConnectFSX;
HWND buttion_DisConnectFSX;
HWND buttion_OpenComm;
HWND buttion_CloseComm;
HWND buttion_Refresh;
HWND cbBox_Com;
HWND txtbox_Monitor;
HWND staticLable;

//Serial port Handle

HANDLE RxThread;
DWORD ThreadID;

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_SERIALHUB, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SERIALHUB));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SERIALHUB));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_SERIALHUB);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
   //hWnd = CreateWindowW(szWindowClass, (LPCWSTR)"CockpitX-MCP", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
	   //CW_USEDEFAULT, CW_USEDEFAULT, 435, 350, nullptr, nullptr, hInstance, nullptr);


   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, WNDOW_WIDTH, WNDOW_HEIGHT, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   myMonitor monitor(&txtbox_Monitor);
   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
	case WM_CREATE:
	{
		//Buttion
		buttion_OpenComm = CreateWindow("BUTTON", "Open COM", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, BTN_GAP+283, 139, 121, 23, hWnd, (HMENU)IDC_BUTTION_OPEN_COMM, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
		buttion_CloseComm = CreateWindow("BUTTON", "Close COM", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, BTN_GAP+283, 168, 121, 23, hWnd, (HMENU)IDC_BUTTION_CLOSE_COMM, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
		buttion_Refresh = CreateWindow("BUTTON", "Refresh", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, BTN_GAP+283, 233, 121, 23, hWnd, (HMENU)IDC_BUTTION_REFRESH, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
		
		//Combo Box;
		cbBox_Com = CreateWindow("COMBOBOX", NULL, WS_CHILD | ES_READONLY | WS_VISIBLE | WS_BORDER | WS_TABSTOP | CBS_DROPDOWN, BTN_GAP+284, 80, 125, 225, hWnd, (HMENU)IDC_CMBOX_PORT, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
		initComboBox(&cbBox_Com);

		//Text Box;
		txtbox_Monitor = CreateWindow("EDIT", "Welcome\n", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE | WS_BORDER | ES_READONLY | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 12, 12, BTN_GAP + 265, WNDOW_HEIGHT-100, hWnd, NULL, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);

		// Set the buttion endbled condtion 
		EnableWindow(GetDlgItem(hWnd, IDC_BUTTION_OPEN_COMM), TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_BUTTION_CLOSE_COMM), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_CMBOX_PORT), TRUE);
	}
	break;
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
			case IDC_BUTTION_OPEN_COMM :
			{
				//Greeting to Command execution
				myMonitor::sendTxt("\n Init Open");

				//Get the selected port from the combobox
				unsigned int index = 0;
				char strText[255] = { 0 };
				//Get Selected index form the combobox.
				index = SendMessage(cbBox_Com, CB_GETCURSEL, 0, 0);
				SendMessage(cbBox_Com, CB_GETLBTEXT, index, (LPARAM)strText);
				string str = strText;
				myMonitor::sendTxt("\n Selected Port is " + str);

				//ConfigureSerialPort();
				OpenSerialPort(9, 9600);

				RxThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)readPort, NULL, NULL, &ThreadID);


			}break;
			case IDC_BUTTION_CLOSE_COMM:
			{
				//Closing of the port.
				quit = true;
				WaitForSingleObject(RxThread, INFINITE);
				
				CloseHandle(RxThread);


			}break;

            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
Posted
Updated 25-Mar-19 5:26am
Comments
Gerry Schmitz 24-Mar-19 12:00pm
   
Don't you ever "write" to the serial port? How do you know what is being sent?
Member 12278335 24-Mar-19 12:35pm
   
Thank you for the replay. I could Successfully Write to the serial port. but trying to receiving the data was the problem.
data is receiving . i monitor through the serial monitor(Eltima).

Rick York 24-Mar-19 13:47pm
   
I don't have an actual solution for but two things look odd to me. First, your output messages say there are x bytes to read but you never display that many bytes that were read. What does that really mean? Maybe you should do a hex dump of them or something like that.

Second, I have never used overlapped I/O. I always set the port to blocking mode with a short timeout, like 500ms, so I can see periodically if the thread should terminate. The one time we used overlapped I/O we had a process waiting for multiple events with the serial port being one of them. As I recall, there were four possible events : comm port, internal message, keyboard, and terminate. Anyway, you might want to consider that.
KarstenK 25-Mar-19 3:08am
   
Please add it as solution to close the Q&A.
Rick York 25-Mar-19 11:22am
   
OK.
User 59241 24-Mar-19 21:11pm
   
Rick York has identified the issue. You are creating an overlapped file for reading but are not handling events. The fact that you got something to happen is merely incidental. Documentation is always the best starting point so you may wish to read this which is a good explanation of how to use threads to handle the overlapped events. Serial Communications | Microsoft Docs[^]

1 solution

Rate this:
Please Sign up or sign in to vote.

Solution 1

Two things look odd to me. First, your output messages say there are x bytes to read but you never display that many bytes that were read. What does that really mean? Maybe you should do a hex dump of them or something like that.

Second, I have never used overlapped I/O. I always set the port to blocking mode with a short timeout, like 500ms, so I can see periodically if the thread should terminate. The one time we used overlapped I/O we had a process waiting for multiple events with the serial port being one of them. As I recall, there were four possible events : comm port, internal message, keyboard, and terminate. Anyway, you might want to consider that.

In your case, you set the port to overlapped mode (by passing the OVERLAPPED structure) and then never service the events. You get characters from the port because they happen to be waiting there for you. As pwasser mentioned, read the documentation on this topic for more information.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100