SoftwareSerial Multiple Instances implementation

I have a situation where I have 4 Rx ports at 4800bps and a PC connection at 115200bps. I want to be able to listen to the 4 ports simultaneously, process data and send it to the PC. I expect the overall data rate of the 4 combined ports to be around 3500bps, so there is absolutely no bottleneck issue.

Has anyone changed the SoftwareSerial class to allow this? I've poked around and it seems I can do it by just ignoring the "active_object" concept.

I want to be able to listen to the 4 ports simultaneously

Not with an Arduino, you can't. You need something with 5 hardware serial ports.

I expect the overall data rate of the 4 combined ports to be around 3500bps, so there is absolutely no bottleneck issue.

You appear to think that no two devices will try to talk to the Arduino at one time. That is not a realistic expectation.

Has anyone changed the SoftwareSerial class to allow this?

It can't be done. SoftwareSerial relies on pin change interrupts. Only one pin at a time can be generating the interrupt that SoftwareSerial cares about.

I've poked around and it seems I can do it by just ignoring the "active_object" concept.

But, you can't. If some device that is not the active object talks to the Arduino, it will be ignored.

You could switch the active object often, or you could make the objects that you are listening to respond only when asked for data.

Changing the active object often does not guarantee that you will be listening to a device when it starts talking.

Changing the objects that you are listening to may not be possible.

If that is the case, you need different hardware.

Looking at the original code (NewSoftSerial | Arduiniana), it seems the issue is bandwidth, not interrupts. Here is a quote from the author:

However, handling asynchronously received data from two, three, or four or more serial devices turns out to be an extremely difficult, if not intractable problem. Imagine four serial devices connected to an Arduino, each transmitting at 38,400 baud. As bits arrive, Arduino’s poor little processor must sample and process each of 4 incoming bits within 26 microseconds or else lose them forever. Yikes!

And I expect that up to 4 devices will be talking to arduino simultaneously.

I have a situation where I have 4 Rx ports at 4800bps and a PC connection at 115200bps.

You could do that with an Arduino Mega as it has 4 hardware serial ports and you could add one SoftwareSerial to have your 5 serial ports concurrently. With a standard UNO your project will fail.

I'm already using a MEGA board, but I need the SoftwareSerial library for TTL signal inversion...

... and doing the inversion in hardware is no option?

PaulS: It can't be done. SoftwareSerial relies on pin change interrupts. Only one pin at a time can be generating the interrupt that SoftwareSerial cares about.

Paul, I've been looking at the code and I seriously doubt it uses pin change interrupts. It seems to use internal timers instead. I'm getting confident that with small changes it will work fine for low baud rates.

It seems to use internal timers instead.

To read the next bit, yes. I still think it relies on pin change interrupts to register when the first bit arrives. I could be wrong. I was once before.

There are no external interrupt for all the digital pins, so it is definitely not using external interrupts. I'm feeling confident and I will try to make a non-restrictive version. I'm sure it would be useful for people with low baud rates requirements, that want to read in real time from several devices.

EDIT: You are absolutely right, it uses pin interrupts, but just not by the attachInterrupt method. Still, I think I can use 4 interrupts as long as the baud rate is low. AFAIK, for same priority, interrupts will be executed sequentially.

It's not using external interrupts but pin change interrupts:

ISR(PCINT0_vect)
{
  SoftwareSerial::handle_interrupt();
}

PaulS was right. The code is using timers for sending bits, the receiving side is done by an interrupt handler for the first bit and NOP loop delays for the rest. That means while receiving a byte the processor is completely used by this code. Without changing large parts of the code you will not get this to run for more than one active receiver channel.

I see why you say it is a lot of work... the way the code is structure, the interrupt reads all 8 bits in sequence, so it will definitively miss incoming bits from other ports.

This would have to be re-written with a timer and a state machine for each port, using pin change interrupts just to avoid processing when idle.

Any suggestion on another library that can do something similar to what I need? Right now I'm really stuck with a PCB I've just ordered, so it is hard to change it to user the 4 serial ports of the MEGA...

I'd guess that you won't get that done with an ATmega328 at 16MHz, it's simply not fast enough to keep up with all that timing stuff. I'd take a look at alternatives like the Leaf Maple (http://shop.boxtec.ch/product_info.php/products_id/40431). That something similar to an Arduino Due but already available and quite a bit faster. With the other enhanced possibilities you have a good chance to get a solution that works.