Background thread.

Hi guys, what’s the best way to go about having something like a background thread?

I have a project that uses an RFID reader and this is customer facing …so as soon as this is scanned I need to feedback which is all fine.

The problem is this same project also communicates with a http server every 100 seconds to download some information and this process can take 20-30 seconds maybe longer if the GRPS connection is poor.

So the problem is that if a user scans while the controller is communicating with the http server then they get no response which is undesired; so what’s the best approach to fix this issue?

Hello,

Replace your blocking code by a state machine, so that it is divided into small tasks. Do not use delays, look the Blink Without Delay example.

Here is a basic example of a state machine

More info here: Gammon Forum : Electronics : Microprocessors : State machines

Can't really help without seeing your code.

The demo several things at a time shows how to make .... (I'm sure you can guess)

It is an extended example of the BWoD technique.

...R

Thanks guys, i will give these a read.

I had a read but these methods look like i need to 'pop out' of the GPRS comms to check to see if other things are happening which i don't think would work as you wouldn't want to just out of the GRPS function...maybe what i want cannot be done.

Think about 'blocking' processes - you have said that the http process needs to wait 20-30 seconds to get a response. While you're waiting, do something else like respond to the user input.

Don't use delay(), or at least don't use it a lot.

Don't use functions like readBytesUntil() because they block your processor from doing anything else until the condition is met.

Reverse your thinking. Don't think about breaking out of the GPRS process but think of running a loop() continuously thousands of times per second doing your main task: responding to the RFIDs. Send out the http request you want and then periodically check if anything came in. Add that to a buffer until you detect that you've received the complete message, then process that message.

markmonkey:
which i don't think would work as you wouldn't want to just out of the GRPS function

Why not. As far as I know the GPRS just sends serial data.
The examples in serial input basics don't use blocking code. Serial data arrives very slowly by Arduino standards.

...R

Ok i will give this a go - i will try and hold it in a buffer until complete, thx

markmonkey:
Ok i will give this a go - i will try and hold it in a buffer until complete, thx

If you still have problems post your code.

...R

Robin2:
If you still have problems post your code.

...R

I will do, thx

Robin2:
If you still have problems post your code.

...R

Hi, i have tried but not getting anywhere, i just cant get my head around the constant loops and doing little bits at a time so that the RFID reader stays available.

I will paste my code but cutout the sections not required.

LOOP

void loop () {
 
 byte i = 0;
 byte val = 0;
 byte code[6];
 byte checksumX = 0;
 byte bytesread = 0;
 byte tempbyte = 0;


 if (Serial1.available() > 0) {

   
   Serial.println("Got serial");
   if ((val = Serial1.read()) == 2) {                 // check for header
     Serial.println("Got serial read");
     getID(); // Get the ID, sets readCard = to the read ID

     if ( findID(readCard) ) // If not, see if the card is in the EEPROM
     {

       digitalWrite(relay, HIGH);   // turn the LED on (HIGH is the voltage level)
       digitalWrite(passPin, HIGH);   // turn the LED on (HIGH is the voltage level)
       delay(500);              // wait for a second
       digitalWrite(relay, LOW);    // turn the LED off by making the voltage LOW
       digitalWrite(passPin, LOW);    // turn the LED off by making the voltage LOW
       Serial.println("Open door");
       openDoor(0);
     }
     else
     {
       digitalWrite(failPin, HIGH);   // turn the LED on (HIGH is the voltage level)
       delay(500);              // wait for a second
       digitalWrite(failPin, LOW);    // turn the LED off by making the voltage LOW
       Serial.println("Go away!");
     }


   }

   bytesread = 0;
 }

 if ((unsigned long)(millis() - gsmPreviousMillis) >= gsmInterval) {
   gsmPreviousMillis = millis();
   digitalWrite(failPin, HIGH);
   Serial.println("*** START GPRS ***");
   connectGPRS();
   digitalWrite(failPin, LOW);
 }

}

CODE SECTION THAT CAN TAKE A WHILE AND STOPS THE RFID READER FROM WORKING.

void connectGPRS()
{
  Serial.println("Attach to GPRS network - APN setting");
  while (!LGPRS.attachGPRS("general.t-mobile.uk ", "user", "wap")) { //attachGPRS(const char *apn, const char *username, const char *password);
    delay(500);
  }
  //blinkerGsm();
  // if you get a connection, report back via serial:
  Serial.print("Connect to ");
  Serial.println(server);
  
  
  if (client.connect(server, port))
  {
    Serial.println("connected");
    // Make a HTTP request:
    client.print("GET ");
    client.print(path);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();

    pollServer();
    //blinkerGsm();
    gsmPreviousMillis = millis();
  }
  else
  {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }

}

void pollServer()
{
  // if there are incoming bytes available
  // from the server, read them and print them:
  //const char split[2] = "-";
  bool startRead = false;
  char buf[2048];
  int count = 0;

  while (client.connected())
  {
    if (client.available())
    {
      while (int i = client.read()) {
        if (i != -1) {
          buf[++count] = ((char)i);
        } else {
          buf[++count] = '\0';
          break;
        }
      }

      char* ch = strtok(buf, "\n");
      bool reading = false;
      while (ch != NULL) {
        if (strcmp(ch, "END") == 0) reading = false;
        if (strcmp(ch, "START") == 0) {
          reading = true;
        } else if (reading) {
          bool active = startsWith("A:", ch);
          bool disabled = startsWith("D:", ch);
          String line(ch);
          if (active) {
            int rfidLength = 10;
            String rfid = line.substring(2, sizeof(line));
            Serial.print("Active: ");
            Serial.println(rfid);

            char rfidBuf[sizeof(rfid) + 1];
            rfid.toCharArray(rfidBuf, sizeof(rfid));
            byte val[sizeof(rfid) / 2];
            size_t count = 0;

            for (count = 0; count < sizeof(val); count++) {
              char buf[5] = {'0', 'x', rfidBuf[count * 2], rfidBuf[count * 2 + 1], 0};
              val[count] = byte(strtol(buf, NULL, 0));
            }
            writeID(val);
          }
          if (disabled) {
            int rfidLength = 10;
            String rfid = line.substring(2, sizeof(line));
            Serial.print("Disabled: ");
            Serial.println(rfid);

            char rfidBuf[sizeof(rfid) + 1];
            rfid.toCharArray(rfidBuf, sizeof(rfid));
            byte val[sizeof(rfid) / 2];
            size_t count = 0;

            for (count = 0; count < sizeof(val); count++) {
              char buf[5] = {'0', 'x', rfidBuf[count * 2], rfidBuf[count * 2 + 1], 0};
              val[count] = byte(strtol(buf, NULL, 0));
            }
            deleteID(val);
          }
        }
        ch = strtok(NULL, "\n");
      }
      Serial.println("Disconnecting.");

      client.stop();
    }
  }

  return;

  // if the server's disconnected, stop the client:
  if (!client.available() && !client.connected())
  {
    Serial.println();
    Serial.println("Disconnecting.");
    client.stop();
  }
}

Any help with trying to make this efficient so that the RFID reader has priority would be great.

Mark

  char buf[2048];

Which Arduino are you using?

The only solution I see to your problem is two Arduinos.

Please post the entire code. If it is too long you can add it as an attachment.

...R

Robin2:
Please post the entire code. If it is too long you can add it as an attachment.

...R

No problem.

sketch.txt (27.1 KB)

while (!LGPRS.attachGPRS("general.t-mobile.uk ", "user", "wap"))
{ //attachGPRS(const char *apn, const char *username, const char *password);
    delay(500);
  }

Of course, waiting for an attach will block everything else.

You have to convert this while loop to an "if" so that control passes to the loop if there is no GPRS attach, instead of endlessly repeating. Of course, you can only make that work with a state machine (or have state variables, i.e. flags).

While and for loops are okay inside your real time loop, provided that they have a rapid, guaranteed exit.

The comment inside the loop is pretty weird. It doesn't seem consistent with the use of the attach.

On line 366 you have

while (client.connected())

And that will also block. I presume the connection last longer than 1 or 2 millisecs.
Again, change WHILE to IF

In general you need to use the natural repetition of loop() in place of those WHILE clauses. That is how things are done in several things at a time.

...R

Which Arduino are you using?

  delay(50);              // wait for a second

I find these comments confusing, don't you?

Thanks guys, i will try and got rid of the 'while' and replace with If's