Peek more than one character (HardwareSerial)

I have seen another post like this but it did not quite address the problem. I have created a library to insert in other peoples code. At the top of their loop, they will call a function from my library.

My function needs to look at what is in the serial buffer to see if "#Reset#" or "#Reload#" or any other predefined string is present. If the string is there, get it off the buffer and call the appropriate function in my library or perhaps return something so they can select their own function to call. If the strings are not present, leave everything in the buffer and simply return so the rest of their program can read the buffer and do whatever with it as if my code was not even there. Although I am looking for a string in the serial buffer, the rest of the time the data could be binary or whatever.

The main thing here is that unless the string is in the serial buffer, their code should behave like my function was never called. Also, I do not want to require the user to modify their existing library files or change their code because "Serial" has changed. They should basically be able to add my library and put my function call at the top of their loop. I don't mind if they have to add a little something at the top of setup or something as well. I also don't mind requiring them to have a newer version of Arduino.

I could see passing an array into "peek" so it could be filled with what is in the buffer and return the number of bytes copied (up to a size limit passed in). Or maybe another peek function that moves the pointer each time you call it with a way to reset it. I've even thought about somehow reassigning "Serial" to be a new HardwareSerial class with an extension that provides my new peek function. I have not got that to work besides I suspect serialEvent would be affected.

Any suggestions would be appreciated. In the event that a developer who submits changes to the Arduino library is reading this, the idea of passing an array into "peek" seems like a good solution if nobody else has a better idea that does not involve changing the library. The problem I see with a moving peek is that you would also need a moving available. You can't return a -1 if the last byte in the buffer is reached because -1 is a perfectly valid number if the data is binary.

Dave

My sense is that you are trying to detect the data at the wrong point in the process. Why not read all the incoming data into a buffer and then look for particular sequences of characters at your leisure. That is the underlying concept in Serial Input Basics

The HardwareSerial buffer can only hold 64 bytes and the sort of sequences you are looking for take up a lot of that - especially if data continues to arrive while you are checking for a sequence.

What is the purpose of the library you are developing?

...R

The reason for not immediately reading the incoming buffer is that it would require whoever uses my library to make modifications throughout their code because the data on the serial port would no longer be there but would be in my byte array. If I could make "Serial" point to my own class that behaves just like the normal Serial does except I have pulled the serial port data into my own array, that would be fine. I suspect this can not work if for no other reason, I believe the serialEvent would no longer work correctly. Although I can create an instance of my own class and call it SerialDave, the person using the library would still have to go through their code and rename "Serial" to "SerialDave". Honestly I still have not figured out how "Serial" is getting created when at first glance the HardwareSerial constructor seems to require parameters that are not being provided.

The reason this whole project came into existence is I converted my code to receive its communication over Bluetooth. I also want to be able to reprogram over Bluetooth. When a new program is sent, the first thing it does, like all programs, is connect to the serial port. The Bluetooth module can detect when this port connection is made and cause a low to be sent to the reset pin. As the board boots up, it looks for the new program and loads it.

When I am not trying to load a new program, the reset should not get triggered due to the Bluetooth serial port connecting. So, I created a library that would read all the data on the serial port into my own byte array and see if it matched one of a couple of predefined strings. If the data equaled "#Reset#", I would immediately send a low to the reset pin. If it equaled "#ReLoad#", I would set a flag that the next time the Bluetooth connected (unless it took to long to connect), it should send a low to the reset pin because it is expecting new code to get loaded.

Pulling the data into my own byte array works great in my code so I made the library for my son to add it to his project. Low and behold, I broke his project because his code tried to read off the serial port and nothing is ever there. This is why I want to see if the first several bytes at the serial port are one of a set of predefined strings without pulling them off the serial port.

The more I think about it, the less sense it makes to add a peek string. It just goes against the standard. This would be the only place where a serial port in C offered a peek with string ability.

Having said that, any suggestions on how to do this will be appreciated. In a nutshell:

1.) Somebody has an existing program that uses serial communication
2.) They replace USB with Bluetooth, this requires no change in code except maybe baud rate
3.) Without rewriting their existing code, how can I add code that will detect a desire to send a new program and load a new program when it is sent?

dave_flyer:
3.) Without rewriting their existing code,

Perhaps this is an unreasonable constraint you are imposing on yourself.

The circumstances you describe are a little unusual and it would not be unreasonable for the user to take some extra steps.

Perhap you could write a function that they must call from loop() in the same way that the AccelStepper library requires a call to stepper.run(). It could even be a function that they must visibly include in their own program.

Indeed your function could also act as a convenience on which they could build their program - take the data from the serial buffer, review it, and then make it available.

...R

Question pops up

Suppose the internal serial buffer contains "abc#reset#def".

Does your function removes the "#reset#" part from the serial buffer?
Or does it remove "abc#reset#" ? => I've lost "abc"

if it doesn't remove the #reset# it will detect it in every loop until it is read?

"Perhap you could write a function that they must call from loop() in the same way that the AccelStepper library requires a call to stepper.run(). "

I do agree that I seem to be making a constraint that I can not adhere to. As eluded to above, I have always intended that they must ADD some lines of code at the top of their loop. They also would probably have to add something in the setup and certainly they would have to add an include file and possibly a little more. I was just hoping they would simply drop in a few lines of code but not have to change any code inside their existing functions.
My current line of thinking is they have to replace the variable "Serial" with something like "SerialDave" which would behave in every other way like it was the Serial variable except this added peek feature. This would be about the most painless way I can think of to modify their code. However, I think they would lose the serialEvent capability. I might be OK with that just not preferable.

"Suppose the internal serial buffer contains "abc#reset#def"."

Although I have the liberty to make it behave any way I want, currently I am looking for the user to very explicitly indicate they want a reset. Therefore, my current code simply reads what is currently waiting in the serial buffer. Hence, I would detect "#reset#" but not "in#reset#the middle" or even "#reset#more stuff". I think it is reasonable that the user must have stopped sending anything else to the buffer before the reset command is sent. This would leave the reset command being the only thing in the buffer.

"if it doesn't remove the #reset# it will detect it in every loop until it is read?"

It doesn't detect it in every loop because I only look at what is currently in the port buffer. The first thing I do is read everything out of the buffer so nothing is left behind going into the next loop.

Tell you what, let me see if I can do another post here in a minute and I will simply include the current draft of my code.

OK. I have attached my current code. It is an actual library and can be loaded as such. After loading the library, You should have my sample code in the Examples menu as BlueToothLoader->Bluetooth.

Keep in mind, I am relatively new to Arduino so if you see something I am doing would be better accomplished in a more "Arduino" way, feel free to make suggestions. I'm open to criticism.

As you can see I currently pull everything off the port and pass it into the original loop function, unless I determine that the message is reset related in which case their code never sees it. Then it is up to the user to pull data from my array and potentially wait for and pull more data from the serial port. I admit that my sample code does not actually use any of the data from the serial port but this is intended to be used with any project that is being moved from USB to Bluetooth.

My original goal was that the users existing code would be completely unaffected by adding my lines of code. That seems ambitious. I don't see any way to detect something on the serial port without removing it which by definition affects their code.

My next thought is to create my own serial communication class that behaves exactly like the existing "Serial" except I can peek for a string. Their code would have to use my class instead of "Serial".
They simple search for Serial and replace it with the name of the variable that is my class. I assume this means using HardwareSerial as a base class in my class to reduce the amount of code. Any thoughts?

BlueToothLoader.zip (430 KB)