vshymanskyy / TinyGSM

A small Arduino library for GSM modules, that just works
GNU Lesser General Public License v3.0
1.94k stars 718 forks source link

Adventure to fix incorrect APN PDP #429

Open Mr-HaleYa opened 4 years ago

Mr-HaleYa commented 4 years ago

NOT AN ISSUE!!! This is to Solve an issue while allowing feedback from the devs (as well as others)

@SRGDamia1 So since I have discovered that the incorrect APN in the PDP can cause extreme instability I have been building a method of correctly setting the PDP when the APN is assigned.

Since you don't know what PDPs have been set previously you have to have it dynamically identify them so you aren't setting new ones that are not necessary. to do this I have it run the AT+CGDCONT? command with SerialAT.println("AT+CGDCONT?");

After doing so I read the response and store it in a String for processing. a typical response looks like this

AT+CGDCONT?
+CGDCONT: 1,"IP","hologram","0.0.0.0",0,0,0,0
+CGDCONT: 13,"IP","hologram","0.0.0.0",0,0,0,0
+CGDCONT: 14,"IP","hologram","0.0.0.0",0,0,0,0
OK

the PDP number(s) can vary from 1-24 as do the number of lines. This is saved as a String which is then cut at the newline (\n) and stored pieces in an array. After that, I have the array read and stop once it hits a "," which is right after the number. Then it identifies the section that contains ": " which is right before the number and gets the index position of the ": " and uses that to take a substring of what is left which is just the number. So for the example that I have, it would put the first row into the array looking like this (technically the second row because AT+CGDCONT? is the first row but we can ignore that)

+CGDCONT: 1,"IP","hologram","0.0.0.0",0,0,0,0

It would be read one char at a time until the first "," is identified like this

+
+C
+CG
+CGD
+CGDC
+CGDCO
+CGDCON
+CGDCONT
+CGDCONT:
+CGDCONT: 
+CGDCONT: 1

then the position of ": " would be identified and for this example, it would be 9. So everything after the 9th position inside of the array would be the output which is 1.

This is working flawlessly and I have even sent in some garbled text before the +CGDCONT: because sometimes that's what the modem replies if it didn't have time to fully process the command and it has always fed me the numbers out correctly. I then put them in an array PDP[] for storage.

At the very end, I try and read the contents of the PDP array with

    for ( int z = 0; z < 24; z++) {
      Serial.print(z);
      Serial.print(" - ");
      Serial.println(PDP[z]);
    }

and I am getting the following

0 - 1
1 - 13
2 - 14
3 - 0
4 - 0
5 - 0
6 - 0
7 - 0
8 - 0
9 - 0
10 - 0
11 - 0
12 - 0
13 - 0
14 - 0
15 - 0
16 - 0
17 - 0
18 - 0
19 - 0
20 - 0
21 - 0
22 - 0
23 - 0

which is exactly what I need!

My next steps are to have these numbers fed into a function that issues the command to change the PDP to the current APN. This should not take to much time.


My current code as of writing this is

(defined at top of sketch)

int PDP[24], counter, lastIndex, numberOfPieces = 24;
String pieces[24], input, data;

Actual code

  SerialAT.println("AT+CGDCONT?");
  delay(500);
  if (SerialAT.available()) {
    input = SerialAT.readString();
    for (int i = 0; i < input.length(); i++) {
      if (input.substring(i, i + 1) == "\n") {
        pieces[counter] = input.substring(lastIndex, i);
        lastIndex = i + 1;
        counter++;
      }
      if (i == input.length() - 1) {
        pieces[counter] = input.substring(lastIndex, i);
      }
    }
    // Reset for reuse
    input = "";
    counter = 0;
    lastIndex = 0;

    for ( int y = 0; y < numberOfPieces; y++) {
      for ( int x = 0; x < pieces[y].length(); x++) {
        char c = pieces[y][x];  //gets one byte from buffer
        if (c == ',') {
          if (input.indexOf(": ") >= 0) {
            data = input.substring((input.indexOf(": ") + 1));
            PDP[counter] = data.toInt();
            counter++;
            input = "";
            data = "";
            break;
          }
          // Reset for reuse
          input = "";
          data = "";
        }
        else {
          input += c;
        }
      }
    }
  } else {
    Serial.println("Failed to get PDP!");
  }
Mr-HaleYa commented 4 years ago

