How to un-block blocking code

I'm going to take a stab that

    while ((n = rdfile.fgets(line, sizeof(line))) > 0)
      { Serial.print(line); }

is blocking code; such that once the while loop is entered it does nothing but read from the SD card and write to the serial port. Is that correct?

At this time I will assume it is. The project is a datalogger. The program must be able to record the data on it's interval, while reading from the SD card and sending the data to the serial port to either be displayed in the serial monitor or be read by PLC-DAQ.

I am using the information from Serial Basics to process the incoming data which is non-blocking. But I'm not sure how to convert the response/output to non-blocking. Any thoughts appreciated.

Don't use that loop, write non-blocking code instead.

Why not to add isr on serial and flag it. Then check for flag in your while loop not to miss anything. Also timout would be good idea. If its in loop this much and nothing is happening which suppose to happen then exit it.

adwsystems:
The project is a datalogger. The program must be able to record the data on it's interval, while reading from the SD card and sending the data to the serial port to either be displayed in the serial monitor or be read by PLC-DAQ.

You need to provide more information.

In what circumstances should the data be read from the SD Card and in what circumstances should the program be doing something different?

How does the data get to be on the SD Card?

What does "record the data on it's interval" mean?

...R

surepic:
Why not to add isr on serial and flag it.

I don't see how that can be practical. The internal Serial code is already using the UART ISR and re-writing the serial library is not a trivial task.

...R

surepic:
Why not to add isr on serial and flag it.

Because the HardwareSerial class already has dibs on the interrupt?

i wouldn't describe that code as blocking. it should read until there is nothing else to read (i.e. EOF end-of-file) and then continue (execute code following the loop).

blocking is waiting for an event that occurs at an unpredictable time (e.g. input from a keyboard)

once the while loop is entered it does nothing but read from the SD card and write to the serial port. Is that correct?

Why use a while loop ? Replace it with an if and let loop() do the looping for you.

It would help considerably if you posted a complete program rather than just a snippet

jremington:
Don't use that loop, write non-blocking code instead.

Yeah. That is the question.

UKHeliBob:
Why use a while loop ? Replace it with an if and let loop() do the looping for you.

It would help considerably if you posted a complete program rather than just a snippet

I'm working on how to post it. Code tags is so far out of the question it isn't even a question.

gcjr:
i wouldn't describe that code as blocking. it should read until there is nothing else to read (i.e. EOF end-of-file) and then continue (execute code following the loop).

blocking is waiting for an event that occurs at an unpredictable time (e.g. input from a keyboard)

Yes a bad description but the only one I had. it does in fact block the rest of the program from running which is predicated on ISR flagged subroutines.

Robin2:
You need to provide more information.

In what circumstances should the data be read from the SD Card and in what circumstances should the program be doing something different?

How does the data get to be on the SD Card?

What does "record the data on it's interval" mean?

...R

The data logger records the data to the SD card in one minute intervals.

