I'm hoping that someone here can help me. I've written a simple application
that opens COM1 and does some simple writes and reads over the serial port
to a device in Windows XP Pro. The device on the other end runs fine in
Hyperterm, so I know my connection and cable are not the problem. Also, I've
been using Serial Monitor Lite from HHD software and haven't seen any data
transmitted. The problem is that WriteFile hangs everytime. I setup
everything, but still have the problem. Please help. Thanks in advance.
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <wsipx.h>
#include <string.h>
#include <stdlib.h>
#define DATA_BUFFER_SIZE 2048
static int SendData( char c);
static DWORD WINAPI SerialRecvThread( PVOID ptr );
static HANDLE hCom, hThread, hStdIn = 0, hStdOut = 0;
static DWORD dwEvtMask = 0;
static DCB dcb;
char buffer[4096];
int main()
{
BOOLEAN cmdComplete = FALSE;
DWORD dwInputEvents; /* number of events actually read */
DWORD dwMode;
INPUT_RECORD inputBuffer;
CONSOLE_CURSOR_INFO cci; /* used when turning off the cursor */
CONSOLE_SCREEN_BUFFER_INFO csbi; /* used to get cursor position */
// Attempt to open the comm port.
hCom = CreateFile( "COM1",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );
if( hCom == INVALID_HANDLE_VALUE )
{
printf( "CreateFile failed %d\n", GetLastError() );
goto TERMINATE;
}
// Set event mask
if( ! SetCommMask( hCom, EV_RXCHAR ) )
{
printf( "SetCommMask failed %d\n", GetLastError() );
goto TERMINATE;
}
// Set buffer sizes
if( ! SetupComm( hCom, 4096, 4096 ) )
{
printf( "SetupComm failed: %d\n", GetLastError() );
goto TERMINATE;
}
// Purge queues
if( ! PurgeComm( hCom,
(PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR) ) )
{
printf( "PurgeComm failed: %d\n", GetLastError() );
goto TERMINATE;
}
// Get the current comm port settings from the system.
if( ! GetCommState( hCom, &dcb ) )
{
printf( "GetCommState failed: %d\n", GetLastError() );
goto TERMINATE;
}
// Set our requirements for the port.
dcb.BaudRate = 19200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = TWOSTOPBITS;
// Send the port configuration back to the system.
if( ! SetCommState( hCom, &dcb ) )
{
printf( "SetCommState failed: %d\n", GetLastError() );
goto TERMINATE;
}
// Create recv thread
if( ( hThread = CreateThread( 0, 0, SerialRecvThread, NULL, 0, NULL) ) ==
NULL)
{
printf( "Thread start failed %d\n", GetLastError() );
goto TERMINATE;
}
// Setup console
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
if (csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y)
{
FreeConsole();
AllocConsole();
}
SetConsoleTitle("Serial Test");
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hStdIn, &dwMode);
SetConsoleMode(hStdIn, (dwMode & ~(ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT)) |
ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
cci.dwSize = 100;
cci.bVisible = TRUE;
SetConsoleCursorInfo(hStdOut, &cci);
// Event loop
do
{
// read an input events from the input event queue
ReadConsoleInput(hStdIn, &inputBuffer, 1, &dwInputEvents);
switch (inputBuffer.EventType)
{
case KEY_EVENT:
if (inputBuffer.Event.KeyEvent.bKeyDown &&
inputBuffer.Event.KeyEvent.uChar.AsciiChar)
{
if( ! SendData(inputBuffer.Event.KeyEvent.uChar.AsciiChar) )
{
goto TERMINATE;
}
}
break;
case WINDOW_BUFFER_SIZE_EVENT:
//Sleep(1000);
break;
}
// If ESC - loop ends
}
while (!(inputBuffer.EventType == KEY_EVENT &&
inputBuffer.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE &&
inputBuffer.Event.KeyEvent.bKeyDown));
TERMINATE:
// Close the port.
CloseHandle( hCom );
return( 0 );
}
static DWORD WINAPI SerialRecvThread( PVOID ptr )
{
ULONG error = 0;
ULONG count = 1;
DWORD written = 0;
DWORD chars = 0;
ULONG i = 0;
char buffer[DATA_BUFFER_SIZE];
while( TRUE )
{
if( ! WaitCommEvent( hCom, &dwEvtMask, NULL ) )
{
error = GetLastError();
printf("RecvThread error - WaitCommEvent failed: %u\n", error );
return( 1 );
}
if( ! ReadFile( hCom, buffer, DATA_BUFFER_SIZE, &count, NULL ) )
{
error = GetLastError();
printf("RecvThread error - ReadFile failed: %u\n", error );
return( 1 );
}
chars = 0;
do
{
WriteConsole (hStdOut, buffer, count, &written, 0);
chars += written;
}
while (chars < count);
} // while
return( 0 );
}
static int SendData( char c )
{
ULONG error = 0;
ULONG written;
if( ! WriteFile( hCom, &c, 1, &written, NULL ) )
{
error = GetLastError();
printf("WriteFile failed: %u\n", error );
return( 0 );
}
return( 1 );
}
Jacob,
it seem that you don't use TAPI - that's what this newsgroup is about.
Take a look at the TapiComm sample from P-SDK.
See my TAPI and TSPI FAQ:
Q: Is there any sample code available ?
http://www.i-b-a-m.de/Andreas_Marschall's_TAPI_and_TSPI_FAQ.htm#_Q:_Is_there
--
Best Regards
Andreas Marschall
Microsoft MVP for TAPI / Windows SDK
TAPI / TSP Developer and Tester
http://www.I-B-A-M.de/Andreas_Marschall's_TAPI_and_TSPI_FAQ.htm
* Please post all messages and replies to the newsgroup so all may
* benefit from the discussion. Private mail is usually not replied to.
* This posting is provided "AS IS" with no warranties, and confers no rights.
Andreas is right, this group is only marginally related to serial
communication issues.
That said, in the past I have used the little HACK below to demonstrate to
newbies soome of the basics of serial communication under Win32. It
demonstrates setting both some basic parameters and timeout behavior as well
as one way to overlap reads and writes. As a test it sends the Hayes
"identify" command to my modem on COM3 and displays the response.
I hope it helps.
Regards,
Will
int main(int argc, char **argv)
{
char szBuffer[80];
DCB dcb = {0};
DWORD dwRead, dwWritten;
HANDLE hComm;
OVERLAPPED ovlr = {0}, ovlw = {0};
COMMTIMEOUTS cto;
// Create events for overlapped operation
ovlr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ovlw.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// Open the port
hComm = CreateFile("\\\\.\\COM3", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// Get the state of the device and modify it
dcb.DCBlength = sizeof(dcb);
GetCommState(hComm, &dcb);
dcb.BaudRate = CBR_9600;
SetCommState(hComm, &dcb);
// Set the timeout parameters
cto.ReadIntervalTimeout = 1000;
cto.ReadTotalTimeoutConstant = 1000;
cto.ReadTotalTimeoutMultiplier = 1000;
cto.WriteTotalTimeoutConstant = 1000;
cto.WriteTotalTimeoutMultiplier = 1000;
SetCommTimeouts(hComm, &cto);
// Send a command and receieve a response. Note that
// we post the receive in advance of sending the
// command in order not to miss anything
printf("\r\nSending: ATI1\r\n");
ReadFile (hComm, szBuffer, sizeof(szBuffer), &dwRead, &ovlr);
WriteFile(hComm, "ATI1\r", strlen("ATI1\r"), &dwWritten, &ovlw);
// Wait for the receive to complete and display the response
if ( GetOverlappedResult(hComm, &ovlr, &dwRead, TRUE) )
{
szBuffer[dwRead] = 0;
printf("Received: %s\r\n", szBuffer);
}
// Close the device
CloseHandle(hComm);
return 0;
}