a simple for loop did the trick

  for ( int z = 0; z < 24; z++) {
    if ( PDP[z] > 0 && PDP[z] < 25) {  // only digits from 1-24 are acceptable 
      String test = "AT+CGDCONT=" + String(PDP[z]) + ",\"IP\",\"" + String(apn) + "\",\"0.0.0.0\",0,0,0,0";
      Serial.println(test);
      modem.sendAT("+CGDCONT=" + String(PDP[z]) + ",\"IP\",\"" + String(apn) + "\",\"0.0.0.0\",0,0,0,0");
      modem.waitResponse();
    }
  }

Running the whole sketch (first changing the apn to wireless.twilio.com) I get this output

+CGDCONT: 1,"IP","hologram","0.0.0.0",0,0,0,0
+CGDCONT: 13,"IP","hologram","0.0.0.0",0,0,0,0
+CGDCONT: 14,"IP","hologram","0.0.0.0",0,0,0,0

OK

^^^check the CGDCONT after boot

my code runs then I check CGDCONT again 

+CGDCONT: 1,"IP","wireless.twilio.com","0.0.0.0",0,0,0,0
+CGDCONT: 13,"IP","wireless.twilio.com","0.0.0.0",0,0,0,0
+CGDCONT: 14,"IP","wireless.twilio.com","0.0.0.0",0,0,0,0

OK

It functions EXACTLY how it is supposed to and allows the PDP to be changed quickly so SIMs can be swapped easily!

Mr-HaleYa commented 4 years ago

I have done a little more work to condense the code and remove some un-needed variables.

int counter, lastIndex, numberOfPieces = 24;
String pieces[24], input;

(^defined at the top of the sketch^)

  SerialAT.println("AT+CGDCONT?");
  delay(500);
  if (SerialAT.available()) {
    input = SerialAT.readString();
    Serial.println(input);
    for (int i = 0; i < input.length(); i++) {
      if (input.substring(i, i + 1) == "\n") {
        pieces[counter] = input.substring(lastIndex, i);
        lastIndex = i + 1;
        counter++;
      }
      if (i == input.length() - 1) {
        pieces[counter] = input.substring(lastIndex, i);
      }
    }
    // Reset for reuse
    input = "";
    counter = 0;
    lastIndex = 0;

    for ( int y = 0; y < numberOfPieces; y++) {
      for ( int x = 0; x < pieces[y].length(); x++) {
        char c = pieces[y][x];  //gets one byte from buffer
        if (c == ',') {
          if (input.indexOf(": ") >= 0) {
            String data = input.substring((input.indexOf(": ") + 1));
            if ( data.toInt() > 0 && data.toInt() < 25) {
              modem.sendAT("+CGDCONT=" + String(data.toInt()) + ",\"IP\",\"" + String(apn) + "\",\"0.0.0.0\",0,0,0,0");
            }
            input = "";
            break;
          }
          // Reset for reuse
          input = "";
        }
        else {
          input += c;
        }
      }
    }
  } else {
    Serial.println("Failed to get PDP!");
  }
SRGDamia1 commented 4 years ago

Hm. Is this something that should be implemented in the library? I've never had a use for multiple PDP contexts, but I assume the chip supports up to 24 of them because others do.

What happens if you send the chip an empty PDP definition? (``AT+CGDCONT=#with none of the other parameters - they're all labeled as optional) Does that clear or un-define the context? What do you get withAT+CGDCONT=?``` (the test command)? Does that reply with 0-24 for the ranger or does it reply with only the ones you're seeing (ie, 1, 13-14)? Do you have to re-define all of the contexts every time or does it hold up through multiple resets?

Mr-HaleYa commented 4 years ago

This should definitely be added to the library, all of my testing has concluded that the script that I have made solves all of the issues I've been having on my 10 devices. not a single one would connect to the network and then after fixing PDP values every single one of them works correctly.

Once PDP is correctly set it will hold up through the device resets.

The problem was that once they are set the library does not change them so that's what this does, is alter them.

I'm currently out of state but once I returned home I can do some more testing

tradexsrl commented 3 years ago

i can confirm the same problem but also with the same sim of the same provider...sometimes it doesn't reigster anymore on the 2G network but i solved on setup() with this: for ( int z = 0; z < 25; z++) { modem.sendAT("+CGDCONT=" + String(z)); delay(200); }

so everytime it start i wipe all pdp context and it works