I have been working to develop a DOS like structure (though those posts went completely unresponded, so I'm on my own) with a few basic commands (rename, del, type) to access the data on the SD card. Most of the commands are short or have a short response time (like rename and del). Type and transfer (created to initiate sending data to PLC-DAQ spreadsheet) will have longer response as they transfer the data. Data files are created daily and expected to be about 1M each. The snippet is reach after serial data command initiates it.

Block Pseudo Code

loop()
if Serial.Available() then receive_serial()

receive_serial() // called from loop()
...follow serial basics to receive data
If end marker received (char 10 or 13) then process_command()

process_command() // called from receive_serial()
if command = type then type_command()
if command = transfer then transfer _command()

type_command() // called from process_command()
file.open()
while ((n = rdfile.fgets(line, sizeof(line))) > 0)
{ Serial.print(line); }
file.close()

Once the command is received for type or transfer, the program is 'stuck' in the command subroutine until the transfer completes. The timer ISR may flag a one-minute interval for data logging, but that check is in loop() which is not accessible while the type or transfer commands are executing.

adwsystems:
I'm working on how to post it. Code tags is so far out of the question it isn't even a question.

What does that mean?

We need to see the complete program.

Once the command is received for type or transfer, the program is 'stuck' in the command subroutine until the transfer completes.

Does that mean that you want to be able to send a command to transfer data and while the data is being transferred the Arduino will continue gathering new data?

If so the answer seems to be in Reply #7

...R

it does in fact block the rest of the program from running

What else could you possibly expect? The Arduino is not a multitasking computer; it runs one line of code at a time.

That code does NOT block interrupts, in fact it depends on them for .print(), at the very least.

I'm really surprised that a person with nearly 2000 posts needs to have this explained to them.

jremington:
What else could you possibly expect? The Arduino is not a multitasking computer; it runs one line of code at a time.

That code does NOT block interrupts, in fact it depends on them for .print(), at the very least.

I'm really surprised that a person with nearly 2000 posts needs to have this explained to them.

Thanks, but that response is not helpful and doesn't provide any detail I don't already know. I know it doesn't block interrupts. Best practice for ISR is to keep them short. If they are to trigger more than a 'short' routine (especially anything that triggers or requires other interrupts), then the ISR should set a flag and be processed by a subroutine in loop() (or main() ).

Robin2:
What does that mean?

We need to see the complete program.

It is way way longer than code tags allows and is in several files and library files.

Robin2:
Does that mean that you want to be able to send a command to transfer data and while the data is being transferred the Arduino will continue gathering new data?

If so the answer seems to be in Reply #7

...R

I believe so. I'm trying to determine the best way to merge serial basics methods with the how to do multiple things with the ISR flag with post 7. I'm thinking the output of receive_serial cannot be to execute the command. Put another way, receive_serial cannot call the command functions. Receive_serial needs to flag that a command is ready and loop() evaluate the flag and execute the command. That will allow #7 to be implemented.

Update from previous post:

Block Pseudo Code

loop()
if Serial.Available() then receive_serial()
if command_flag set process_command()

receive_serial() // called from loop()
...follow serial basics to receive data
If end marker received (char 10 or 13) then set command_flag

process_command() // called from loop()
if command = type then type_command()
if command = transfer then transfer _command()

type_command() // called from process_command()
file.open()
while ((n = rdfile.fgets(line, sizeof(line))) > 0)
{ Serial.print(line); }
file.close()

doesn’t provide any detail I don’t already know

You OBVIOUSLY did not understand why that is blocking code.

Before continuing to post on the topic, I suggest to study and actually learn how the Blink Without Delay example works.

Since the File class inherits from the Stream class, you can use the same non-blocking techniques as demonstrated in @Robin2’s ‘Serial In Basics’.

gfvalvo:
Since the File class inherits from the Stream class, you can use the same non-blocking techniques as demonstrated in @Robin2’s ‘Serial In Basics’.

I have (tried to) follow the serial input basics as well as the do multiple things, blink without delay, and ISR best practices. Using the useful responses to fill in some gaps, what has really happened is the resulting "showData equivalent" routine in my program has undone the non-blocking techniques already implemented. I need a way to incorporate a longer-duration showData subroutine. I need the best way to implement from the code

while ((n = rdfile.fgets(line, sizeof(line))) > 0)
      { Serial.print(line); }

in a "Serial Output without Delay" subroutine ("Serial Transfer without Delay"?); given that the serial output is trigger by serial input (but maybe that doesn't matter as much as the processor is much much faster than serial comms).

adwsystems:
I’m trying to determine the best way to merge serial basics methods with the how to do multiple things with the ISR flag with post 7.

Forget you ever heard of ISR flags. Yours is not a problem that needs interrupts to solve it.

Have you actually tried the very simple advice in Reply #7?

If so, please post the program based on that advice and tell us in detail what actually happens when you run it and what you want it to do that is different.

…R

Can't advise further without seeing real code. And no, we don't want to see your whole big, messy project. Make an MRE. Barring that, I'm out of here. Good luck.

Robin2:
Forget you ever heard of ISR flags. Yours is not a problem that needs interrupts to solve it.

Have you actually tried the very simple advice in Reply #7?

If so, please post the program based on that advice and tell us in detail what actually happens when you run it and what you want it to do that is different.

...R

I cannot forget them as they are a critical aspect of the program. Servicing the set flags has brought me to this point. You are correct that ISR flags (more of them, any of them, etc) will not solve this problem.

No I haven't tried the advice in reply #7, as noted I haven't figure out how to get from Post #1 to post #7. I haven't figured out how to solve post 14 (ie., implement suggest in post #7)

gfvalvo:
Can't advise further without seeing real code. And no, we don't want to see your whole big, messy project. Make an MRE. Barring that, I'm out of here. Good luck.

Working on turning the pseudo code in post 11 into arduino code. I had hoped while I was away from my hardware the problem could be solved.

adwsystems:
Working on turning the pseudo code in post 11 into arduino code.

Good plan. Also please identify the Arduino Board / Processor you're using. You may have done so already, but as the post is getting longer it's harder to scan through it.

I had hoped while I was away from my hardware the problem could be solved.

Hope is not a plan.

gfvalvo:
Good plan. Also please identify the Arduino Board / Processor you're using. You may have done so already, but as the post is getting longer it's harder to scan through it.

It will be a MEGA or UNO.

gfvalvo:
Hope is not a plan.

I also hope for more useful comments when I post here. That doesn't always happen either. But I can make the code happen.