Serial communication using C# for WinCE 5.0 platform

G

Guest

Hi,
Iam new to C#. Iam using Microsoft Visual Studio .Net 2003. Iam writing
a program to read the COM port in C# (Compact Framework). Iam planning to put
this code on a Windows CE OS image generated using WinCE Platform Builder
5.0.

Iam able to open the COM port using the function CreateFile (in
coredll.dll). The function returns a positive file handler. But when I try to
read the port using ReadFile, it does not read anything and the number of
Bytes read is 0. GetLastError and GetLastWin32Error gives 1400 - Invalid
window handle. Even ReadFile returns positive number

I read in one of the Microsoft Blog sites -
http://www.danielmoth.com/Blog/2004/09/serial-rs232-communications-in-net.html

"WinCE does not support overlapped io. Even the non-overlapped io is
implemented differently on the PC than on CE (e.g. Read/WriteFile do not
block on CE). Finally, the threading support of the CF is not as rich as that
of the full framework. Basically rs232 libraries designed for the
desktop/full framework will not just work on CE devices with the CF"

The author of this site gives option of using some custom library CFSerialIO
which didn't work either.
Other option the author gave was, to use OpenNETCF.IO.Serial which Iam
trying now (hope it works!)
System.IO.Ports is not supported in Visual Studio .Net 2003.

So if ReadFile is not for CE, then what else is an alternative?
One more question, Is there a COM2 in WinCE?
Please reply.
 
G

Ginny Caughey [MVP]

ReadFile and WriteFile work fine on CE, and both CFSerial and the OpenNETCF
Serial class use it internally. Can you show us the code you're using for
CreateFile and ReadFile?
 
D

Dick Grier

Hi,

There are a number of people who are using CFSerial for CE 5 (using Visual
Studio 2003). You say that it didn't work, but you don't really make clear
what didn't work. Did you try the terminal example that is included in the
download? Perhaps you can post the code that fails to work -- I may be able
to spot a problem.

Dick

--
Richard Grier (Microsoft Visual Basic MVP)

See www.hardandsoftware.net for contact information.

Author of Visual Basic Programmer's Guide to Serial Communications, 4th
Edition ISBN 1-890422-28-2 (391 pages) published July 2004. See
www.mabry.com/vbpgser4 to order.
 
G

Guest

Hi,
Thanks for replying. I rewrote the code as in the C#FSerial example for
WinCE.Net emulator. It opens the port (COM 1) but event handler fails to read
anything -

SerialPort = new SerialPort();
SerialPort.CommPort = 1;
SerialPort.BitRate = 38400;
SerialPort.DataBits = 8;
SerialPort.RTSEnable = true;
SerialPort.DTREnable = true;
SerialPort.StopBits = 1;
SerialPort.EnableOnComm = true;
SerialPort.PortOpen = true;

// define an event handler
SerialPort.OnComm +=new SerialPort.OnCommEventHandler(DataReceived);
string Buffer = "This is a test";
SerialPort.Output(Buffer);

and DataReceived goes as follows:

private void DataReceived()
{
string inputData;
// read input text
// you may want to use StringBuilder instead of string
inputData = SerialPort.InputString();
// display it
txtTerm.Text += inputData;
}

This event handler reads COM events in PocketPC emulator

// define an event handler
SerialPort.OnComm +=new SerialPort.OnCommEventHandler(DataReceived);

but fails to read any event in WinCE.Net emulator (reads nothing).
I have setup Device Tools ->Hardware Options correctly in Visual Studio .Net
2003. Is this a problem with emulator or is it something else?
Please Reply.
 
G

Guest

Hi,
Thanks for replying. Thank you for the info about ReadFile and WriteFile.
The following code is to read a byte from the COM port:
The PortName Iam sending is "COM1:".

