I'm reading on a stream connected on a UART serial port via half-duplex RS-485 protocol at 9600bps, Data : 8 bits, Stop 1 bit no parity with an embedded device.
I know that the system which I'm connected to sends binary commands between 2 byte and 10 bytes long at an interval of 20ms.
I access the stream with the following flags:
uart0_filestream = open(COM_UART_DEV, O_RDWR | O_NOCTTY | O_NDELAY);
However, it happens frequently that the 10 bytes long commands will be chunked in half causing a checksum error in my application. I need to poll every 20 ms and the only solution I found for this is to inscrease the sleep time between polls, which I don't want.
Is there a flag or a smart method that I can use to make sure the transmission is complete before reading the content of the stream buffer?
Okay, I found a solution that's ok for my needs. Since I can't know for sure that when I will read the content of the stream all the data will be there and I don't want to increase my poll interval, as #sawdust suggested, I increased the poll rate:
unsigned char *pStartBuffer = pRxBuffer;
if(uart0_filestream != -1)
{
int rx_length = 0, rx = 0, elapsed = 0;
bool bCommand = false;
while(rx_length <= 10)//&& elapsed <= 10)
{
rx = read(uart0_filestream, (void*)pRxBuffer, length);
if(rx > 0)
{
rx_length += rx;
pRxBuffer += rx;
if(checksum(pStartBuffer, rx_length) == true)
{
bCommand = true;
break;
}
}
nanosleep(&sleep_rx, NULL);
//elapsed+=2;
}
I increased the poll rate to 8ms at first. Since I know that the longest command I can receive is 10 bytes long, I read until the checksum is valid or that the content read is 10 bytes long and sleep an extra 2ms between polls. This performs very well for now.
Related
I made a simple c++ program for armv7 architecture (compiled with linaro gnueabihf using raspi rootfs) that takes in arguments with baud rate, data, serial port etc and sends it to the selected serial port and receives the response. At least that's the goal of it.
I'm currently using it to send a command to disable/enable backlight on an industrial screen through an UART port. The screen takes a simple text command ended with crlf and returns a response. The specification of the screen says it uses 9600 baud, no parity, 8 data bits and 1 stop bit for communication, so pretty much standard.
While the sending works flawlessly - I cannot seem to find a way to properly receive the response. I tried configuring the termios port structure in multiple different ways (disabling hardware control, using cfmakeraw, configuring the VMIN and VTIME values) but without luck.
First thing is that, I'm receiving all the input byte by byte (so each read() call returns exactly 1 byte..), but that wouldn't be a problem.
When using nonblocking mode without select() I'm receiving all bytes, but I don't know when to stop receiving (and I want it to be universal, so I send a command, expect a simple response and if there is no more data then just exit). I made a time counter since the last message, so if nothing was received in last ~500ms then I assume nothing more will come. But this sometimes loses some bytes of the response and I don't know why.
When using blocking mode, I receive correct bytes (still byte by byte though), but I don't know when to stop and the last call to read() leaves the program hanging, because nothing else comes in the input.
When adding select() to the blocking call, to see if input is readable, I get very frequent data loss (sometimes just receiving a few bytes), and sometimes select returns 1, but read() blocks, and I'm left hanging.
When I just send data without doing any reading, and look at the input using cat -v < /dev/ttyS3 I can actually see correct input on the serial port all the time, however when I run both cat and my program as receivers, only one of them gets the data (or cat receives a few bytes and my program a few), this suggests me that something is "stealing" my bytes the same way when I try to read it, but what could it be, and why is it like that?
My current code (using the nonblocking read + 500ms timeout), that still loses some bytes from time to time:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
int open_port(char* portname)
{
int fd; // file description for the serial port
fd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1) // if open is unsucessful
{
printf("Error: open_port: Unable to open %s. \n", portname);
}
else
{
//fcntl(fd, F_SETFL, 0);
fcntl(fd, F_SETFL, FNDELAY);
}
return(fd);
}
int configure_port(int fd, int baud_rate)
{
struct termios port_settings;
tcgetattr(fd, &port_settings);
cfsetispeed(&port_settings, baud_rate); // set baud rates
cfsetospeed(&port_settings, baud_rate);
cfmakeraw(&port_settings);
port_settings.c_cflag &= ~PARENB; // no parity
port_settings.c_cflag &= ~CSTOPB; // 1 stop bit
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8; // 8 data bits
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return(fd);
}
/**
* Convert int baud rate to actual baud rate from termios
*/
int get_baud(int baud)
{
switch (baud) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return -1;
}
}
unsigned char* datahex(char* string) {
if(string == NULL)
return NULL;
size_t slength = strlen(string);
if((slength % 2) != 0) // must be even
return NULL;
size_t dlength = slength / 2;
unsigned char* data = (unsigned char*)malloc(dlength);
memset(data, 0, dlength);
size_t index = 0;
while (index < slength) {
char c = string[index];
int value = 0;
if(c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
else if (c >= 'a' && c <= 'f')
value = (10 + (c - 'a'));
else {
free(data);
return NULL;
}
data[(index/2)] += value << (((index + 1) % 2) * 4);
index++;
}
return data;
}
int main(int argc, char **argv) {
int baud_rate = B9600;
baud_rate = get_baud(atoi(argv[1]));
if(baud_rate == -1) {
printf("Error: Cannot convert baud rate %s, using 9600\n", argv[1]);
baud_rate = B9600;
}
bool convertHex = false;
char portName[24] = "/dev/ttyS0";
bool debug = false;
bool noreply = false;
for(int i = 3; i < argc; i++) {
if(!strcmp(argv[i], "hex"))
convertHex = true;
else if(strstr(argv[i], "/dev/") != NULL)
strncpy(portName, argv[i], sizeof(portName));
else if(!strcmp(argv[i], "debug"))
debug = true;
else if(!strcmp(argv[i], "no-reply"))
noreply = true;
}
unsigned char* data = nullptr;
size_t len = 0;
if(convertHex) {
data = datahex(argv[2]);
if((int)data == (int)NULL) {
convertHex = false;
printf("Error: Couldn't convert hex value! Needs to be even length (2 chars per byte)\n");
}
else
len = strlen(argv[2])/2;
}
if(!convertHex) {
data = (unsigned char*)argv[2];
len = strlen(argv[2]);
}
int fd = open_port(portName);
if(fd == -1) {
printf("Error: Couldn't open port %s\n", portName);
if(convertHex)
free(data);
return 0;
}
configure_port(fd, baud_rate);
if(debug) {
printf("Sending data (raw): ");
for(int i =0; i< len; i++) {
printf("%02X", data[i]);
}
printf("\n");
}
size_t writelen = write(fd, data, len);
if(debug)
printf("Sent %d/%d bytes\n", writelen, len);
if(writelen != len)
printf("Error: not all bytes were sent (%d/%d)\n", writelen, len);
else if(noreply)
printf("WRITE OK");
if(!noreply) {
unsigned char ibuff[512] = {0};
int curlen = 0; // full length
clock_t begin_time = clock();
while(( float(clock() - begin_time) / CLOCKS_PER_SEC) < 0.5 && curlen < sizeof(ibuff)) {
int ret = read(fd, ibuff+curlen, sizeof(ibuff)-curlen-1);
if(ret < 0) {
ret = 1;
continue;
}
if(ret > 0) {
curlen += ret;
begin_time = clock();
}
}
if(curlen > 0) {
ibuff[curlen] = 0; // null terminator
printf("RESPONSE: %s", ibuff);
}
}
if(fd)
close(fd);
if(convertHex)
free(data);
return 0;
}
I launch the program like ./rs232 9600 [hex string] hex debug
The scren should return a response like #BLIGHT_ON!OK, but sometimes I receive for example #BLI_ON!O
What can be the cause of this? I made some serial communcation earlier with QtSerial <-> STM32 controller and had no such issues that would cause data loss.
First thing is that, I'm receiving all the input byte by byte (so each
read() call returns exactly 1 byte..) [...]
That's not surprising. The response is coming back at 9600 baud, which is likely much slower per byte than one iteration of the loop requires. It would also arise directly from some configurations of the serial driver. It should be possible to tune this by manipulating VMIN and VTIME, but do note that that requires disabling canonical mode (which you probably want to do anyway; see below).
When using nonblocking mode without select() I'm receiving all bytes,
but I don't know when to stop receiving (and I want it to be
universal, so I send a command, expect a simple response and if there
is no more data then just exit). I made a time counter since the last
message, so if nothing was received in last ~500ms then I assume
nothing more will come. But this sometimes loses some bytes of the
response and I don't know why.
It's all in the details, which you have not presented for that case. We cannot therefore speak to your particular data losses.
Generally speaking, if you're working without flow control, then you have to be sure to read each byte before the next one arrives, on average, else pretty soon, new bytes will overwrite previously-received ones. VMIN and VTIME can help with that, or one can try other methods for tune read timing, but note well that a 9600 baud response will deliver bytes at a rate exceeding one per millisecond, so a 500 ms delay between read attempts is much too long. Supposing that the particular responses you are trying to read are relatively short, however, this will not explain the data losses.
When using blocking mode, I receive correct bytes (still byte by byte
though), but I don't know when to stop and the last call to read()
leaves the program hanging, because nothing else comes in the input.
So the command is required to be CRLF-terminated, but the response cannot be relied upon to be likewise terminated? What a rude device you're working with. If it terminated its responses the same way it required terminated commands, then you could probably work in canonical mode, and you could definitely watch for the terminator to recognize end-of-transmission.
When adding select() to the blocking call, to see if input is
readable, I get very frequent data loss (sometimes just receiving a
few bytes), and sometimes select returns 1, but read() blocks, and I'm
left hanging.
I cannot suggest what the problem may be in that case without any relevant code to analyze, but you really shouldn't need select() for this.
When I just send data without doing any reading, and look at the input
using cat -v < /dev/ttyS3 I can actually see correct input on the
serial port all the time,
That's a good test.
however when I run both cat and my program
as receivers, only one of them gets the data (or cat receives a few
bytes and my program a few),
That's exactly as I would expect. Once a program reads a byte from the port, it is no longer available for any other program to read. Thus, if multiple programs try to read from the same port at the same time then the data available will be partitioned among them in some unspecified and not necessarily consistent fashion.
this suggests me that something is
"stealing" my bytes the same way when I try to read it, but what could
it be, and why is it like that?
That seems unlikely, considering that cat is not affected the same way when you run it alone, nor (you report) are some versions of your own program.
In the first place, if the device supports flow control then I would enable it. Hardware flow control in preference to software flow control if both are viable. This is mainly a fail-safe, however -- I don't see any reason to think that flow control is likely to actually trigger if your program is well written.
Mainly, then, in addition to setting the serial line parameters (8/n/1), you should
Disable canonical mode. This is necessary because you (apparently) cannot rely on the response to be terminated by a line terminator, among other reasons.
Disable echo.
Avoid enabling non-blocking mode on the file.
(Optional) read the first response byte with VMIN == 1 and VTIME == 0; this allows for an arbitrary delay before the device starts sending the response. Alternatively, if you have a reliable upper bound on the time you're willing to wait for the device to start sending the response then you can probably skip this step by using a suitable VTIME in the next one. Or perhaps use a a larger VTIME for this first byte to accommodate a delay before start of transmission, yet not hang if the device fails to respond.
Do read the remaining response bytes with VTIME == 1 (or larger) and VMIN == 0. This probably gets you the whole remainder of the response in one call, but do repeat the read() until it returns 0 (or negative). The 0 return indicates that all available bytes have been transferred and no new ones were received for VTIME tenths of a second -- much longer than the inter-character time in a 9600-baud transmission even for VTIME == 1. Do note that the larger you make VTIME, the longer will be the delay between the device sending the last byte of its response and the program detecting end-of-transmission.
Do not implement any artificial delay between successive read attempts.
You should not need non-blocking mode at the fcntl level, and you should not need select(). There may be other termios settings you could apply to better tune your program for the particular device at the other end of the serial link, but the above should be enough for single-command / single-response pairs with ASCII-only data and no control characters other than carriage returns and newlines.
I'm using a RedBearLabs Blend V2 to communicate with a SPI peripheral. Everything is functioning correctly at this point and I am receiving the expected data using SPI.write() and catching the return value. The SPI bus is running at 1 MHz in mode 0.
The image below shows the SPI bus connected to a scope. Trace 1 is SCLK, 2 is MISO, 3 is MOSI and 4 is CS. As you can see, I have 4 bursts of SCLK whilst CS is low, each 8 bits in length with a delay of approximately 20 µs in between each burst. Ideally, I need to completely alleviate this 20 µs delay and have 1 SCLK burst of 32 cycles.
The below code is how I am currently achieving what is seen in the scope grab.
int16_t MAX1300::sampleChannel(uint8_t channel, uint8_t inputMode, uint8_t adcMode)
{
int16_t sample;
int8_t hi = 0;
int8_t lo = 0;
MAX1300::InputWord_u word;
word.bits.start = 0b1;
if (inputMode == MAX1300::SINGLE_ENDED) {
word.bits.select = (Channels_se_e)channel;
} else {
word.bits.select = (Channels_dif_e)channel;
}
word.bits.payload = 0b0000;
if (adcMode == MAX1300::EXT_CLK) {
m_cs = 0;
m_spiBus.write(word.all);
m_spiBus.write(7);
hi = m_spiBus.write(0);
lo = m_spiBus.write(0);
m_cs = 1;
}
sample = ((int16_t)hi << 8) | lo;
return sample;
}
So far I have tried setting SPI.format(16, 0) with the intention of having 2 SCLK bursts of 16 cycles, however the SPI bus no longer functions if I do this. The same happens if I use SPI.transfer() with 32-bit buffers - no SPI bus.
I am able to increase the frequency of the bus, thus reducing the delay between each SCLK burst, however this is not really a suitable solution due to the end-application for this device.
What am I doing wrong here, or is what I am attempting to do just not possible with this hardware/firmware combination?
Thanks, Adam
I have been sending serial data with an arduino via bluetooth to my computer. Here is the sample arduino code.
long interval=10;
long previousMs=0;
int k=1000;
int K=9999;
void setup() {
Serial1.begin(115200);
}
void loop() {
unsigned long currentMs = millis();
if(currentMs - previousMs > interval) {
previousMs = currentMs;
k=k+1;
Serial1.println(k);
if(k>K){
k=1000;
}
}
}
This is the relevant part of my .cpp code that reads the data. I changed it a bit to print out the number of bytes read. It should be 6 every time (4 digits, carriage return, new line), but every once in a while it will give 5,4,3,2, or 1.
int read_bt(PORTTYPE port, char *buf, int bytes_to_read)
{
COMMTIMEOUTS timeout;
DWORD n = 0;
BOOL r;
FILE *fp;
fp = fopen("C:\\Users\\Myname\\Documents\\Visual Studio 2013\\Projects\\Project2\\Debug\\BT_Constant.txt", "w+t");
GetCommTimeouts(port, &timeout);
timeout.ReadIntervalTimeout = MAXDWORD; // non-blocking
timeout.ReadTotalTimeoutMultiplier = 0;
timeout.ReadTotalTimeoutConstant = 0;
SetCommTimeouts(port, &timeout);
while (1){
// Get and clear current errors on the port.
if (!ClearCommError(fd, &dwErrors, &comStat))
// Report error in ClearCommError.
exit(0);
// Get error flags.
fDNS = dwErrors & CE_DNS;
fIOE = dwErrors & CE_IOE;
fOOP = dwErrors & CE_OOP;
fPTO = dwErrors & CE_PTO;
fMODE = dwErrors & CE_MODE;
fBREAK = dwErrors & CE_BREAK;
fFRAME = dwErrors & CE_FRAME;
fRXOVER = dwErrors & CE_RXOVER;
fTXFULL = dwErrors & CE_TXFULL;
fOVERRUN = dwErrors & CE_OVERRUN;
fRXPARITY = dwErrors & CE_RXPARITY;
if (comStat.cbInQue != 0){
// comStat.cbInQue bytes have been received, but not read
r = ReadFile(fd,
buf,
bytes_to_read,
&n,
NULL);
}
fprintf(fp,"%d\n", n);
printf("%d\n", n);
}
}
I thought about sharing the output text file but I can't think of the best way to do that. Basically it is just a ton of "6"'s and its scattered with 1-5 in various spots.
I am working on an project with EEG data so a very high resolution and low latency is required. I was wondering if there was an issue with any of my code or if it was more likely a hardware issue with the bluetooth module I am using (HC-05 BT 2.0EDR).
If anyone can shed some light on to why this is happening I would definitely appreciate it!
The OS sends a "received new bytes on the interface" whenever it wants. If you send, let's say, the string "Hello" (5 bytes), it can (and usually does this) just notify you once that you received 5 bytes, but that's not guaranteed. It can notify you the first two bytes and then the other three, or 3-2, or even 1-1-1-1-1.
That's why you should see the return value of ReadFile which, I suppose, gives you the actual number of read bytes, and then loop until you read every byte you need.
We don't know what is the actual output of your program, but I bet that whenever you found some "5-4-3-2-1" they were paired in such a way that the sum was exactly 6..
Anyway, you say that you need a "low latency system". Then avoid printing it in text format (6 bytes), but use the binary mode (for any number under 65536 you need just two bytes).
Bye
I'm sending large data (well… 1Mb) via socket, but I don’t know why the send action is blocking the program and never ends. Small sends runs perfectly and I’m couldn’t found where is the problem here. Can anyone help me, please?
Thank you in advance for any help you can provide.
int liResult = 1;
int liConnection = 0;
int liSenderOption = 1;
struct addrinfo laiSenderAddrInfo;
struct addrinfo *laiResultSenderAddrInfo;
memset(&laiSenderAddrInfo,0,sizeof(laiSenderAddrInfo));
laiSenderAddrInfo.ai_socktype = SOCK_STREAM;
laiSenderAddrInfo.ai_flags = AI_PASSIVE;
liResult = getaddrinfo(_sIp.c_str(), _sPort.c_str(), &laiSenderAddrInfo, &laiResultSenderAddrInfo);
if (liResult > -1)
{
liConnection = socket(laiResultSenderAddrInfo->ai_family, SOCK_STREAM, laiResultSenderAddrInfo->ai_protocol);
liResult = liConnection;
if (liConnection > -1)
{
setsockopt(liConnection, SOL_SOCKET, SO_REUSEADDR, &liSenderOption, sizeof(liSenderOption));
liResult = connect(liConnection, laiResultSenderAddrInfo->ai_addr, laiResultSenderAddrInfo->ai_addrlen);
}
}
size_t lBufferSize = psText->length();
long lBytesSent = 1;
unsigned long lSummedBytesSent = 0;
while (lSummedBytesSent < lBufferSize and lBytesSent > 0)
{
lBytesSent = send(liConnection, psText->c_str() + lSummedBytesSent, lBufferSize - lSummedBytesSent, MSG_NOSIGNAL);
if (lBytesSent > 0)
{
lSummedBytesSent += lBytesSent;
}
}
Check the buffer size, you can do so by following this answer
How to find the socket buffer size of linux
In my case, the values are
Minimum = 4096 bytes ~ 4KB
Default = 16384 bytes ~ 16 KB
Maximum = 4022272 bytes ~ 3.835 MB
You can tweak the values net.core.rmem_max and net.core.wmem_max in /etc/sysctl.conf to increase the socket buffer size and reload with sysctl -p.
Source: http://www.runningunix.com/2008/02/increasing-socket-buffer-size-in-linux/
The send() call blocks until all of the data has been sent or buffered. If the program at the other end of the socket isn't reading and thus there is no flow of data, the write buffer at your end will fill up and send() will block. Chances are that when you tried to send a smaller amount of data it fit into the buffer.
See also this answer.
For TCP, the kernel has a fixed size buffer in which is stores unsent data. The size of this buffer is the current window size of the TCP session. Once this buffer is full any new send will be failed. This is a TCP flow control mechanism which prevents you from trying to send data faster than the receiver can consume the data while at the same time providing an automatic resend for lost data. The default window can be as small as 64K but can grow larger for high latency high bandwidth networks.
What you probably need to do is break the data up into smaller send blocks and then ensure you have a flow-off mechanism for when your send buffer is full.
I'm trying to establish a SerialPort connection which transfers 16 bit data packages at a rate of 10-20 kHz. Im programming this in C++/CLI. The sender just enters an infinte while-loop after recieving the letter "s" and constantly sends 2 bytes with the data.
A Problem with the sending side is very unlikely, since a more simple approach works perfectly but too slow (in this approach, the reciever sends always an "a" first, and then gets 1 package consisting of 2 bytes. It leads to a speed of around 500Hz).
Here is the important part of this working but slow approach:
public: SerialPort^ port;
in main:
Parity p = (Parity)Enum::Parse(Parity::typeid, "None");
StopBits s = (StopBits)Enum::Parse(StopBits::typeid, "1");
port = gcnew SerialPort("COM16",384000,p,8,s);
port->Open();
and then doing as often as wanted:
port->Write("a");
int i = port->ReadByte();
int j = port->ReadByte();
This is now the actual approach im working with:
static int values[1000000];
static int counter = 0;
void reader(void)
{
SerialPort^ port;
Parity p = (Parity)Enum::Parse(Parity::typeid, "None");
StopBits s = (StopBits)Enum::Parse(StopBits::typeid, "1");
port = gcnew SerialPort("COM16",384000,p,8,s);
port->Open();
unsigned int i = 0;
unsigned int j = 0;
port->Write("s"); //with this command, the sender starts to send constantly
while(true)
{
i = port->ReadByte();
j = port->ReadByte();
values[counter] = j + (i*256);
counter++;
}
}
in main:
Thread^ readThread = gcnew Thread(gcnew ThreadStart(reader));
readThread->Start();
The counter increases (much more) rapidly at a rate of 18472 packages/s, but the values are somehow wrong.
Here is an example:
The value should look like this, with the last 4 bits changing randomly (its a signal of an analogue-digital converter):
111111001100111
Here are some values of the threaded solution given in the code:
1110011001100111
1110011000100111
1110011000100111
1110011000100111
So it looks like the connection reads the data in the middle of the package (to be exact: 3 bits too late). What can i do? I want to avoid a solution where this error is fixed later in the code while reading the packages like this, because I don't know if the the shifting error gets worse when I edit the reading code later, which I will do most likely.
Thanks in advance,
Nikolas
PS: If this helps, here is the code of the sender-side (an AtMega168), written in C.
uint8_t activate = 0;
void uart_puti16(uint16_t val) //function that writes the data to serial port
{
while ( !( UCSR0A & (1<<UDRE0)) ) //wait until serial port is ready
nop(); // wait 1 cycle
UDR0 = val >> 8; //write first byte to sending register
while ( !( UCSR0A & (1<<UDRE0)) ) //wait until serial port is ready
nop(); // wait 1 cycle
UDR0 = val & 0xFF; //write second byte to sending register
}
in main:
while(1)
{
if(active == 1)
{
uart_puti16(read()); //read is the function that gives a 16bit data set
}
}
ISR(USART_RX_vect) //interrupt-handler for a recieved byte
{
if(UDR0 == 'a') //if only 1 single data package is requested
{
uart_puti16(read());
}
if(UDR0 == 's') //for activating constant sending
{
active = 1;
}
if(UDR0 == 'e') //for deactivating constant sending
{
active = 0;
}
}
At the given bit rate of 384,000 you should get 38,400 bytes of data (8 bits of real data plus 2 framing bits) per second, or 19,200 two-byte values per second.
How fast is counter increasing in both instances? I would expect any modern computer to keep up with that rate whether using events or directly polling.
You do not show your simpler approach which is stated to work. I suggest you post that.
Also, set a breakpoint at the line
values[counter] = j + (i*256);
There, inspect i and j. Share the values you see for those variables on the very first iteration through the loop.
This is a guess based entirely on reading the code at http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx#Y228. With this caveat out of the way, here's my guess:
Your event handler is being called when data is available to read -- but you are only consuming two bytes of the available data. Your event handler may only be called every 1024 bytes. Or something similar. You might need to consume all the available data in the event handler for your program to continue as expected.
Try to re-write your handler to include a loop that reads until there is no more data available to consume.