PaulStoffregen / AltSoftSerial

Software emulated serial using hardware timers for improved compatibility
http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
338 stars 132 forks source link

Issues with .available() #34

Open RileyStarlight opened 7 years ago

RileyStarlight commented 7 years ago

I have been having problems with .available(), returning zero when there really was data in the input buffer. It seems that you need to leave a small amount of time between queries to return a correct value. Even though is not always like that.

PaulStoffregen commented 7 years ago

Perhaps the stop bit time matters?

If there really is a problem, I'm afraid I can't do anything (and must close this issue) unless you provide a (hopefully small) complete program that demonstrates the problem, and all other details needed to reproduce the problem. Realistically, the test program needs to be used with other hardware, which must be something like another Arduino or Teensy board also running a complete program, or some other hardware that's readily available for testing.

RileyStarlight commented 7 years ago

Thank you for answering so quickly The system that I am implementing uses an AT modem with which I communicate to send or receive data. This problem I have detected (and bypassed) in two points of my code. The first is in the initialization of the modem, where I send AT and I expect to receive an AT echo followed with OK in a window of time.

bool modemBegin() {
    bool ret = false;
    char atbuff[16] = "";
    unsigned long tout = 0;

    sigfox.begin(9600);
    if (checkDebug(DEBUG_SERIAL | VERBOSE_DEBUG)) Serial.println(F(";Warming up modem..."));
    delay(SIGFOX_WARM_TIME);
    if (checkDebug(DEBUG_SERIAL | DEBUG_SERIAL_ATECHO)) Serial.println("\r\n;>> AT");
    Serial.flush();
    sigfox.println("AT");
    tout = millis();
    while (((tout - millis()) < AT_TIMEOUT) && (!sigfox.available()));
    delay(10); // FIXME should not be necessary but it doesn't work without it
    if (sigfox.available()) ret = modemExtractString(atbuff);
    else ret = false;
    return ret;
}

If I ask twice in a row, it leaves the loop correctly, since data has been received but it becomes false. Just as instead of asking true or false make a numerical comparison, the result is the same and its solution too.

In the second case, within the finite state machine where the incoming data is processed, the available data questions in each case cause it to return false, causing the function to re-enter when it exits, since there are data available. Similarly in the previous case, it does not matter whether the comparison is boolean or numeric.

bool modemExtractString(char str[]) {
    bool ret = false;
    char c = 0;
    unsigned char subs = 0;
    unsigned int index = 0;
    unsigned long tout = 0;
    receiveFSM_t s = FSM_NONE;

    tout = millis();
    do {
        switch (s) {
          case FSM_NONE:
            s = FSM_ECHO_DETECT_1;
            break;
          case FSM_ECHO_DETECT_1:
            if (sigfox.available()) {
                c = sigfox.read();
                //Serial.print("D1 ");
                //Serial.println(c);
                if (c == 'A') s = FSM_ECHO_DETECT_2;
            }
            break;
          case FSM_ECHO_DETECT_2:
            if (sigfox.available()) {
                c = sigfox.read();
                //Serial.print("D2 ");
                //Serial.println(c);
                if (c == 'T') s = FSM_ECHO_SKIP_1;
                else s = FSM_NONE;
            }
            break;
          case FSM_ECHO_SKIP_1:
            if (sigfox.available()) {
                c = sigfox.read();
                //Serial.print("E1 ");
                //Serial.println(c);
                if (c == '\r') s = FSM_ECHO_SKIP_2;
            }
            break;
            // [...]
          case FSM_SAVE_UNTIL_EOP:
            if (sigfox.available()) {
                c = sigfox.read();
                //Serial.print("S  ");
                //Serial.println(c);
                str[index++] = c;
                //[...]
            }
            break;
        }
    } while ((s != FSM_OK) && ((millis() - tout) < AT_TIMEOUT));
    if (s == FSM_OK) {
        s = FSM_NONE;
        ret = true;
    }
    return ret;
}

In this case I can not enter a delay, since it causes overflow of the input buffer (up to 320 characters can be processed). The solution has been to not enter the function until there are the minimum of characters to process, 8 in my case.

if (sigfox.available() > 8) modemExtractString(rxstr); 

I hope this helps to locate the problem, anything else you need, you tell me.

PaulStoffregen commented 7 years ago

I'm currently working on another project. Actually, a very long list of other projects.

With only code fragments, I can't dedicate the time to fill in the rest to make this into a complete program, and then try to find a modem which will reproduce the problem.

If you want me to actually investigate, to actually put engineering time into this, you must post a complete program I can copy and paste into Arduino and upload to a board. If any part is missing, if it doesn't compile, I will stop there and do nothing more, so please take a moment to actually copy the program you post back into Arduino and verify it truly does reproduce the problem.

Then I'm going to need to know where to buy this modem. Ideally, you could write a 2nd program to run on another Arduino which does the simplest possible modem responses to reproduce the problem. I have plenty of Arduino boards. But if this modem is readily available, I could buy one. I do have a modest budget for such thing.

But the thing I do not have is time for guesswork. An incomplete program or lack of specific details means I will not look into this problem. I simply have far too many other urgent projects to do.