public static byte ReadPortByte(string PortName)
{
int hPort = CEAPI.INVALID_HANDLE_VALUE;
int read = 0;
byte[] buffer = new byte[1];

// open port
hPort = CEAPI.CreateFile(PortName, CEAPI.GENERIC_READ, 0, 0,
CEAPI.OPEN_EXISTING, 0, 0);

// Specify a set of events to be monitored for the port.
CEAPI.SetCommMask (hPort, CEAPI.EV_RXCHAR | CEAPI.EV_CTS | CEAPI.EV_DSR |
CEAPI.EV_RLSD | CEAPI.EV_RING);

// check for success
if(hPort == CEAPI.INVALID_HANDLE_VALUE)
{
Exception e = new Exception("Failed to open port '" + PortName + "': "
+ Convert.ToString(CEAPI.GetLastError()));
throw e;
}

// read port value
if(!CEAPI.ReadFile(hPort, buffer, 1, ref read, 0))
{
Exception e = new Exception("Failed to read port '" + PortName + "': " +
Convert.ToString(CEAPI.GetLastError()));
throw e;
}

if(read != 1)
{
Exception e;
e = new Exception("BYTE block size specified but " +
Convert.ToString(read) + " bytes returned");
throw e;
}

// close port
if(!CEAPI.CloseHandle(hPort))
{
Exception e = new Exception("Unable to close port '" + PortName + "': "
+ Convert.ToString(CEAPI.GetLastError()));
throw e;
}

return buffer[0];
}


internal class CEAPI
{
public const UInt32 EV_RXCHAR = 0x0001;
public const UInt32 EV_RXFLAG = 0x0002;
public const UInt32 EV_TXEMPTY = 0x0004;
public const UInt32 EV_CTS = 0x0008;
public const UInt32 EV_DSR = 0x0010;
public const UInt32 EV_RLSD = 0x0020;
public const UInt32 EV_BREAK = 0x0040;
public const UInt32 EV_ERR = 0x0080;
public const UInt32 EV_RING = 0x0100;
public const Int16 DTR_CONTROL_ENABLE = 0x01;
public const Int16 RTS_CONTROL_ENABLE = 0x01;
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;

[DllImport("coredll.dll", EntryPoint="WriteFile")]
public static extern bool WriteFile(
int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);

[DllImport("coredll.dll", EntryPoint="ReadFile")]
public static extern bool ReadFile(
int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
ref int lpNumberOfBytesRead,
int lpOverlapped);

[DllImport("coredll.dll", EntryPoint="CreateFile")]
public static extern int CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);

[DllImport("coredll.dll", EntryPoint="CloseHandle")]
public static extern bool CloseHandle(int hObject);
 
G

Ginny Caughey [MVP]

I see a couple of potential problems. First you need to be sure to check the
return values of all the API functions you call. And second, although you
are calling SetCommMask to EV_RXCHAR, you aren't waiting for it with
WaitCommEvent before attempting to read - something that most of us do in a
separate thread - so there might not be any data at the port at the time you
attempt to read from it.

One trick I've found useful for working with serial devices is to first test
them on the desktop using Hyperterminal or something similar so I know for
sure how the device behaves and what serial protocol it supports.

HTH,

--
Ginny Caughey
..NET Compact Framework MVP


Nithin U.K said:
Hi,
Thanks for replying. Thank you for the info about ReadFile and WriteFile.
The following code is to read a byte from the COM port:
The PortName Iam sending is "COM1:".

