How to use serialEvent ?

I am using Arduino Mega 1280 and trying to use the newer serialEvent way of reading from the serial port.
What i basically want to do is buffer the input till i get a newline, get a trigger via serialEvent and then process it.

here is my current code and the error that i get during compilation

void setup() {
  Serial.begin(9600);
  Serial.buffer(10);

}

void loop() {
  // put your main code here, to run repeatedly: 
  
}

void serialEvent(){
  Serial.println("Got 10 bytes");
}

ERROR:
BareMinimum.cpp: In function 'void setup()':
BareMinimum:2: error: 'class HardwareSerial' has no member named 'buffer'

My question is: Is the new serialEvent system really implemented in the Arduino 1.0 codebase ? and how to use it ?

Is the new serialEvent system really implemented in the Arduino 1.0 codebase ?

Yes. The buffer() method did not make the cut, though.

In the SerialEvent() method, you are actually supposed to read the data.

The function is called once per pass through loop, not as soon as the serial data arrives.

@PaulS Its just a sample code that i quickly wrote so that i can copy paste the error I got.

Is this method available in the current development version of arduino.

I am kinda curious why is serialEvent mentioned in the reference when its actually not in the code ?

serialEvent() is available. Serial.buffer() is not. Why it wasn't removed from the documentation is a question for the authors.

just took a look at the source of HardwareSerial

void serialEventRun(void)
{
#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implemented
  if (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implemented
  if (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implemented
  if (Serial3.available()) serialEvent3();
#endif
}

Apparently serialEvent is called for every received byte.
n yes, there doesnt seem to be any implementation of bufferUntil

serialEventRun() is only called after each execution of loop().

int main(void)
{
	init();

#if defined(USBCON)
	USB.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}

	return 0;
}

@dxw00d Yeah I saw that code in main.cpp What i wanted to say was there doesnt seems to be any implementation of bufferUntil in the codebase.

I downloaded the current development version of hardwareSerial.cpp https://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/HardwareSerial.cpp and there still doesnt seems to be an implementation for bufferUntil in it eighter.

I would have liked it if there was an existing code for that function. I would hate to reinvent the wheel.

Someone should make a note in the docs that buffer and bufferUntil are currently not implemented.

@OP - Please don't PM people unless they invite you to. Keep the conversation to the forum. I can't personally 'point you to a general interrupt driven AVR class for USART control'. Others here might be able to.

@dxw00d, I am trying to keep stuff thats offtopic out of this thread.
I know you would be bombarded by PM's on a daily basis but It would have been nice if you were less sulky in your reply.

dxw00d:
serialEventRun() is only called after each execution of loop().

It does appear to work this way, but then one wonders, what's the point? With the present implementation I cannot reliably send any significant length of data to an Arduino UNO at even 19200 bps without over running the fixed length internal serial buffer. I would have thought that the point of having an event for this was to make serial communication more reliable, but this seems like a step in the wrong direction. I did not have this problem with Arduino IDE 23.

William

With the present implementation I cannot reliably send any significant length of data to an Arduino UNO at even 19200 bps without over running the fixed length internal serial buffer.

Why not? You should be able to read serial data far faster than it arrives.

I did not have this problem with Arduino IDE 23.

Prior to 1.0, outgoing serial data was not buffered. Now, it is. In order to not increase the size of the Serial instance, the incoming buffer size was cut in half. The other half is now the outgoing buffer.

PaulS:
Why not? You should be able to read serial data far faster than it arrives.

One would think so, but it's not working that way. I am trying to fix the sketch for the "Arduino ISP" programmer so it works with IDE 1.0 (runs fine with 22 or 23). AVRdude is trying to send a 133 byte string, and it's getting truncated. The code is pretty simple:

String sBuffer = "";
void setup() {
  Serial.begin(19200); 
  sBuffer.reserve(256);
}

void loop(void) {
  // light the heartbeat LED
  heartbeat();
  // have we received a complete request?  (ends with CRC_EOP)
  if (EOP_SEEN) avrisp();
}

void serialEvent() {
  while (Serial.available())
  {
    char ch = (char)Serial.read();
    sBuffer += ch;  // add it to the buffer
    if (ch == CRC_EOP) EOP_SEEN = true;
  }
}

"avrisp" is the sub that handles all the requests. All of the short ones work fine. When AVRDude tries to write a page, the string is 133 chars - 4 bytes of descriptor, 128 of data, the EOP. The EOP character is never received.

William

FWIW - I'm using a serial port monitor to try to debug this. It captures all of the traffic nicely. The data sent by AVRDude definitely has the EOP (x'20') character.

String sBuffer = "";
  sBuffer.reserve(256);

If you know how big the array is that the String function should wrap, why do you need a String object? Storing data in a char array directly would be faster.

  while (Serial.available())
  {
    char ch = (char)Serial.read();
    sBuffer += ch;  // add it to the buffer
    if (ch == CRC_EOP) EOP_SEEN = true;
  }

If you see a CRC_EOP, set a flag and keep reading. Is that right? Wouldn't you want to break out of the loop and send the data to wherever avrisp() sends it?

What does avrisp() do? Perhaps the issue is that it is blocking for so long that data gets lost before avrisp() returns, and you get back to reading serial data.

You might try modifying the HardwareSerial class to increase the buffer size, to see if that makes any difference.

The code was originally written using a byte array. I changed it to use the string as that is the example given on arduino.cc. I'm not sure that one method is actually that much faster than the other though. It seems intuitive that a byte array would be faster but then you have to keep track of the pointers and check for overflow...

In this case it does not matter what avrisp() does. Since it is only called when an EOP is receiveed, it never gets called for the long request. It does get called for all of the short requests, there are several of these and they are all run and responded to. I have a port monitor report showing all of this working. Then AVRDude sends the 133 byte string, and only part of it gets thru, the rest is lost. Since the EOP is the last character, it is never seen, and the request times out. At this point the only thing running is the Serial Event loop.

With Arduino IDE 22 I can read all 133 characters without a hitch. With 1.0 it's getting truncated. I am very surprised by this, I would have expected to be able to easily keep up with the data at 19200 bps. The size of internal buffer should not be an issue but it appears that it is.

I know I can edit something in the IDE so that the buffer is larger, and I will try this to see if it helps, but I really don't want a solution that involves modifications to the Arduino IDE that will get wiped out by an upgrade.

Thanks for all the suggestions, it's all helpful and I appreciate your taking the time.

William

It seems intuitive that a byte array would be faster but then you have to keep track of the pointers and check for overflow...

As opposed to allocing and copying data. Well, I know which of those two operations is generally faster.

In this case it does not matter what avrisp() does. Since it is only called when an EOP is receiveed, it never gets called for the long request.

Only because you don't explicitly stop and call it when the EOP does arrive.

Then AVRDude sends the 133 byte string, and only part of it gets thru, the rest is lost. Since the EOP is the last character, it is never seen, and the request times out.

That's a different story. And difficult to prove. If only part of the data arrives at the Arduino, then the Arduino can be be faulted for not getting it all. If it all arrives at the Arduino, but does not all get added to the buffer, how would you know that? There is code in the Stream class (I think that's where it is) to check for overflow of the buffer. Perhaps you could light an LED when overflow occurs, to see if that is indeed the problem.

