I am a new programmer, so I am having a bit of problem with Serial communication of Arduino.
I am trying to read data from serial Input, sent by a simulation as characters and I need to store it as integer to write it with my servo.
I found this https://forum.arduino.cc/t/serial-input-basics-updated/382007 tutorial and example 4 does the job,
However, the simulation sends the data so fast that Arduino bottlenecks and the data pile up in the serial port and even if I stop the simulation the Arduino continues to perform the messages.
How can I slow down the data receiving like read data every 0.3 seconds instead. I tried to put some delays but it seems like it doesn't work.
Also, how can I change the code in a way that it stops performing new thing when there is no new serial messages and cancel the ones in the queue?
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
//SERVO//
#include <Servo.h>
Servo myservo; // create servo object to control a servo
////////////////////////
int dataNumber = 0; // new for this version
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithEndMarker();
showNewNumber();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
if (Serial.available()> 0) {
rc = Serial.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
delay(1);
}
}
}
void showNewNumber() {
if (newData == true) {
dataNumber = 0; // new for this version
dataNumber = atoi(receivedChars); // new for this version
Serial.print("This just in ... ");
Serial.println(receivedChars);
Serial.print("Data as Number ... "); // new for this version
Serial.println(dataNumber); // new for this version
myservo.write(dataNumber); // sets the servo position according to the scaled value
delay(50);
newData = false;
}
}
Thanks!
Welcome to the forum.
I'll admit that I don't know about your arduino set-up, but I hope that I can help.
Serial ports are asynchronous sources of data.
For base 3 wire RS-232, the receiver can't control the speed at which data is received other than baud rate hence received data is copied into a buffer (array) before it is processed.
This is to give your code time to process the received data before more messages arrive and cause what is known as a buffer overrun, corrupting data already received. Think of the serial link as being a hose pipe filling a bucket (the buffer) with water and you emptying it using a cup (your processing).
If your processing code is running too slowly and you are losing data then one option is to increase the size of the reception buffer, say from 32 to 255.
Adding delays to the reception code will only make matters worse.
An important point to make is that you must ensure that any processed data is removed from the buffer otherwise it will be processed again.
If your processing is fast enough then a nasty method is to just clear the buffer of all data by setting all array values to 0.
Another method is to use is keep a records (index value) of the next available location to write to and read from.
Data from the serial port is written into the buffer address using the write index value saved previously as a starting point. It is updated to take into account the size of the data written and incremented to indicate where to start the next write operation.
Your processing reads from the buffer using the last read index until it detects your end of message indicator and increments the read index to indicate the next location to read from.
It may be that your arduino serial port supports hardware flow control raising a Ready To Receive line when the hardware buffer (in the serial port itself) is full. This would be set before you open it.
Code:
Remove Delay calls - they only slow down your code.
Sending data out Serial.print, Serial.println commands take time,
place those after myservo.write
Remove Serial.print type commands that aren't strictly necessary.
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 have tried to create wireless PWM transmission using 433Mhz transmitter modules. I found this library for transmiting https://github.com/zeitgeist87/RFTransmitter and this library for reading PWM values on some pin https://github.com/xkam1x/Arduino-PWM-Reader.
I wrote code for sending PWM values:
#include "PWM.hpp"
#include <RFTransmitter.h>
#define NODE_ID 1
#define OUTPUT_PIN 11
RFTransmitter transmitter(OUTPUT_PIN, NODE_ID);
PWM my_pwm(2);
// the setup function runs once when you press reset or power the board
void setup() {
my_pwm.begin(true);
}
// the loop function runs over and over again forever
void loop() {
int pwmValue = my_pwm.getValue();
char stringValue[4];
itoa(pwmValue, stringValue, 10);
transmitter.send(stringValue, strlen(stringValue) + 1);
}
And similar code for receiving
#include <Servo.h>
#include <PinChangeInterruptHandler.h>
#include <RFReceiver.h>
int PWM_out_pin = 9;
Servo servo;
// Listen on digital pin 2
RFReceiver receiver(2);
void setup() {
servo.attach(PWM_out_pin);
receiver.begin();
}
void loop() {
char msg[MAX_PACKAGE_SIZE];
byte senderId = 0;
byte packageId = 0;
byte len = receiver.recvPackage((byte *)msg, &senderId, &packageId);
String *stringObject = new String(msg);
servo.writeMicroseconds(stringObject->toInt());
}
It works, but it has few problems.
First is that is not optimal. I transforming all to string. How can I send int values from PWM directly?
Second problem is that it has about 1 sec delay. Does it possible make it faster? I need it for realtime controlling servo.
Thanks.
How can I send int values from PWM directly?
transmitter.send((char*)pwmValue, sizeof(int));
Then on the receive side, you don't need to convert the data to a string.
servo.writeMicroseconds((int) *msg);
(int) and (char*) are C-style typecasts. Essentially telling the compiler that you want the data to be interpreted as a different variable type.
WARNING: Be careful with the "new" keyword, you are dynamically allocating memory. Rule of thumb in C/C++: Wherever you use the "new" keyword there should be a corresponding "delete" call that cleans up the memory.
In terms of making it faster, your C/C++ code here is not the limiting factor causing the 1 sec latency from command to action. Most likely there is a parameter in your RF transmitter transmit/receive stack that needs to be tweaked. Before sending PWM values, I would benchmark your latency of sending and printing out a simple string.
Specific problem
I am trying to communicate between a Python script and my Arduino Pro Mini using serial with a USB cable. In Python I can read what the Arduino writes but the Arduino can either not read what the Python writes or it is reading it in a form that I can't process. The most obvious way this manifests itself is when I try to write what the Arduino has just read from Python, to Python. Nothing gets displayed in Python.
My Arduino sketch appears to work just fine when I work with it in the Serial Monitor, i.e. it can read and write so I suspect it is something at the Python end. What's causing this?
Details
I want to be able test how quickly I can send 64 byte-long pieces of information to my Arduino. To do this I wrote a Python script that could should be able to periodically send various information to my Arduino. I can change the period and thus test what kind of speed I can get.
However, despite the fact that my Arduino sketch works just fine with Serial Monitor, i.e. I can send it information and read information from it, I can't get it to work with Python.
With my Python script I can open the connection and read what the Arduino writes, but for some reason there is a problem with writing from Python. I have tried the following but none of them have worked:
Using an Uno instead of a Pro Mini.
Putting a Serial.println() statement in my get_data() function. Nothing gets printed.
Sending a string with the format "T(number);" and using sscanf() to extract the number. Using an if statement to examine the number and turn an onboard LED on. Did not work.
Sending a string beginning with "T" and using an if statement to see if it is stored in raw_data[]. It isn't.
Writing the data from Python at different times (i.e. using a longer delay).
Writing from Python using device.write(b"mystring") and device.write("mystring".encode())
I'm at a loss for what to try next…
Python (2.7) code
import serial, time, random, string
device = serial.Serial('/dev/tty.usbserial-A105YOZX', baudrate = 38400)
initial_time = time.time()
current_time = time.time()
counter = 0
control = 0
while counter < 1000:
current_time = time.time()
if current_time - initial_time > 0.1:
initial_time = current_time
counter += 1
device.read()
if current_time - initial_time > 1 and control == 0:
device.write(b"Message being sent")
control = 1
Arduino code
#define RAW_LEN 64 //max length of incoming string (buffer size is only 64 bytes)
//variables for incoming data
char raw_data[RAW_LEN];
int raw_data_i = 0; //index
unsigned long my_time;
int control = 0;
int for_print;
int get_data(int i) {
//fills up raw_data[] with serial data. Clears raw_data if it gets too long
if (Serial.available()>0) {
raw_data[i] = Serial.read();
Serial.println(raw_data[i]);
//Serial.println(raw_data[i]);
if (i<RAW_LEN-1){
i++;
}
}
return i;
}
void clear_data() {
//clears raw_data and resets raw_data_i
raw_data_i = 0;
memset(raw_data,'\0',RAW_LEN-1);
}
//print functions
void raw_print(char data[]) {
Serial.println("Received data: ");
//if (raw_data[0] == 'T') {digitalWrite(LED_BUILTIN, HIGH);}
for (int i=0; i< RAW_LEN;i++) {
Serial.println(data[i]);
}
}
void setup() {
Serial.begin(38400);
Serial.println("Restart");
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
my_time = millis();
raw_data_i = get_data(raw_data_i);
//clear raw_data if it gets full
if (raw_data_i == RAW_LEN-1) {
clear_data();
}
if (my_time > 5000 && control == 0) {
Serial.println("Here");
raw_print(raw_data);
control = 1;
}
}
The problem turned out to be in the Python code. In while loop the first if statement is True after 0.1s, and then executes 9 more times before the second if statement is True.
The problem with this is that device.read() just hangs if it does not receive a character. Because I wasn't sending enough characters from the Arduino the Python code paused at the device.read() and never got to the second if statement.
An annoying mistake that took a while to figure out, hopefully this question and answer will save someone else a lot of debugging time.
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.