public static byte ReadPortByte(string PortName)
{
int hPort = CEAPI.INVALID_HANDLE_VALUE;
int read = 0;
byte[] buffer = new byte[1];

// open port
hPort = CEAPI.CreateFile(PortName, CEAPI.GENERIC_READ, 0, 0,
CEAPI.OPEN_EXISTING, 0, 0);

// Specify a set of events to be monitored for the port.
CEAPI.SetCommMask (hPort, CEAPI.EV_RXCHAR | CEAPI.EV_CTS | CEAPI.EV_DSR |
CEAPI.EV_RLSD | CEAPI.EV_RING);

// check for success
if(hPort == CEAPI.INVALID_HANDLE_VALUE)
{
Exception e = new Exception("Failed to open port '" + PortName + "':
"
+ Convert.ToString(CEAPI.GetLastError()));
throw e;
}

// read port value
if(!CEAPI.ReadFile(hPort, buffer, 1, ref read, 0))
{
Exception e = new Exception("Failed to read port '" + PortName + "': "
+
Convert.ToString(CEAPI.GetLastError()));
throw e;
}

if(read != 1)
{
Exception e;
e = new Exception("BYTE block size specified but " +
Convert.ToString(read) + " bytes returned");
throw e;
}

// close port
if(!CEAPI.CloseHandle(hPort))
{
Exception e = new Exception("Unable to close port '" + PortName + "':
"
+ Convert.ToString(CEAPI.GetLastError()));
throw e;
}

return buffer[0];
}


internal class CEAPI
{
public const UInt32 EV_RXCHAR = 0x0001;
public const UInt32 EV_RXFLAG = 0x0002;
public const UInt32 EV_TXEMPTY = 0x0004;
public const UInt32 EV_CTS = 0x0008;
public const UInt32 EV_DSR = 0x0010;
public const UInt32 EV_RLSD = 0x0020;
public const UInt32 EV_BREAK = 0x0040;
public const UInt32 EV_ERR = 0x0080;
public const UInt32 EV_RING = 0x0100;
public const Int16 DTR_CONTROL_ENABLE = 0x01;
public const Int16 RTS_CONTROL_ENABLE = 0x01;
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;

[DllImport("coredll.dll", EntryPoint="WriteFile")]
public static extern bool WriteFile(
int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);

[DllImport("coredll.dll", EntryPoint="ReadFile")]
public static extern bool ReadFile(
int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
ref int lpNumberOfBytesRead,
int lpOverlapped);

[DllImport("coredll.dll", EntryPoint="CreateFile")]
public static extern int CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);

[DllImport("coredll.dll", EntryPoint="CloseHandle")]
public static extern bool CloseHandle(int hObject);
.
.
.
}
The output is "BYTE block size specified but 0 bytes returned".
This number of bytes read is 0 (read = 0) even though there is data coming
at COM port. Can you find the bug ?
Please reply.

Ginny Caughey said:
ReadFile and WriteFile work fine on CE, and both CFSerial and the
OpenNETCF
Serial class use it internally. Can you show us the code you're using for
CreateFile and ReadFile?
 
D

Dick Grier

Hi,

I ALWAYS recommend that you use actual hardware for serial debugging. I
have NEVER been able to get the emulator to work "as advertised." Others
claim that they have... But, not I.

Dick

--
Richard Grier (Microsoft Visual Basic MVP)

See www.hardandsoftware.net for contact information.

Author of Visual Basic Programmer's Guide to Serial Communications, 4th
Edition ISBN 1-890422-28-2 (391 pages) published July 2004. See
www.mabry.com/vbpgser4 to order.
 
G

Ginny Caughey [MVP]

Hi Dick,

That's been my experience as well. The emulators are great for what they do,
but you need the real devices for serial comm testing - not just the CE
device but the actual serial device it connects with as well.
 
G

Guest

Hi,
Thanks for the reply. I tried this code on an WinCE 5.0 PC and it worked.
I think there was some problem with my emulator.
Thanks again.

Regards,
Nithin.
 
D

Dick Grier

The emulator (IMO) should be reserved for UI and logical development and
testing. Working with the hardware is important when... You actually are
using hardware "bits."

Dick

--
Richard Grier (Microsoft Visual Basic MVP)

See www.hardandsoftware.net for contact information.

Author of Visual Basic Programmer's Guide to Serial Communications, 4th
Edition ISBN 1-890422-28-2 (391 pages) published July 2004. See
www.mabry.com/vbpgser4 to order.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top