Friday, April 10, 2009

Win32 Serial Communication Programming

Allot of embedded systems (Windows Ce, Windows Embedded) provide an API for working with Serial Communication protocols such as RS232, RS422 and RS485.


Initial steps for creating synchronies connection:

At first we must open communications port.
It can be made by using CreateFile function which can create a handle to a communications resource, such as the serial port (COM1 for example).

Next we need to set a Baud rate. Baud rate is a measure of how fast data are moving between systems that use serial communication (most modern embedded systems transmitting at 115,200 baud and higher).
SetCommState function configures a communications device according to the specifications in a device-control block.

In addition it is necessary to sets the time-out parameters for all read and write operations our communications device (we don't want to wait for response forever!).
SetCommTimeouts - is the right function for this.


Now you can send and receive data!
In many applications developers preferred not to close a handle after one transition.
Single handle can be used for multiple I/O transitions.


Here is a simple class for synchronies serial communications:

SerialAPI.h

#include <windows.h>
class SerialAPI
{
public:
SerialAPI(int portNumber);
virtual ~SerialAPI(void);

virtual bool Write(const void *buf,int length);
virtual bool Read(void *buf,int length);
virtual bool SetBaudRate(int rate);
virtual bool SetTimeout(int timeoutMs);
virtual bool Connect();
virtual bool Disconnect();

inline bool IsConnected()const{return m_isConnected;}
inline HANDLE GetHandle()const{return m_handle;}

private:
TCHAR m_portNumberName[15];
bool m_isConnected;
HANDLE m_handle;

private:
SerialAPI(SerialAPI&);
SerialAPI& operator=(SerialAPI&);

};



SerialAPI.cpp
#include "SerialAPI.h"
#include <stdio.h>


SerialAPI::SerialAPI(int portNumber)
{
_stprintf(m_portNumberName,_T("COM%d:"),portNumber);
Connect();
}

SerialAPI::~SerialAPI(void)
{
Disconnect() ;
}

bool SerialAPI::Write(const void *buf, int length)
{
DWORD bufLength = length, bytesWritten = 0;

if (!WriteFile(m_handle, (LPVOID)buf, bufLength, &bytesWritten, 0) || length != bytesWritten)
return false;
return true;
}

bool SerialAPI::Read(void *buf,int length)
{
DWORD bufLength = length, bytesRead = 0;

if (!ReadFile(m_handle, (LPVOID)buf, bufLength, &bytesRead, 0) || length != bytesRead)
return false;
return true;
}

bool SerialAPI::SetBaudRate(int rate)
{
DCB PortDCB;
PortDCB.DCBlength = sizeof(DCB);

if (!GetCommState (m_handle, &PortDCB))
return false;

PortDCB.BaudRate = (DWORD)rate;

if (!SetCommState(m_handle, &PortDCB))
return false;

return true;
}

bool SerialAPI::SetTimeout(int timeoutMs)
{
COMMTIMEOUTS CommTimeouts;

if (!GetCommTimeouts(m_handle, &CommTimeouts))
return false;

CommTimeouts.ReadTotalTimeoutConstant = timeoutMs;
CommTimeouts.WriteTotalTimeoutConstant = timeoutMs;

if (!SetCommTimeouts(m_handle, &CommTimeouts))
return true;
}

bool SerialAPI::Connect()
{
if (m_isConnected)
return false;

m_handle = CreateFile (m_portNumberName, // Pointer to the name of the port
GENERIC_READ | GENERIC_WRITE, // Access (read-write) mode
0, // Share mode
NULL, // Pointer to the security attribute
OPEN_EXISTING, // How to open the serial port
0, // Port attributes
NULL); // Handle to port with attribute to copy

if (m_handle == INVALID_HANDLE_VALUE)
return false;

m_isConnected = true;

return true;
}

bool SerialAPI::Disconnect()
{
if (m_isConnected)
{
if (!CloseHandle(m_handle))
return false;

m_handle = INVALID_HANDLE_VALUE;
}

m_isConnected = false;

return true;
}

0 comments:

Post a Comment