Browse Source

Really got location working

Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
v_master
Sara Damiano 5 years ago
parent
commit
43391944df
9 changed files with 381 additions and 381 deletions
  1. +15
    -4
      examples/AllFunctions/AllFunctions.ino
  2. +2
    -0
      examples/HttpsClient/HttpsClient.ino
  3. +76
    -77
      src/TinyGsmClientSIM7000.h
  4. +52
    -52
      src/TinyGsmClientSIM7600.h
  5. +67
    -75
      src/TinyGsmClientSIM808.h
  6. +53
    -67
      src/TinyGsmClientSaraR4.h
  7. +53
    -67
      src/TinyGsmClientUBLOX.h
  8. +33
    -37
      src/TinyGsmGSMLocation.tpp
  9. +30
    -2
      src/TinyGsmModem.tpp

+ 15
- 4
examples/AllFunctions/AllFunctions.ino View File

@ -318,6 +318,7 @@ void loop() {
#endif #endif
#if TINY_GSM_TEST_GSM_LOCATION && defined TINY_GSM_MODEM_HAS_GSM_LOCATION #if TINY_GSM_TEST_GSM_LOCATION && defined TINY_GSM_MODEM_HAS_GSM_LOCATION
DBG("Waiting for GSM location");
String location = modem.getGsmLocation(); String location = modem.getGsmLocation();
DBG("GSM Based Location String:", location); DBG("GSM Based Location String:", location);
float lat = 0; float lat = 0;
@ -328,7 +329,9 @@ void loop() {
int day = 0; int day = 0;
int hour = 0; int hour = 0;
int min = 0; int min = 0;
int sec = 0;
int sec = 0;
for (int8_t i = 5; i; i--) {
DBG("Waiting for GSM location");
if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour, if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
&min, &sec)) { &min, &sec)) {
DBG("Latitude:", String(lat, 8)); DBG("Latitude:", String(lat, 8));
@ -341,12 +344,15 @@ void loop() {
DBG("Minute:", min); DBG("Minute:", min);
DBG("Second:", sec); DBG("Second:", sec);
} else { } else {
DBG("Couldn't get GSM location");
DBG("Couldn't get GSM location, retrying in 10s.");
delay(10000L);
}
} }
#endif #endif
#if TINY_GSM_TEST_GPS && defined TINY_GSM_MODEM_HAS_GPS #if TINY_GSM_TEST_GPS && defined TINY_GSM_MODEM_HAS_GPS
modem.enableGPS(); modem.enableGPS();
DBG("Waiting for GPS/GNSS/GLONASS location");
String gps_raw = modem.getGPSraw(); String gps_raw = modem.getGPSraw();
DBG("GPS/GNSS Based Location String:", gps_raw); DBG("GPS/GNSS Based Location String:", gps_raw);
float lat2 = 0; float lat2 = 0;
@ -362,7 +368,9 @@ void loop() {
int hour2 = 0; int hour2 = 0;
int min2 = 0; int min2 = 0;
int sec2 = 0; int sec2 = 0;
if (modem.getGPS(&lat2, &lon, &speed2, &alt2, &vsat2, &usat2, &accuracy2,
for (int8_t i = 5; i; i--) {
DBG("Waiting for GPS/GNSS/GLONASS location");
if (modem.getGPS(&lat2, &lon2, &speed2, &alt2, &vsat2, &usat2, &accuracy2,
&year2, &month2, &day2, &hour2, &min2, &sec2)) { &year2, &month2, &day2, &hour2, &min2, &sec2)) {
DBG("Latitude:", String(lat2, 8)); DBG("Latitude:", String(lat2, 8));
DBG("Longitude:", String(lon2, 8)); DBG("Longitude:", String(lon2, 8));
@ -377,8 +385,11 @@ void loop() {
DBG("Hour:", hour2); DBG("Hour:", hour2);
DBG("Minute:", min2); DBG("Minute:", min2);
DBG("Second:", sec2); DBG("Second:", sec2);
break;
} else { } else {
DBG("Couldn't get GPS/GNSS location");
DBG("Couldn't get GSM location, retrying in 10s.");
delay(10000L);
}
} }
modem.disableGPS(); modem.disableGPS();
#endif #endif


+ 2
- 0
examples/HttpsClient/HttpsClient.ino View File

@ -46,7 +46,9 @@
// Chips without internal buffering (A6/A7, ESP8266, M590) // Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response // need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail). // else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 650 #define TINY_GSM_RX_BUFFER 650
#endif
// See all AT commands, if wanted // See all AT commands, if wanted
// #define DUMP_AT_COMMANDS // #define DUMP_AT_COMMANDS


+ 76
- 77
src/TinyGsmClientSIM7000.h View File

@ -194,7 +194,6 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
res2.trim(); res2.trim();
name = res2; name = res2;
DBG("### Modem:", name);
return name; return name;
} }
@ -375,7 +374,15 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
* SIM card functions * SIM card functions
*/ */
protected: protected:
// Able to follow all SIM card functions as inherited from the template
// Doesn't return the "+CCID" before the number
String getSimCCIDImpl() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
/* /*
* Messaging functions * Messaging functions
@ -403,7 +410,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
// get the RAW GPS output // get the RAW GPS output
String getGPSrawImpl() { String getGPSrawImpl() {
sendAT(GF("+CGNSINF")); sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
String res = stream.readStringUntil('\n'); String res = stream.readStringUntil('\n');
waitResponse(); waitResponse();
res.trim(); res.trim();
@ -415,84 +422,76 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
int* vsat = 0, int* usat = 0, float* accuracy = 0, int* vsat = 0, int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0, int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) { int* minute = 0, int* second = 0) {
bool fix = false;
sendAT(GF("+CGNSINF")); sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
streamSkipUntil(','); // GNSS run status
if (streamGetInt(',') == 1) fix = true; // fix status
// UTC date & Time
char dtSBuff[7] = {'\0'};
stream.readBytes(dtSBuff, 4); // Four digit year
dtSBuff[4] = '\0'; // null terminate buffer
if (year != NULL) *year = atoi(dtSBuff); // Convert to int
stream.readBytes(dtSBuff, 2); // Two digit month
dtSBuff[2] = '\0';
if (month != NULL) *month = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit day
dtSBuff[2] = '\0';
if (day != NULL) *day = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit hour
dtSBuff[2] = '\0';
if (hour != NULL) *hour = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit minute
dtSBuff[2] = '\0';
if (minute != NULL) *minute = atoi(dtSBuff);
stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds
dtSBuff[6] = '\0';
if (second != NULL) *second = atoi(dtSBuff);
// *secondWithSS = atof(dtSBuff);
streamSkipUntil(','); // Throw away the final comma
*lat = streamGetFloat(','); // Latitude
*lon = streamGetFloat(','); // Longitude
if (alt != NULL) { // MSL Altitude. Unit is meters
*alt = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (speed != NULL) { // Speed Over Ground. Unit is knots.
*speed = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // Fix Mode
streamSkipUntil(','); // Reserved1
streamSkipUntil(','); // Horizontal Dilution Of Precision
if (accuracy != NULL) { // Position Dilution Of Precision
*accuracy = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil(','); // Reserved2
if (vsat != NULL) { // GNSS Satellites in View
*vsat = streamGetInt(',');
} else {
streamSkipUntil(',');
}
if (usat != NULL) { // GNSS Satellites Used
*usat = streamGetInt(',');
} else {
streamSkipUntil(',');
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
streamSkipUntil(','); // GNSS run status
if (streamGetInt(',') == 1) { // fix status
// init variables
float ilat = 0;
float ilon = 0;
float ispeed = 0;
int ialt = 0;
int ivsat = 0;
int iusat = 0;
float iaccuracy = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
float secondWithSS = 0;
// UTC date & Time
iyear = streamGetInt(static_cast<int8_t>(4)); // Four digit year
imonth = streamGetInt(static_cast<int8_t>(2)); // Two digit month
iday = streamGetInt(static_cast<int8_t>(2)); // Two digit day
ihour = streamGetInt(static_cast<int8_t>(2)); // Two digit hour
imin = streamGetInt(static_cast<int8_t>(2)); // Two digit minute
secondWithSS = streamGetFloat(','); // 6 digit second with subseconds
ilat = streamGetFloat(','); // Latitude
ilon = streamGetFloat(','); // Longitude
ialt = streamGetFloat(','); // MSL Altitude. Unit is meters
ispeed = streamGetFloat(','); // Speed Over Ground. Unit is knots.
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // Fix Mode
streamSkipUntil(','); // Reserved1
streamSkipUntil(','); // Horizontal Dilution Of Precision
iaccuracy = streamGetFloat(','); // Position Dilution Of Precision
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil(','); // Reserved2
ivsat = streamGetInt(','); // GNSS Satellites in View
iusat = streamGetInt(','); // GNSS Satellites Used
streamSkipUntil(','); // GLONASS Satellites Used
streamSkipUntil(','); // Reserved3
streamSkipUntil(','); // C/N0 max
streamSkipUntil(','); // HPA
streamSkipUntil('\n'); // VPA
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (speed != NULL) *speed = ispeed;
if (alt != NULL) *alt = ialt;
if (vsat != NULL) *vsat = ivsat;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = static_cast<int>(secondWithSS);
waitResponse();
return true;
} }
streamSkipUntil(','); // GLONASS Satellites Used
streamSkipUntil(','); // Reserved3
streamSkipUntil(','); // C/N0 max
streamSkipUntil(','); // HPA
streamSkipUntil('\n'); // VPA
streamSkipUntil('\n'); // toss the row of commas
waitResponse(); waitResponse();
return fix;
return false;
} }
/* /*


+ 52
- 52
src/TinyGsmClientSIM7600.h View File

@ -314,10 +314,10 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// = 10 (default) // = 10 (default)
// DelayTm = number of milliseconds to delay before outputting received data // DelayTm = number of milliseconds to delay before outputting received data
// = 0 (default) // = 0 (default)
// Ack = sets whether reporting a string Send ok = 0 (don't report)
// Ack = sets whether reporting a string "Send ok" = 0 (don't report)
// errMode = mode of reporting error result code = 0 (numberic values) // errMode = mode of reporting error result code = 0 (numberic values)
// HeaderType = which data header of receiving data in multi-client mode // HeaderType = which data header of receiving data in multi-client mode
// = 1 (+RECEIVE,<link num>,<data length>)
// = 1 (+RECEIVE,<link num>,<data length>)
// AsyncMode = sets mode of executing commands // AsyncMode = sets mode of executing commands
// = 0 (synchronous command executing) // = 0 (synchronous command executing)
// TimeoutVal = minimum retransmission timeout in milliseconds = 75000 // TimeoutVal = minimum retransmission timeout in milliseconds = 75000
@ -439,69 +439,69 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
uint8_t fixMode = streamGetInt(','); // mode 2=2D Fix or 3=3DFix uint8_t fixMode = streamGetInt(','); // mode 2=2D Fix or 3=3DFix
// TODO(?) Can 1 be returned // TODO(?) Can 1 be returned
if (fixMode == 1 || fixMode == 2 || fixMode == 3) { if (fixMode == 1 || fixMode == 2 || fixMode == 3) {
// init variables
float ilat = 0;
float ilon = 0;
float ispeed = 0;
int ialt = 0;
int ivsat = 0;
int iusat = 0;
float iaccuracy = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
float secondWithSS = 0;
streamSkipUntil(','); // GPS satellite valid numbers streamSkipUntil(','); // GPS satellite valid numbers
streamSkipUntil(','); // GLONASS satellite valid numbers streamSkipUntil(','); // GLONASS satellite valid numbers
streamSkipUntil(','); // BEIDOU satellite valid numbers streamSkipUntil(','); // BEIDOU satellite valid numbers
*lat = streamGetFloat(','); // Latitude
ilat = streamGetFloat(','); // Latitude
streamSkipUntil(','); // N/S Indicator, N=north or S=south streamSkipUntil(','); // N/S Indicator, N=north or S=south
*lon = streamGetFloat(','); // Longitude
ilon = streamGetFloat(','); // Longitude
streamSkipUntil(','); // E/W Indicator, E=east or W=west streamSkipUntil(','); // E/W Indicator, E=east or W=west
// Date. Output format is ddmmyy // Date. Output format is ddmmyy
char dtSBuff[7] = {'\0'};
stream.readBytes(dtSBuff, 2); // Two digit day
dtSBuff[2] = '\0'; // null terminate buffer
if (day != NULL) *day = atoi(dtSBuff); // Convert to int
stream.readBytes(dtSBuff, 2); // Two digit month
dtSBuff[2] = '\0';
if (month != NULL) *month = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit year
dtSBuff[2] = '\0';
if (year != NULL) *year = atoi(dtSBuff);
streamSkipUntil(','); // Throw away the final comma
iday = streamGetInt(static_cast<int8_t>(2)); // Two digit day
imonth = streamGetInt(static_cast<int8_t>(2)); // Two digit month
iyear = streamGetInt(','); // Two digit year
// UTC Time. Output format is hhmmss.s // UTC Time. Output format is hhmmss.s
stream.readBytes(dtSBuff, 2); // Two digit hour
dtSBuff[2] = '\0';
if (hour != NULL) *hour = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit minute
dtSBuff[2] = '\0';
if (minute != NULL) *minute = atoi(dtSBuff);
stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds
dtSBuff[6] = '\0';
if (second != NULL) *second = atoi(dtSBuff);
// *secondWithSS = atof(dtSBuff);
streamSkipUntil(','); // Throw away the final comma
if (alt != NULL) { // MSL Altitude. Unit is meters
*alt = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (speed != NULL) { // Speed Over Ground. Unit is knots.
*speed = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // After set, will report GPS every x seconds
if (accuracy != NULL) { // Position Dilution Of Precision
*accuracy = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Horizontal Dilution Of Precision
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil('\n'); // TODO(?) is one more field reported??
ihour = streamGetInt(static_cast<int8_t>(2)); // Two digit hour
imin = streamGetInt(static_cast<int8_t>(2)); // Two digit minute
secondWithSS = streamGetFloat(','); // 4 digit second with subseconds
ialt = streamGetFloat(','); // MSL Altitude. Unit is meters
ispeed = streamGetFloat(','); // Speed Over Ground. Unit is knots.
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // After set, will report GPS every x seconds
iaccuracy = streamGetFloat(','); // Position Dilution Of Precision
streamSkipUntil(','); // Horizontal Dilution Of Precision
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil('\n'); // TODO(?) is one more field reported??
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (speed != NULL) *speed = ispeed;
if (alt != NULL) *alt = ialt;
if (vsat != NULL) *vsat = ivsat;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = static_cast<int>(secondWithSS);
waitResponse(); waitResponse();
return true; return true;
} }
waitResponse();
return false; return false;
} }


+ 67
- 75
src/TinyGsmClientSIM808.h View File

@ -41,7 +41,7 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
// works only with ans SIM808 V2 // works only with ans SIM808 V2
String getGPSrawImpl() { String getGPSrawImpl() {
sendAT(GF("+CGNSINF")); sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
String res = stream.readStringUntil('\n'); String res = stream.readStringUntil('\n');
waitResponse(); waitResponse();
res.trim(); res.trim();
@ -54,84 +54,76 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
int* vsat = 0, int* usat = 0, float* accuracy = 0, int* vsat = 0, int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0, int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) { int* minute = 0, int* second = 0) {
bool fix = false;
sendAT(GF("+CGNSINF")); sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
streamSkipUntil(','); // GNSS run status
if (streamGetInt(',') == 1) fix = true; // fix status
// UTC date & Time
char dtSBuff[7] = {'\0'};
stream.readBytes(dtSBuff, 4); // Four digit year
dtSBuff[4] = '\0'; // null terminate buffer
if (year != NULL) *year = atoi(dtSBuff); // Convert to int
stream.readBytes(dtSBuff, 2); // Two digit month
dtSBuff[2] = '\0';
if (month != NULL) *month = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit day
dtSBuff[2] = '\0';
if (day != NULL) *day = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit hour
dtSBuff[2] = '\0';
if (hour != NULL) *hour = atoi(dtSBuff);
stream.readBytes(dtSBuff, 2); // Two digit minute
dtSBuff[2] = '\0';
if (minute != NULL) *minute = atoi(dtSBuff);
stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds
dtSBuff[6] = '\0';
if (second != NULL) *second = atoi(dtSBuff);
// *secondWithSS = atof(dtSBuff);
streamSkipUntil(','); // Throw away the final comma
*lat = streamGetFloat(','); // Latitude
*lon = streamGetFloat(','); // Longitude
if (alt != NULL) { // MSL Altitude. Unit is meters
*alt = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (speed != NULL) { // Speed Over Ground. Unit is knots.
*speed = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // Fix Mode
streamSkipUntil(','); // Reserved1
streamSkipUntil(','); // Horizontal Dilution Of Precision
if (accuracy != NULL) { // Position Dilution Of Precision
*accuracy = streamGetFloat(',');
} else {
streamSkipUntil(',');
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
streamSkipUntil(','); // GNSS run status
if (streamGetInt(',') == 1) { // fix status
// init variables
float ilat = 0;
float ilon = 0;
float ispeed = 0;
int ialt = 0;
int ivsat = 0;
int iusat = 0;
float iaccuracy = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
float secondWithSS = 0;
// UTC date & Time
iyear = streamGetInt(static_cast<int8_t>(4)); // Four digit year
imonth = streamGetInt(static_cast<int8_t>(2)); // Two digit month
iday = streamGetInt(static_cast<int8_t>(2)); // Two digit day
ihour = streamGetInt(static_cast<int8_t>(2)); // Two digit hour
imin = streamGetInt(static_cast<int8_t>(2)); // Two digit minute
secondWithSS = streamGetFloat(','); // 6 digit second with subseconds
ilat = streamGetFloat(','); // Latitude
ilon = streamGetFloat(','); // Longitude
ialt = streamGetFloat(','); // MSL Altitude. Unit is meters
ispeed = streamGetFloat(','); // Speed Over Ground. Unit is knots.
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // Fix Mode
streamSkipUntil(','); // Reserved1
streamSkipUntil(','); // Horizontal Dilution Of Precision
iaccuracy = streamGetFloat(','); // Position Dilution Of Precision
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil(','); // Reserved2
ivsat = streamGetInt(','); // GNSS Satellites in View
iusat = streamGetInt(','); // GNSS Satellites Used
streamSkipUntil(','); // GLONASS Satellites Used
streamSkipUntil(','); // Reserved3
streamSkipUntil(','); // C/N0 max
streamSkipUntil(','); // HPA
streamSkipUntil('\n'); // VPA
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (speed != NULL) *speed = ispeed;
if (alt != NULL) *alt = ialt;
if (vsat != NULL) *vsat = ivsat;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = static_cast<int>(secondWithSS);
waitResponse();
return true;
} }
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil(','); // Reserved2
if (vsat != NULL) { // GNSS Satellites in View
*vsat = streamGetInt(',');
} else {
streamSkipUntil(',');
}
if (usat != NULL) { // GNSS Satellites Used
*usat = streamGetInt(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // GLONASS Satellites Used
streamSkipUntil(','); // Reserved3
streamSkipUntil(','); // C/N0 max
streamSkipUntil(','); // HPA
streamSkipUntil('\n'); // VPA
streamSkipUntil('\n'); // toss the row of commas
waitResponse(); waitResponse();
return fix;
return false;
} }
}; };


+ 53
- 67
src/TinyGsmClientSaraR4.h View File

@ -445,14 +445,14 @@ class TinyGsmSaraR4
if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; } if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; }
return waitResponse(10000L) == 1; return waitResponse(10000L) == 1;
} }
String getUbloxLocationRaw(int8_t sensor) {
String inline getUbloxLocationRaw(int8_t sensor) {
// AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy> // AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy>
// <mode> - 2: single shot position // <mode> - 2: single shot position
// <sensor> - 0: use the last fix in the internal database and stop the GNSS // <sensor> - 0: use the last fix in the internal database and stop the GNSS
// receiver // receiver
// - 1: use the GNSS receiver for localization // - 1: use the GNSS receiver for localization
// - 2: use cellular CellLocate® location information
// - 3: ?? use the combined GNSS receiver and CellLocate® service
// - 2: use cellular CellLocate location information
// - 3: ?? use the combined GNSS receiver and CellLocate service
// information ?? - Docs show using sensor 3 and it's // information ?? - Docs show using sensor 3 and it's
// documented for the +UTIME command but not for +ULOC // documented for the +UTIME command but not for +ULOC
// <response_type> - 0: standard (single-hypothesis) response // <response_type> - 0: standard (single-hypothesis) response
@ -475,18 +475,18 @@ class TinyGsmSaraR4
return getUbloxLocationRaw(1); return getUbloxLocationRaw(1);
} }
bool getUbloxLocation(int8_t sensor, float* lat, float* lon, float* speed = 0,
bool inline getUbloxLocation(int8_t sensor, float* lat, float* lon, float* speed = 0,
int* alt = 0, int* vsat = 0, int* usat = 0, int* alt = 0, int* vsat = 0, int* usat = 0,
float* accuracy = 0, int* year = 0, int* month = 0, float* accuracy = 0, int* year = 0, int* month = 0,
int* day = 0, int* hour = 0, int* minute = 0, int* day = 0, int* hour = 0, int* minute = 0,
int* second = 0) { int* second = 0) {
// AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy> // AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy>
// <mode> - 2: single shot position // <mode> - 2: single shot position
// <sensor> - 2: use cellular CellLocate® location information
// <sensor> - 2: use cellular CellLocate location information
// - 0: use the last fix in the internal database and stop the GNSS // - 0: use the last fix in the internal database and stop the GNSS
// receiver // receiver
// - 1: use the GNSS receiver for localization // - 1: use the GNSS receiver for localization
// - 3: ?? use the combined GNSS receiver and CellLocate® service
// - 3: ?? use the combined GNSS receiver and CellLocate service
// information ?? - Docs show using sensor 3 and it's documented // information ?? - Docs show using sensor 3 and it's documented
// for the +UTIME command but not for +ULOC // for the +UTIME command but not for +ULOC
// <response_type> - 0: standard (single-hypothesis) response // <response_type> - 0: standard (single-hypothesis) response
@ -502,74 +502,60 @@ class TinyGsmSaraR4
// <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>, // <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>,
// <jamming_status> // <jamming_status>
// init variables
float ilat = 0;
float ilon = 0;
float ispeed = 0;
int ialt = 0;
int iusat = 0;
float iaccuracy = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
float secondWithSS = 0;
// Date & Time // Date & Time
char dtSBuff[7] = {'\0'};
stream.readBytes(dtSBuff, 2); // Two digit day
dtSBuff[2] = '\0'; // null terminate buffer
if (day != NULL) *day = atoi(dtSBuff); // Convert to int
streamSkipUntil('/'); // Throw out slash
stream.readBytes(dtSBuff, 2); // Two digit month
dtSBuff[2] = '\0';
if (month != NULL) *month = atoi(dtSBuff);
streamSkipUntil('/'); // Throw out slash
stream.readBytes(dtSBuff, 4); // Four digit year
dtSBuff[4] = '\0';
if (year != NULL) *year = atoi(dtSBuff);
streamSkipUntil(','); // Throw out comma
stream.readBytes(dtSBuff, 2); // Two digit hour
dtSBuff[2] = '\0';
if (hour != NULL) *hour = atoi(dtSBuff);
streamSkipUntil(':'); // Throw out colon
stream.readBytes(dtSBuff, 2); // Two digit minute
dtSBuff[2] = '\0';
if (minute != NULL) *minute = atoi(dtSBuff);
streamSkipUntil(':'); // Throw out colon
stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds
dtSBuff[6] = '\0';
if (second != NULL) *second = atoi(dtSBuff);
// *secondWithSS = atof(dtSBuff);
streamSkipUntil(','); // Throw away the final comma
*lat = streamGetFloat(','); // Estimated latitude, in degrees
*lon = streamGetFloat(','); // Estimated longitude, in degrees
if (alt != NULL) { // Estimated altitude, in meters - only for GNSS
// positioning, 0 in case of CellLocate
*alt = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (accuracy != NULL) { // Maximum possible error, in meters (0 - 20000000)
*accuracy = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (speed != NULL) { // Speed over ground m/s3
*speed = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
iday = streamGetInt('/'); // Two digit day
imonth = streamGetInt('/'); // Two digit month
iyear = streamGetInt(','); // Four digit year
ihour = streamGetInt(':'); // Two digit hour
imin = streamGetInt(':'); // Two digit minute
secondWithSS = streamGetFloat(','); // 6 digit second with subseconds
ilat = streamGetFloat(','); // Estimated latitude, in degrees
ilon = streamGetFloat(','); // Estimated longitude, in degrees
ialt = streamGetFloat(','); // Estimated altitude, in meters - only for
iaccuracy = streamGetFloat(
','); // Maximum possible error, in meters (0 - 20000000)
ispeed = streamGetFloat(','); // Speed over ground m/s3
streamSkipUntil(','); // Course over ground in degree (0 deg - 360 deg) streamSkipUntil(','); // Course over ground in degree (0 deg - 360 deg)
streamSkipUntil(','); // Vertical accuracy, in meters streamSkipUntil(','); // Vertical accuracy, in meters
streamSkipUntil(','); // Sensor used for the position calculation streamSkipUntil(','); // Sensor used for the position calculation
if (vsat != NULL) vsat = 0; // Number of satellites viewed not reported
if (usat != NULL) { // Number of satellite used to calculate the position
*usat = streamGetInt(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Antenna status
iusat = streamGetInt(
','); // Number of satellite used to calculate the position
streamSkipUntil(','); // Antenna status
streamSkipUntil('\n'); // Jamming status streamSkipUntil('\n'); // Jamming status
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (speed != NULL) *speed = ispeed;
if (alt != NULL) *alt = ialt;
if (vsat != NULL) *vsat = 0; // Number of satellites viewed not reported;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = static_cast<int>(secondWithSS);
// final ok // final ok
waitResponse(); waitResponse();
return true; return true;
} }
bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0, bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0,
@ -577,7 +563,7 @@ class TinyGsmSaraR4
int* hour = 0, int* minute = 0, int* second = 0) { int* hour = 0, int* minute = 0, int* second = 0) {
return getUbloxLocation(2, lat, lon, 0, 0, 0, 0, accuracy, year, month, day, return getUbloxLocation(2, lat, lon, 0, 0, 0, 0, accuracy, year, month, day,
hour, minute, second); hour, minute, second);
};
}
bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0, bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0,
int* vsat = 0, int* usat = 0, float* accuracy = 0, int* vsat = 0, int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0, int* year = 0, int* month = 0, int* day = 0, int* hour = 0,


+ 53
- 67
src/TinyGsmClientUBLOX.h View File

@ -412,14 +412,14 @@ class TinyGsmUBLOX
if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; } if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; }
return waitResponse(10000L) == 1; return waitResponse(10000L) == 1;
} }
String getUbloxLocationRaw(int8_t sensor) {
String inline getUbloxLocationRaw(int8_t sensor) {
// AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy> // AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy>
// <mode> - 2: single shot position // <mode> - 2: single shot position
// <sensor> - 0: use the last fix in the internal database and stop the GNSS // <sensor> - 0: use the last fix in the internal database and stop the GNSS
// receiver // receiver
// - 1: use the GNSS receiver for localization // - 1: use the GNSS receiver for localization
// - 2: use cellular CellLocate® location information
// - 3: ?? use the combined GNSS receiver and CellLocate® service
// - 2: use cellular CellLocate location information
// - 3: ?? use the combined GNSS receiver and CellLocate service
// information ?? - Docs show using sensor 3 and it's // information ?? - Docs show using sensor 3 and it's
// documented for the +UTIME command but not for +ULOC // documented for the +UTIME command but not for +ULOC
// <response_type> - 0: standard (single-hypothesis) response // <response_type> - 0: standard (single-hypothesis) response
@ -442,18 +442,18 @@ class TinyGsmUBLOX
return getUbloxLocationRaw(1); return getUbloxLocationRaw(1);
} }
bool getUbloxLocation(int8_t sensor, float* lat, float* lon, float* speed = 0,
bool inline getUbloxLocation(int8_t sensor, float* lat, float* lon, float* speed = 0,
int* alt = 0, int* vsat = 0, int* usat = 0, int* alt = 0, int* vsat = 0, int* usat = 0,
float* accuracy = 0, int* year = 0, int* month = 0, float* accuracy = 0, int* year = 0, int* month = 0,
int* day = 0, int* hour = 0, int* minute = 0, int* day = 0, int* hour = 0, int* minute = 0,
int* second = 0) { int* second = 0) {
// AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy> // AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy>
// <mode> - 2: single shot position // <mode> - 2: single shot position
// <sensor> - 2: use cellular CellLocate® location information
// <sensor> - 2: use cellular CellLocate location information
// - 0: use the last fix in the internal database and stop the GNSS // - 0: use the last fix in the internal database and stop the GNSS
// receiver // receiver
// - 1: use the GNSS receiver for localization // - 1: use the GNSS receiver for localization
// - 3: ?? use the combined GNSS receiver and CellLocate® service
// - 3: ?? use the combined GNSS receiver and CellLocate service
// information ?? - Docs show using sensor 3 and it's documented // information ?? - Docs show using sensor 3 and it's documented
// for the +UTIME command but not for +ULOC // for the +UTIME command but not for +ULOC
// <response_type> - 0: standard (single-hypothesis) response // <response_type> - 0: standard (single-hypothesis) response
@ -469,74 +469,60 @@ class TinyGsmUBLOX
// <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>, // <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>,
// <jamming_status> // <jamming_status>
// init variables
float ilat = 0;
float ilon = 0;
float ispeed = 0;
int ialt = 0;
int iusat = 0;
float iaccuracy = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
float secondWithSS = 0;
// Date & Time // Date & Time
char dtSBuff[7] = {'\0'};
stream.readBytes(dtSBuff, 2); // Two digit day
dtSBuff[2] = '\0'; // null terminate buffer
if (day != NULL) *day = atoi(dtSBuff); // Convert to int
streamSkipUntil('/'); // Throw out slash
stream.readBytes(dtSBuff, 2); // Two digit month
dtSBuff[2] = '\0';
if (month != NULL) *month = atoi(dtSBuff);
streamSkipUntil('/'); // Throw out slash
stream.readBytes(dtSBuff, 4); // Four digit year
dtSBuff[4] = '\0';
if (year != NULL) *year = atoi(dtSBuff);
streamSkipUntil(','); // Throw out comma
stream.readBytes(dtSBuff, 2); // Two digit hour
dtSBuff[2] = '\0';
if (hour != NULL) *hour = atoi(dtSBuff);
streamSkipUntil(':'); // Throw out colon
stream.readBytes(dtSBuff, 2); // Two digit minute
dtSBuff[2] = '\0';
if (minute != NULL) *minute = atoi(dtSBuff);
streamSkipUntil(':'); // Throw out colon
stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds
dtSBuff[6] = '\0';
if (second != NULL) *second = atoi(dtSBuff);
// *secondWithSS = atof(dtSBuff);
streamSkipUntil(','); // Throw away the final comma
*lat = streamGetFloat(','); // Estimated latitude, in degrees
*lon = streamGetFloat(','); // Estimated longitude, in degrees
if (alt != NULL) { // Estimated altitude, in meters - only for GNSS
// positioning, 0 in case of CellLocate
*alt = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (accuracy != NULL) { // Maximum possible error, in meters (0 - 20000000)
*accuracy = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
if (speed != NULL) { // Speed over ground m/s3
*speed = streamGetFloat(',');
} else {
streamSkipUntil(',');
}
iday = streamGetInt('/'); // Two digit day
imonth = streamGetInt('/'); // Two digit month
iyear = streamGetInt(','); // Four digit year
ihour = streamGetInt(':'); // Two digit hour
imin = streamGetInt(':'); // Two digit minute
secondWithSS = streamGetFloat(','); // 6 digit second with subseconds
ilat = streamGetFloat(','); // Estimated latitude, in degrees
ilon = streamGetFloat(','); // Estimated longitude, in degrees
ialt = streamGetFloat(','); // Estimated altitude, in meters - only for
iaccuracy = streamGetFloat(
','); // Maximum possible error, in meters (0 - 20000000)
ispeed = streamGetFloat(','); // Speed over ground m/s3
streamSkipUntil(','); // Course over ground in degree (0 deg - 360 deg) streamSkipUntil(','); // Course over ground in degree (0 deg - 360 deg)
streamSkipUntil(','); // Vertical accuracy, in meters streamSkipUntil(','); // Vertical accuracy, in meters
streamSkipUntil(','); // Sensor used for the position calculation streamSkipUntil(','); // Sensor used for the position calculation
if (vsat != NULL) *vsat = 0; // Number of satellites viewed not reported
if (usat != NULL) { // Number of satellite used to calculate the position
*usat = streamGetInt(',');
} else {
streamSkipUntil(',');
}
streamSkipUntil(','); // Antenna status
iusat = streamGetInt(
','); // Number of satellite used to calculate the position
streamSkipUntil(','); // Antenna status
streamSkipUntil('\n'); // Jamming status streamSkipUntil('\n'); // Jamming status
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (speed != NULL) *speed = ispeed;
if (alt != NULL) *alt = ialt;
if (vsat != NULL) *vsat = 0; // Number of satellites viewed not reported;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = static_cast<int>(secondWithSS);
// final ok // final ok
waitResponse(); waitResponse();
return true; return true;
} }
bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0, bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0,
@ -544,7 +530,7 @@ class TinyGsmUBLOX
int* hour = 0, int* minute = 0, int* second = 0) { int* hour = 0, int* minute = 0, int* second = 0) {
return getUbloxLocation(2, lat, lon, 0, 0, 0, 0, accuracy, year, month, day, return getUbloxLocation(2, lat, lon, 0, 0, 0, 0, accuracy, year, month, day,
hour, minute, second); hour, minute, second);
};
}
bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0, bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0,
int* vsat = 0, int* usat = 0, float* accuracy = 0, int* vsat = 0, int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0, int* year = 0, int* month = 0, int* day = 0, int* hour = 0,


+ 33
- 37
src/TinyGsmGSMLocation.tpp View File

@ -93,45 +93,41 @@ class TinyGsmGSMLocation {
if (thisModem().waitResponse(120000L, GF("+CLBS:0,")) != 1) { if (thisModem().waitResponse(120000L, GF("+CLBS:0,")) != 1) {
return false; return false;
} }
*lat = thisModem().streamGetFloat(','); // Latitude
*lon = thisModem().streamGetFloat(','); // Longitude
if (accuracy != NULL) { // Positioning accuracy
*accuracy = thisModem().streamGetInt(',');
} else {
thisModem().streamSkipUntil(',');
}
// init variables
float ilat = 0;
float ilon = 0;
float iaccuracy = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
int isec = 0;
ilat = thisModem().streamGetFloat(','); // Latitude
ilon = thisModem().streamGetFloat(','); // Longitude
iaccuracy = thisModem().streamGetInt(','); // Positioning accuracy
// Date & Time // Date & Time
char dtSBuff[5] = {'\0'};
thisModem().stream.readBytes(dtSBuff, 4); // Four digit year
dtSBuff[4] = '\0'; // null terminate buffer
if (year != NULL) *year = atoi(dtSBuff); // Convert to int
thisModem().streamSkipUntil('/'); // Throw out slash
thisModem().stream.readBytes(dtSBuff, 2); // Two digit month
dtSBuff[2] = '\0';
if (month != NULL) *month = atoi(dtSBuff);
thisModem().streamSkipUntil('/'); // Throw out slash
thisModem().stream.readBytes(dtSBuff, 2); // Two digit day
dtSBuff[2] = '\0';
if (day != NULL) *day = atoi(dtSBuff);
thisModem().streamSkipUntil(','); // Throw out comma
thisModem().stream.readBytes(dtSBuff, 2); // Two digit hour
dtSBuff[2] = '\0';
if (hour != NULL) *hour = atoi(dtSBuff);
thisModem().streamSkipUntil(':'); // Throw out colon
thisModem().stream.readBytes(dtSBuff, 2); // Two digit minute
dtSBuff[2] = '\0';
if (minute != NULL) *minute = atoi(dtSBuff);
thisModem().streamSkipUntil(':'); // Throw out colon
thisModem().stream.readBytes(dtSBuff, 2); // Two digit second
dtSBuff[2] = '\0';
if (second != NULL) *second = atoi(dtSBuff);
thisModem().streamSkipUntil('\n'); // Should be at the end of the line
iyear = thisModem().streamGetInt('/');
imonth = thisModem().streamGetInt('/');
iday = thisModem().streamGetInt(',');
ihour = thisModem().streamGetInt(':');
imin = thisModem().streamGetInt(':');
isec = thisModem().streamGetInt('\n');
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = isec;
// Final OK // Final OK
thisModem().waitResponse(); thisModem().waitResponse();


+ 30
- 2
src/TinyGsmModem.tpp View File

@ -255,7 +255,21 @@ class TinyGsmModem {
thisModem().streamWrite(tail...); thisModem().streamWrite(tail...);
} }
int16_t inline streamGetInt(char lastChar) {
int16_t inline streamGetInt(int8_t numChars) {
char buf[6];
size_t bytesRead = thisModem().stream.readBytes(buf, numChars);
if (bytesRead) {
buf[numChars] = '\0';
int16_t res = atoi(buf);
return res;
} else {
return -9999;
}
}
template <class T>
// calling with template only to prevent promotion of char to int
int16_t inline streamGetInt(T lastChar) {
char buf[6]; char buf[6];
size_t bytesRead = thisModem().stream.readBytesUntil( size_t bytesRead = thisModem().stream.readBytesUntil(
lastChar, buf, static_cast<size_t>(6)); lastChar, buf, static_cast<size_t>(6));
@ -267,7 +281,21 @@ class TinyGsmModem {
} }
} }
float inline streamGetFloat(char lastChar) {
float inline streamGetFloat(int8_t numChars) {
char buf[12];
size_t bytesRead = thisModem().stream.readBytes(buf, numChars);
if (bytesRead) {
buf[numChars] = '\0';
int16_t res = atof(buf);
return res;
} else {
return static_cast<float>(-9999);
}
}
template <class T>
// calling with template only to prevent promotion of char to int
float inline streamGetFloat(T lastChar) {
char buf[12]; char buf[12];
size_t bytesRead = thisModem().stream.readBytesUntil( size_t bytesRead = thisModem().stream.readBytesUntil(
lastChar, buf, static_cast<size_t>(12)); lastChar, buf, static_cast<size_t>(12));


Loading…
Cancel
Save