I got a RS232 signal capture device. and it working great.
I need some help making sense of the data. Basically we bought it because we are dealing a late 80's machine controller that uses serial communication. We had little luck despite knowing the port parameters.
From the data I dumped machine control is using the break signal as part of it's protocol. I am having trouble duplicating it using VB and the MSComm. I know to toggle the break signal and on and off. But I am not sure what I am supposed to be doing with it. I am supposed to leave it on for each byte of data I send. Or send a byte of data and then toggle.
Also I am confused how I supposed to receive any data from the controller. Do I toggle a flag when the break is turned on and then when it turned off read the input?
Michael Burr's description of the way break works is accurate. Often, "break" signals are sent for significantly longer than one character time.
These days, "Break" is infrequently used in serial comms, but the most common use is as a 'cheap' way of providing packet synchronization. "Break" may be sent before a packet starts, to alert the receiver that a new packet is on the way (and allow it to reset buffers, etc.) or at the end of a packet, to signal that no more data is expected. It's a kind of 'meta-character' in that it allows you to keep the full range of 8 or 7-bit values for packet contents, and not worry about how start or end of packet are delineated.
To send a break, typically you call SetCommBreak, wait an appropriate period (say, around 2 millseconds at 9600 baud) then call ClearCommBreak. During this time you can't be sending anything else, of course.
So, assuming that the protocol requires 'break' at the start of the packet, I'd do this (sorry for pseudocode):-
procedure SendPacket(CommPort port, Packet packet)
{
SetCommBreak(port)
Sleep(2); // 2 milliseconds - assuming 9600 baud. Pro-rata for others
ClearCommBreak(port)
foreach(char in packet)
SendChar(port, char)
}
Pseudocode for a receiver is more difficult, because you have to make a load of assumptions about the incoming packet format and the API calls used to receive breaks. I'll write in C this time, and assume the existence of an imaginary function. WaitCommEvent is probably the key to handling incoming Breaks.
bool ReadCharOrBreak(char *ch); // return TRUE if break, FALSE if ch contains received char
We'll also assume fixed-length 100 byte packets with "break" sent before each packet.
void ReadAndProcessPackets()
{
char buff[100];
int count;
count = 0;
while (true)
{
char ch;
if (ReadcharOrBreak(ch))
count = 0; // start of packet - reset count
else
{
if (count < 100)
{
buff[count++] = ch;
if (count == 100)
ProcessPacket(buff);
}
else
Error("too many bytes rx'd without break")
}
}
WARNING - totally untested, but should give you the idea...
For an example of a protocol using Break, check out the DMX-512 stage lighting protocol.
The start of a packet is signified by
a Break followed by a "mark" (a
logical one) known as the "Mark After
Break" (MAB). The break signals end of
one packet and the start of the next.
It causes the receivers to start
reception. After the break up to 513
slots are sent.
A break signal is an invalid character. When the RS-232 line is idle, the voltage is in the 'mark' (or '1') state (which is -12 volts if I remember right). When a character is sent, the protocol toggles the line to the 'space' (or '0') state for one bit time (the start bit) then toggles the signal as appropriate for the data (the data bits) and any parity bits. It then holds the line in an idle/mark (or 1) state for a number of bits defined by the stop bits, which is typically configurable (usually 1 stop bit in my experience).
Since there is always some period of time where the line will be in a mark state between data characters, the start of a character can always be recognised. This also means that the longest period of time that the line can be in a space state is:
1 start bit + however many data bits + a parity bit (if any)
A break signal is defined as holding the line in the space state for longer than that period of time - no valid data byte can do that, so the break 'character' isn't really a character. It's a special signal.
As far as when you need to issue a break signal depends entirely on the protocol being used.
'Break' was intended for when the line synchronization got totally mixed up.
I am supposed to leave it on for each byte of data I send. Or send a byte of data and then toggle.
Try sending a nice long 'break' signal (500 ms?) then wait a bit (50 ms?) then send your data.
Sending break can be achieved by:
lowering the bit-rate
sending 0x00 which will seem as break.
change bit-rate back.
During the break, it won't be possible to receive data since the bit-rate is not correct.
I used this for Linbus communication which has 1 master sending break then 0x55 as sync.
I helped out a friend and implemented the Comm Break in C#
It can be used as an extension method:
System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
//... serial communications code
myPort.SendCOMMbreak(5); //sends a break for rougly 5ms
Or a direct call:
RS232_Com_Break.UseWinAPItoSendBreak("COM1", 5); //aquires serial port and sends a break for rougly 5ms
Here is the complete code for the supporting class:
using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;
public static class RS232_Com_Break
{
/*===================================================================================
* EXTENSION METHOD TO HOLD THE VOLTAGE ON A COMM PORT HIGH FOR X(ms),
* for talking to old devices that need an RS232 "break" signal sent.
*
* 1/5/23 Blue Mosaic Software ~mwr
*
* Use: System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
* ... serial communications code
* myPort.SendCOMMbreak(5); //sends a break for rougly 5ms
*
* Or: RS232_Com_Break.UseWinAPItoSendBreak("COM1", 5); //aquires serial port and sends a break for rougly 5ms
* ==================================================================================*/
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
static extern bool SetCommBreak([InAttribute] IntPtr fileHandle);
[DllImport("kernel32.dll")]
static extern bool ClearCommBreak(IntPtr hFile);
public const short FILE_ATTRIBUTE_NORMAL = 0x80;
public const short INVALID_HANDLE_VALUE = -1;
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint CREATE_NEW = 1;
public const uint CREATE_ALWAYS = 2;
public const uint OPEN_EXISTING = 3;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll")]
static extern public bool CloseHandle(IntPtr hObject);
/// <summary>
/// Extension method to reset a serial port. Holds Port high (+5vdc) for the duration requested.
/// should work with an open or closed port.
/// </summary>
/// <param name="oPort"></param>
public static void SendCOMMbreak(this SerialPort oPort, int milliseconds)
{
// I think it takes 1 ms to set and clear the break.
int iPauseLength = milliseconds > 1 ? milliseconds - 1 : 1;
//little management to insure the port is free.
if (oPort.IsOpen)
{
oPort.Close();
UseWinAPItoSendBreak(oPort.PortName, iPauseLength);
oPort.Open();
}
else
{
UseWinAPItoSendBreak(oPort.PortName, iPauseLength);
}
}
/// <summary>
/// All the windows API calls are here, so this would be the code to use if
/// not using the .NET System.IO.Ports.SerialPort object.
/// </summary>
/// <param name="sPortName">The name of the COM port</param>
/// <param name="iPauseLengthMS">pause time in milliseconds</param>
public static void UseWinAPItoSendBreak(string sPortName, int iPauseLengthMS)
{
//get a handle to the port. Once we have done this sucessfully, it is unavalible elsewhere
IntPtr port_ptr = CreateFile(sPortName, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (port_ptr.ToInt32() == INVALID_HANDLE_VALUE) // -1 = oops
{
// Did not get a handle. We need to ask the framework to marshall the win32 error code to an exception
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
else
{
SetCommBreak(port_ptr);
Thread.Sleep(iPauseLengthMS);
ClearCommBreak(port_ptr);
//Close only happens if handle achieved.
CloseHandle(port_ptr);
}
}
}
Not really an SO question, but let me dredge up stuff from my
long-past (1980s in fact)
days as a comms programmer. You normally send a break by holding all bits low
or high (depending on your comms hardware). So to cause a break
either send the value 0x00 repeatedly for about half a second, or the value 0xFF.
You should be able to see the data that the port is sending. You'll need a null-modem cable, a computer with a serial port (or a serial-USB dongle) and a terminal program (as HyperTerminal on Windows -- not included in Vista). If you configure your terminal program adequately (correct speed, number of bits for data, the correct setting of start-stop, and correct port) all the data will be show on screen.
Sometimes it is requiered to hit the enter key to start seeing the data. You can toggle the setting for the terminal program during the test to see if something changes ("noise" to data).
Related
AVFormatContext's interrupt_callback field is a
Custom interrupt callbacks for the I/O layer.
It's type is AVIOInterruptCB, and it explains in comment section:
Callback for checking whether to abort blocking functions.
AVERROR_EXIT is returned in this case by the interrupted function. During blocking operations, callback is called with opaque as parameter. If the callback returns 1, the blocking operation will be aborted.
No members can be added to this struct without a major bump, if new elements have been added after this struct in AVFormatContext or AVIOContext.
I have 2 questions:
what does the last section means? Especially "without a major bump"?
If I use this along with an RTSP source, when I close the input by avformat_close_input, the "TEARDOWN" message is being sent out, however it won't reach the RTSP server.
For 2: here is a quick pseudo-code for demo:
int pkts = 0;
bool early_exit = false;
int InterruptCallback(void* ctx) {
return early_exit ? 1 : 0;
}
void main() {
ctx = avformat_alloc_context
ctx->interrupt_callback.callback = InterruptCallback;
avformat_open_input
avformat_find_stream_info
pkts=0;
while(!early_exit) {
av_read_frame
if (pkts++ > 100) early_exit=true;
}
avformat_close_input
}
In case I don't use the interrupt callback at all, TEARDOWN is being sent out, and it also reaches the RTSP server so it can actually tear down the connection. Otherwise, it won't tear down it, and I have to wait until TCP socket times out.
What is the proper way of using this interrupt callback?
It means that they are not going to change anything for this structure (AVIOInterruptCB). However, if thats the case it would be in a major bump (major change from 4.4 eg to 5.0)
You need to pass a meaningful parameter to void* ctx. Anything that you like so you can check it within the static function. For example a bool that you will set as cancel so you will interrupt the av_read_frame (which will return an AVERROR_EXIT). Usually you pass a class of your decoder context or something similar which also holds all the info that you required to check whether to return 1 to interrupt or 0 to continue the requests properly. A real example would be that you open a wrong rtsp and then you want to open another one (the right one) so you need to cancel your previous requests.
I suppose I actually have two separate questions, but I think that they are related enough to include them both. The context is a Linux USB device driver (not userspace).
After transmitting a request URB, how do I receive the response once my complete callback is called?
How can I use interrupt URBs for single request/response pairs, and not as actual continuous interrupt polling (as they are intended)?
So for some background, I'm working on a driver for the Microchip MCP2210 a USB-to-SPI Protocol Converter with GPIO (USB 2.0, datasheet here). This device advertises as generic HID and exposes two interrupt endpoints (an in and an out) as well as it's control endpoint.
I am starting from a working, (but alpha-quality) demo driver written by somebody else and kindly shared with the community. However, this is a HID driver and the mechanism it uses to communicate with the device is very expensive! (sending a 64 byte message requires allocating a 6k HID report struct, and allocation is sometimes performed in the context of an interrupt, requiring GFP_ATOMIC!). We'll be accessing this from an embedded low-memory device.
I'm new to USB drivers and still pretty green with Linux device drivers in general. However, I'm trying to convert this to a plain-jane USB driver (not HID) so I can use the less expensive interrupt URBs for my communications. Here is my code for transmitting my request. For the sake of (attempted) brevity, I'm not including the definition of my structs, etc, but please let me know if you need more of my code. dev->cur_cmd is where I'm keeping the current command I'm processing.
/* use a local for brevity */
cmd = dev->cur_cmd;
if (cmd->state == MCP2210_CMD_STATE_NEW) {
usb_fill_int_urb(dev->int_out_urb,
dev->udev,
usb_sndintpipe(dev->udev, dev->int_out_ep->desc.bEndpointAddress),
&dev->out_buffer,
sizeof(dev->out_buffer), /* always 64 bytes */
cmd->type->complete,
cmd,
dev->int_out_ep->desc.bInterval);
ret = usb_submit_urb(dev->int_out_urb, GFP_KERNEL);
if (ret) {
/* snipped: handle error */
}
cmd->state = MCP2210_CMD_STATE_XMITED;
}
And here is my complete fn:
/* note that by "ctrl" I mean a control command, not the control endpoint */
static void ctrl_complete(struct urb *)
{
struct mcp2210_device *dev = urb->context;
struct mcp2210_command *cmd = dev->cur_cmd;
int ret;
if (unlikely(!cmd || !cmd->dev)) {
printk(KERN_ERR "mcp2210: ctrl_complete called w/o valid cmd "
"or dev\n");
return;
}
switch (cmd->state) {
/* Time to rx the response */
case MCP2210_CMD_STATE_XMITED:
/* FIXME: I think that I need to check the response URB's
* status to find out if it was even transmitted or not */
usb_fill_int_urb(dev->int_in_urb,
dev->udev,
usb_sndintpipe(dev->udev, dev->int_in_ep->desc
.bEndpointAddress),
&dev->in_buffer,
sizeof(dev->in_buffer),
cmd->type->complete,
dev,
dev->int_in_ep->desc.bInterval);
ret = usb_submit_urb(dev->int_in_urb, GFP_KERNEL);
if (ret) {
dev_err(&dev->udev->dev,
"while attempting to rx response, "
"usb_submit_urb returned %d\n", ret);
free_cur_cmd(dev);
return;
}
cmd->state = MCP2210_CMD_STATE_RXED;
return;
/* got response, now process it */
case MCP2210_CMD_STATE_RXED:
process_response(cmd);
default:
dev_err(&dev->udev->dev, "ctrl_complete called with unexpected state: %d", cmd->state);
free_cur_cmd(dev);
};
}
So am I at least close here? Secondly, both dev->int_out_ep->desc.bInterval and dev->int_in_ep->desc.bInterval are equal to 1, will this keep sending my request every 125 microseconds? And if so, how do I say "ok, ty, now stop this interrupt". The MCP2210 offers only one configuration, one interface and that has just the two interrupt endpoints. (I know everything has the control interface, not sure where that fits into the picture though.)
Rather than spam this question with the lsusb -v, I'm going to pastebin it.
Typically, request/response communication works as follows:
Submit the response URB;
submit the request URB;
in the request completion handler, if the request was not actually sent, cancel the response URB and abort;
in the response completion handler, handle the response data.
All that asynchronous completion handler stuff is a big hassle if you have a single URB that is completed almost immediately; therefore, there is the helper function usb_interrupt_msg() which works synchronously.
URBs to be used for polling must be resubmitted (typically from the completion handler).
If you do not resubmit the URB, no polling happens.
In Win32, is there a way to test if a socket is non-blocking?
Under POSIX systems, I'd do something like the following:
int is_non_blocking(int sock_fd) {
flags = fcntl(sock_fd, F_GETFL, 0);
return flags & O_NONBLOCK;
}
However, Windows sockets don't support fcntl(). The non-blocking mode is set using ioctl with FIONBIO, but there doesn't appear to be a way to get the current non-blocking mode using ioctl.
Is there some other call on Windows that I can use to determine if the socket is currently in non-blocking mode?
A slightly longer answer would be: No, but you will usually know whether or not it is, because it is relatively well-defined.
All sockets are blocking unless you explicitly ioctlsocket() them with FIONBIO or hand them to either WSAAsyncSelect or WSAEventSelect. The latter two functions "secretly" change the socket to non-blocking.
Since you know whether you have called one of those 3 functions, even though you cannot query the status, it is still known. The obvious exception is if that socket comes from some 3rd party library of which you don't know what exactly it has been doing to the socket.
Sidenote: Funnily, a socket can be blocking and overlapped at the same time, which does not immediately seem intuitive, but it kind of makes sense because they come from opposite paradigms (readiness vs completion).
Previously, you could call WSAIsBlocking to determine this. If you are managing legacy code, this may still be an option.
Otherwise, you could write a simple abstraction layer over the socket API. Since all sockets are blocking by default, you could maintain an internal flag and force all socket ops through your API so you always know the state.
Here is a cross-platform snippet to set/get the blocking mode, although it doesn't do exactly what you want:
/// #author Stephen Dunn
/// #date 10/12/15
bool set_blocking_mode(const int &socket, bool is_blocking)
{
bool ret = true;
#ifdef WIN32
/// #note windows sockets are created in blocking mode by default
// currently on windows, there is no easy way to obtain the socket's current blocking mode since WSAIsBlocking was deprecated
u_long flags = is_blocking ? 0 : 1;
ret = NO_ERROR == ioctlsocket(socket, FIONBIO, &flags);
#else
const int flags = fcntl(socket, F_GETFL, 0);
if ((flags & O_NONBLOCK) && !is_blocking) { info("set_blocking_mode(): socket was already in non-blocking mode"); return ret; }
if (!(flags & O_NONBLOCK) && is_blocking) { info("set_blocking_mode(): socket was already in blocking mode"); return ret; }
ret = 0 == fcntl(socket, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK);
#endif
return ret;
}
I agree with the accepted answer, there is no official way to determine the blocking state of a socket on Windows. In case you get a socket from a third party (let's say, you are a TLS library and you get the socket from upper layer) you cannot decide if it is in blocking state or not.
Despite this I have a working, unofficial and limited solution for the problem which works for me for a long time.
I attempt to read 0 bytes from the socket. In case it is a blocking socket it will return 0, in case it is a non-blocking it will return -1 and GetLastError equals WSAEWOULDBLOCK.
int IsBlocking(SOCKET s)
{
int r = 0;
unsigned char b[1];
r = recv(s, b, 0, 0);
if (r == 0)
return 1;
else if (r == -1 && GetLastError() == WSAEWOULDBLOCK)
return 0;
return -1; /* In case it is a connection socket (TCP) and it is not in connected state you will get here 10060 */
}
Caveats:
Works with UDP sockets
Works with connected TCP sockets
Doesn't work with unconnected TCP sockets
I'm working an application of which only one instance must exist at any given time. There are several possibilities to accomplish this:
Check running processes for one matching our EXE's name (unreliable)
Find the main window (unreliable, and I don't always have a main window)
Create a mutex with a unique name (GUID)
The mutex option seems to me the most reliable and elegant.
However, before my second instance terminates, I want to post a message to the already running instance. For this, I need a handle to the thread (or the process) that owns the mutex.
However, there seems to be no API function to get the creator/owner of a given mutex. Am I just overlooking it? Is there another way to get to this thread/process? Is there another way to go about this?
Update: This guy simply broadcast a message to all running processes. I guess that's possible, but I don't really like it...
This should get you started on the original request to get a process that owns a mutex.
It's in C#, but the Win32 calls are the same.
class HandleInfo
{
[DllImport("ntdll.dll", CharSet = CharSet.Auto)]
public static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr VirtualAlloc(IntPtr address, uint numBytes, uint commitOrReserve, uint pageProtectionMode);
[DllImport("kernel32.dll", SetLastError=true)]
internal static extern bool VirtualFree(IntPtr address, uint numBytes, uint pageFreeMode);
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_HANDLE_INFORMATION
{
public int ProcessId;
public byte ObjectTypeNumber;
public byte Flags; // 1 = PROTECT_FROM_CLOSE, 2 = INHERIT
public short Handle;
public int Object;
public int GrantedAccess;
}
static uint MEM_COMMIT = 0x1000;
static uint PAGE_READWRITE = 0x04;
static uint MEM_DECOMMIT = 0x4000;
static int SystemHandleInformation = 16;
static uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public HandleInfo()
{
IntPtr memptr = VirtualAlloc(IntPtr.Zero, 100, MEM_COMMIT, PAGE_READWRITE);
int returnLength = 0;
bool success = false;
uint result = NtQuerySystemInformation(SystemHandleInformation, memptr, 100, out returnLength);
if (result == STATUS_INFO_LENGTH_MISMATCH)
{
success = VirtualFree(memptr, 0, MEM_DECOMMIT);
memptr = VirtualAlloc(IntPtr.Zero, (uint)(returnLength + 256), MEM_COMMIT, PAGE_READWRITE);
result = NtQuerySystemInformation(SystemHandleInformation, memptr, returnLength, out returnLength);
}
int handleCount = Marshal.ReadInt32(memptr);
SYSTEM_HANDLE_INFORMATION[] returnHandles = new SYSTEM_HANDLE_INFORMATION[handleCount];
using (StreamWriter sw = new StreamWriter(#"C:\NtQueryDbg.txt"))
{
sw.WriteLine("# Offset\tProcess Id\tHandle Id\tHandleType");
for (int i = 0; i < handleCount; i++)
{
SYSTEM_HANDLE_INFORMATION thisHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(
new IntPtr(memptr.ToInt32() + 4 + i * Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION))),
typeof(SYSTEM_HANDLE_INFORMATION));
sw.WriteLine("{0}\t{1}\t{2}\t{3}", i.ToString(), thisHandle.ProcessId.ToString(), thisHandle.Handle.ToString(), thisHandle.ObjectTypeNumber.ToString());
}
}
success = VirtualFree(memptr, 0, MEM_DECOMMIT);
}
}
I don't think there is a trivial way to resolve the actual owner of a Mutex, but the process that owns it can create other secondary items whose lifetimes are tied to it. There are plenty of mechanisms that are suitable for calling back across-process without having a main window.
Register an object in the COM Running Object Table. Clients that are unable to take ownership of the Mutex can lookup the owner via the ROT and call back to the owner. A File Moniker should be suitable for registration here.
Create a chunk of shared memory containing location details for the owner process. From there, write into the buffer the process handle and thread handle of a thread that can receive windows messages, and then use PostThreadMessage() to send a notification. Any other competing process may open the shared memory for read-only to determine where to send a windows message.
Listen in the owner process on a Socket or Named Pipe. Probably overkill and not a good match for your needs.
Use a shared file with locking. I'm not fond of this because the owner will need to poll, and it won't gracefully handle N potential other processes that could be trying to contact the owner at the same time.
Here are reference links for the first two options.
IRunningObjectTable # MSDN ,
File Monikers # MSDN
Creating Named Shared Memory # MSDN
I have never really understood the rational behind using a Mutex which has no signaling capability. I would instead create an event (using CreateEvent) which has the same properties as creating a mutex (i.e. with a name it can return that the object already existed) but you can set the event flag in the new process, as long as the original process is waiting on the event flag it can be notified when it needs to wake itself up.
You could always do it the UNIX way and create a "pid" file, putting the process id of the currently running instance into that file. Then have the app delete the file when it exits.
When a new instance starts up it should verify that the process in the PID file is actually alive as well (in case the app exits abnormally and the file doesn't get deleted)
Create a shared memory area with the fixed name:
http://msdn.microsoft.com/en-us/library/aa366551%28VS.85%29.aspx
Then you can put any structure you like inside, including process id, HWND etc.
There's a portable option: create a socket on a port (with a fixed number) and wait (accept) on it. The second instance of the app will fail since the port is already taken. Then the second instance can connect to the socket of the primary instance and send any information desired.
I hope this helps...
I had similar problems. I am want a function that returns if a single instance of an app is running. Then another function to bring the app to the front. In which I must first deduce the HWND of the already running window.
FindWindow sucks big time. Window titles can change, another window could be using the same class and title, etc.
Then I thought maybe extra data could be stored with a mutex. But I dont see where user data can be stored in a mutex object or event object. But a mutex knows which thread it belongs to and thus which process it belongs to. But as you said, the api doesnt seem to exist.
Many new and complicated looking methods have been suggested here; with the exeception of simply using a file. So I want to add another method, temporary registry keys.
This method is easiest for me as I already built an hkey library. But the win32 registry api is pretty straight forward compared to the horrifying looking shared memory method.
I want to read and write from serial using events/interrupts.
Currently, I have it in a while loop and it continuously reads and writes through the serial. I want it to only read when something comes from the serial port. How do I implement this in C++?
This is my current code:
while(true)
{
//read
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
}
//write
if(!WriteFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
}
//print what you are reading
printf("%s\n", szBuff);
}
Use a select statement, which will check the read and write buffers without blocking and return their status, so you only need to read when you know the port has data, or write when you know there's room in the output buffer.
The third example at http://www.developerweb.net/forum/showthread.php?t=2933 and the associated comments may be helpful.
Edit: The man page for select has a simpler and more complete example near the end. You can find it at http://linux.die.net/man/2/select if man 2 select doesn't work on your system.
Note: Mastering select() will allow you to work with both serial ports and sockets; it's at the heart of many network clients and servers.
For a Windows environment the more native approach would be to use asynchronous I/O. In this mode you still use calls to ReadFile and WriteFile, but instead of blocking you pass in a callback function that will be invoked when the operation completes.
It is fairly tricky to get all the details right though.
Here is a copy of an article that was published in the c/C++ users journal a few years ago. It goes into detail on the Win32 API.
here a code that read serial incomming data using interruption on windows
you can see the time elapsed during the waiting interruption time
int pollComport(int comport_number, LPBYTE buffer, int size)
{
BYTE Byte;
DWORD dwBytesTransferred;
DWORD dwCommModemStatus;
int n;
double TimeA,TimeB;
// Specify a set of events to be monitored for the port.
SetCommMask (m_comPortHandle[comport_number], EV_RXCHAR );
while (m_comPortHandle[comport_number] != INVALID_HANDLE_VALUE)
{
// Wait for an event to occur for the port.
TimeA = clock();
WaitCommEvent (m_comPortHandle[comport_number], &dwCommModemStatus, 0);
TimeB = clock();
if(TimeB-TimeA>0)
cout <<" ok "<<TimeB-TimeA<<endl;
// Re-specify the set of events to be monitored for the port.
SetCommMask (m_comPortHandle[comport_number], EV_RXCHAR);
if (dwCommModemStatus & EV_RXCHAR)
{
// Loop for waiting for the data.
do
{
ReadFile(m_comPortHandle[comport_number], buffer, size, (LPDWORD)((void *)&n), NULL);
// Display the data read.
if (n>0)
cout << buffer <<endl;
} while (n > 0);
}
return(0);
}
}