Though, I would be hard pressed to understand how that could occur, since reading is orders of magnitude faster than receiving.

With Arduino IDE 22 I can read all 133 characters without a hitch. With 1.0 it's getting truncated. I am very surprised by this, I would have expected to be able to easily keep up with the data at 19200 bps. The size of internal buffer should not be an issue but it appears that it is.

Since that is the only change that occurred, I guess I would tend to disagree with your conclusion.

Make a copy of HardwareSerial.h and HardwareSerial.cpp, with new names. Create an instance of the new class, and change the buffer size back to 128. Use your new instance in place of Serial, and see what happens. If it fixes the problem, then the Arduino team should look into the situation further.

I'm not sure where you are going with this, though. The avrdude command that you say is sending data is the function that talks to the bootloader, and initiates the process of loading a new sketch. I'm wondering if the "last successfully executed command" triggered some state change that is responsible for the issue you are having, rather than the size of the serial buffer.

You could, of course, test this by not calling avrisp when the EOP arrives. Just discard the data.

Allocing and copying data slow? .reserve helps with the allocing. copying at machine level isn't all that slow. But in any case none of this matters because it finally dawned on me that there are bytes of zeros in the data and that won't work with strings. So I'm back to a byte array.

I'm getting closer. I'm pretty sure I understand what is happening now - the original code in Arduino ISP is really dependent on the larger serial buffer of the older IDE because it isn't reading the data as it arrives, but rather when it needs it. That worked fine as long as all of the request block fit in the buffer but with IDE 1.0 that's no longer true. I've made changes to improve this but I still have one timing issue.

More to come...