Pages: [1]   Go Down
Author Topic: Elegant method for calling multiple softSerial ports?  (Read 484 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 44
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello -

I have a project that will be working with multiple software serial connections (2 at the moment, but will potentially be expanding up to 4 or 5), all of which feed in data in the exact same format.  I have the communication link working with a single serial port and am able to extract all the data I need, but I was wondering if anyone knows of a more elegant way to repeat the process on the remaining ports other than copy/pasting all of my code and replacing all the "serial1" calls with "serial2". 

My thought would be to put everything into a for loop or a separate function that I call repeatedly with a reference to the next port I want to work with, but I don't know if there is any way of making the serial call into some sort of variable that can be updated dynamically, or if I just have to suck it up and hard code each one, which is going to cost me quite a bit of memory.

Can someone please let me know if this is an impossible dream or if you have any ideas on how I might implement it?

-Scott
Logged

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Put a wrapper around it:

Code:
void mySerialfunc(unsigned char * str, unsigned char serialN) {
  switch (serialN) {
    case 0: Serialfunc0(str); break;
    case 1: Serialfunc1(str); break;
    ...
   }
}

Define once, use many times.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 613
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
all of which feed in data in the exact same format.
But ONLY the one that you are listening to. Data on the other serial ports hits the bit bucket when you are not listening.
Logged

Atlanta
Offline Offline
Full Member
***
Karma: 4
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

or search ebay for 190779019188
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 44
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for all the replies so far.

I'm not having any issues with the physical connections.  The inputs are true RS-232 which I'm running through MAX232 chips to convert down to TTL signals.  I have plenty of pins, so multiplexing is not needed.  The units only respond on the 232 line when I query them, and my code is designed to activate one serial port, do it's business, then move on to the next one, so I'm not worried about data loss when I'm not actively listening to a given port.

What I am looking for is a way to condense my code to carry out the same operation on multiple ports while minimizing the amount of memory it takes up, since the communication back and forth is fairly complex (I did not design the protocol, nor do I have control over it).

dhenry - I think you're on the right track, but I'm not exactly sure how I would apply that to my code.  Do you think you could show me how you would implement it on this sub-set of my code?

Code:
      serial1.println("Q600 700");  //send data request on serial1
      loopCount = 0;
      rx_count = 0;
      while (!serial1.available() || rx_count != serial1.available()) {  //loop, waiting for complete response - responses are always small enough to fit in the buffer, don't have to worry about overflow
        rx_count = serial1.available();
        loopCount++;
        delay(1);
        if (loopCount > 100) {  //if no response within so many loops, assume machine is off
          break;
          //other code
        }
      }
      if (serial1.available()) {  //if there is data in buffer, proceed to read
        serial1.parseFloat();  // ignore the first number
        m1_cycles[0] = serial1.parseFloat();  //read in new value
        while(serial1.available()) { //flush buffer
          serial1.read();
          }
        }
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I was wondering if anyone knows of a more elegant way to repeat the process on the remaining ports other than copy/pasting all of my code and replacing all the "serial1" calls with "serial2".  

Implement a function which takes a pointer to a SoftwareSerial object as a parameter. If processing of that data stream requires you to know which instance you're dealing with then pass that in as another parameter. Call that function with each SoftwareSerial you want to process. If they're identical you might consider storing them in an array, using a FOR loop to work through the array, and use the array index to identify the instances.

I'm not sure you have noticed an important point PaulS made: only one instance of SoftwareSerial can receive data at a time. No problem if you're polling each connection individually and can control which one transmits at a given time, but if they're sending data spontaneously then I suspect you'll find this simply doesn't work; you'll only receive data from the instance you're currently listening to and data from all others will be silently discarded.

ETA: from your later reply I see that you did notice PaulS's comment and this shouldn't be a problem in your case. In this case, rather than using a FOR loop to process all the SoftwareSerials in one go, you probably want a simple state machine which can keep track of which instance is currently being polled, and call the handler function for that instance.
« Last Edit: January 08, 2013, 09:53:21 am by PeterH » Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 44
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Peter -

Pointers have always been a bit of a sticking point for me.  Could you possibly show me what the basic structure of the code your proposing would look like?

-Scott
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not sure about some of the details of what you're trying to do, but I get that you have a set of pins that are being driven by SoftwareSerial, and you want to poll them one by one and get a result back.

To me that suggests a solution that keeps the SoftwareSerial objects in an array, and has some sort of state machine with timers to decide when to take action on a given serial port. The code to access the serial ports could look like this:

Code:
// incomplete, uncompiled, untested
const int SERIAL_COUNT = 5;
int serialRxPins[SERIAL_COUNT] = { 2, 3, 4, 5, 6};
int serialTxPins[SERIAL_COUNT] = { 7, 8, 9, 10, 11};
SoftwareSerial*serial[SERIAL_COUNT];

void setup()
{
    ...
    for(int i = 0; i < SERIAL_COUNT; i++)
    {
        serial[i] = new SoftwareSerial(serialRxPins[i], serialTxPins[i]);
        serial[i]->begin(9600);
    }
    ...
}

void loop()
{
    // assume some sort of state machine and timer handling to decide when to take action on a given serial port
    ...
    doSomethingToSerialPort(serial[currentSerialPort]);
    ...
}

void doSomethingToSerialPort(SoftwareSerial *serialPort)
{
    if(serialPort->available())
    {
        ...
    }
}
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 44
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Peter -

Thanks, that looks pretty much exactly like what I had envisioned, except I think I was missing the pointer part because I try to avoid them like the plague due to my lack of knowledge on them.  I suppose I should really sit down and try to wrap my head around what exactly they do.

Is the "->" in the serial calls part of the pointers?  I'm unfamiliar with that notation.

-Scott
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 613
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I suppose I should really sit down and try to wrap my head around what exactly they do.
Yes, you should.

Quote
Is the "->" in the serial calls part of the pointers?  I'm unfamiliar with that notation.
It's how you dereference a pointer. It is similar to the . in Serial.begin(), for instance, when the part on the left is a pointer to an instance, rather than an instance.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 44
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello again,

I did some research into pointers but apparently my understanding is still not quite there as I ran into an issue while trying to rewrite my code in the format Peter suggested, so I'm hoping that one of you might be able to help me out.

I want to call a function within doSomethingToSerialPort, doSomethingRepeatedlyToSerialPort, that needs to get serialPort passed into it, but I can't quite figure out how to do so successfully.  Can someone help me out?

Code:
const int SERIAL_COUNT = 5;
int serialRxPins[SERIAL_COUNT] = { 2, 3, 4, 5, 6};
int serialTxPins[SERIAL_COUNT] = { 7, 8, 9, 10, 11};
SoftwareSerial*serial[SERIAL_COUNT];

void setup() {
  for(int i = 0; i < SERIAL_COUNT; i++) {
    serial[i] = new SoftwareSerial(serialRxPins[i], serialTxPins[i]);
    serial[i]->begin(9600);
  }
}

void loop() {
  doSomethingToSerialPort(serial[currentSerialPort]);
}

void doSomethingToSerialPort(SoftwareSerial *serialPort) {
  while(true) {
    doSomethingRepeatedlyToSerialPort(__something_goes_here__);
  }
}

void doSomethingRepeatedlyToSerialPort(__something_goes_here__) {
  serialPort->read();
}

-Scott
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 98
Posts: 4807
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

And hopefully whatever Arduino you're using has enough RAM for buffers for 4 soft serial (plus the regular serial?) objects?
Hey, run fast enough and 16 byte buffers might do it but I dunno how much control you have there.



Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 613
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    doSomethingRepeatedlyToSerialPort(__something_goes_here__);
serialPort goes there.

Code:
void doSomethingRepeatedlyToSerialPort(__something_goes_here__) {
Just like the other function - SoftwareSerial *serialPort goes there.
Logged

Pages: [1]   Go Up
Jump to: