0

I have an Arduino and an APC220 wireless transceiver. I'm writing a library that reads in data from the APC using the SoftwareSerial class. I originally started with the (incorrect) code below that was causing a seg fault because the i variable is incremented even when there is no data available to read. In cases where it happened to work (by chance when the data was immediately available), this function took approximately 6 milliseconds to execute. When I put the i++; statement in its proper place (above the closing brace immediately above it), the function takes over 270 ms to run. Speed is crucial for this function, so I'm wondering what it is about that statement's placement that causes such a dramatic increase in time.

For the code below, buff is declared as char buff[10]; and sSerial is an instance of SoftwareSerial

unsigned long updateLocation(Marker* marker) {
    this->sSerial->print('~');
    //initiate request from vision system
    this->sSerial->flush();
    this->sSerial->print('#');
    this->sSerial->print(marker->num);
    this->sSerial->print('*');
    this->sSerial->flush();
    unsigned long start = millis();
    int state = 0, i = 0;
    while((millis() - start) < 600) {
        if(this->sSerial->available()) {
            buff[i] = this->sSerial->read();
            if(buff[i] == ',') {
                buff[i] = 0;
                switch(state) {
                    case 0:
                        i = -1;
                        state++;
                        break;
                    case 1:
                        marker->x = atof(buff);
                        i = -1;
                        state++;
                        break;
                    case 2:
                        marker->y = atof(buff);
                        i = -1;
                        state++;
                        break;
                    case 3:
                        marker->theta = atof(buff);
                        i = -1;
                        return (millis() - start);
                        break;
                    default:
                        return 0;
                        break;
                }
            }
            // Correct location for i++; takes 270 ms to execute
        }
        // Incorrect location for i++; Takes 6 ms to execute
        i++;
    }
    this->sSerial->print('~');
    this->sSerial->flush();
    return 0;
}
Elan Hamburger
  • 2,137
  • 10
  • 14
  • Please could you add some comments `//` in your code where `i++;` is working OK and NOK and add details about time duration. – J. Piquard Nov 19 '16 at 17:18

1 Answers1

0

Assuming that there's data ready and waiting from sSerial, there's no effective difference in the placement of i++.

You said yourself, in most cases the data isn't ready. With the incorrect placement of i++, i quickly grows to greater than the size of buff which causes the segfault.

With the correct placement, your code blocks for up to 600ms waiting for enough data to come in to reach case 3 and return. On average, you're seeing that it takes 270ms for that to happen.

You can test this theory yourself by timing the same function operating directly on a string rather than reading in from serial.

You may want to a) increase your baud rate b) check to see if there's a more efficient software serial implementation you can use c) switch to hardware serial. If you are only using hardware serial currently for debugging output, you can switch that around. Use an FTDI adapter ($6-10 on eBay) to pipe software serial to USB and reserve the hardware serial for your time sensitive function.

You might also be able to reconfigure your code so it doesn't block the whole time waiting. You can read in what's available, store it in a global and go back to your main loop to do something else until there's data available again.

edit: I see now that the APC220 is 9600 baud max. That's pretty slow, so the bottle neck may not be software serial (but you should test it). If the bottle neck is simply the baud rate, you will need to look at optimizing your code not to block waiting for input if there are other things your system can work on while it's waiting.

imjosh
  • 4,734
  • 1
  • 19
  • 22
  • The function was purposely designed to be blocking because the main code needs the information it receives in order to continue. When the incorrect placement of `i++` was used, in the cases where it didn't seg fault it took 6 ms to execute, which would seem to indicate that the function CAN operate that quickly but for some reason doesn't when `i++` is moved to the correct spot. The only thing I can think of is compiler optimization of a constant increment in the `while`. – Elan Hamburger Nov 22 '16 at 18:36
  • again, I think it will always operate that quickly if it doesn't have to wait on data coming over. I've suggested a way for you to test my theory - eliminate the serial reads and simply pass the function a string that looks like the data you are expecting. – imjosh Nov 22 '16 at 20:16