Merge pull request #794 from EnviroDIY/master

Updates from EnviroDIY
This commit is contained in:
Sara Damiano
2024-05-28 15:15:09 -04:00
committed by GitHub
56 changed files with 6046 additions and 3607 deletions

View File

@@ -25,7 +25,7 @@ with your board before submitting any issues.
Modem: <!-- Brand, model, variant, firmware version, ie Quectel BG96 Revision: BG96MAR02A07M1G -->
Main processor board: <!-- Uno, Zero, ESP32, Particle, etc -->
TinyGSM version: <!-- always try to use the latest (0.11.7) -->
TinyGSM version: <!-- always try to use the latest (0.12.0) -->
Code: <!-- Example name or paste in your code -->
### Scenario, steps to reproduce

View File

@@ -3,10 +3,67 @@ name: Build Examples with PlatformIO
# Triggers the workflow on push or pull request events
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
determine_library_source:
name: determine_library_source
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'ci skip')"
outputs:
library_install_zip: ${{ steps.store_vars.outputs.library_install_zip }}
library_install_git: ${{ steps.store_vars.outputs.library_install_git }}
steps:
- uses: actions/checkout@v4
- name: Set environment variables for pushes to any branch
if: github.event_name == 'push'
run: |
echo "Push to commit ${GITHUB_SHA}"
echo "LIBRARY_INSTALL_ZIP=https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.zip" >> $GITHUB_ENV
echo "LIBRARY_INSTALL_GIT=https://github.com/${GITHUB_REPOSITORY}.git#${GITHUB_SHA}" >> $GITHUB_ENV
- name: Set environment variable for PR's from any branch
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.name == github.repository
run: |
echo "Pull Request from the ${GITHUB_HEAD_REF} branch"
echo "LIBRARY_INSTALL_ZIP=https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_HEAD_REF}.zip" >> $GITHUB_ENV
echo "LIBRARY_INSTALL_GIT=https://github.com/${GITHUB_REPOSITORY}.git#${GITHUB_HEAD_REF}" >> $GITHUB_ENV
- name: Set environment variable for PR's from any branch
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.name != github.repository
run: |
echo "Pull Request from the fork ${{ github.event.pull_request.head.repo.full_name }} at ${{ github.event.pull_request.head.ref }}"
echo "LIBRARY_INSTALL_ZIP=https://github.com/${{ github.event.pull_request.head.repo.full_name }}/archive/${{ github.event.pull_request.head.ref }}.zip" >> $GITHUB_ENV
echo "LIBRARY_INSTALL_GIT=https://github.com/${{ github.event.pull_request.head.repo.full_name }}.git#${{ github.event.pull_request.head.ref }}" >> $GITHUB_ENV
- name: store enviroment variables as output
id: store_vars
run: |
echo "library_install_zip=${{ env.LIBRARY_INSTALL_ZIP }}" >> $GITHUB_OUTPUT
echo "library_install_git=${{ env.LIBRARY_INSTALL_GIT }}" >> $GITHUB_OUTPUT
print_library_source:
name: print_library_source
runs-on: ubuntu-latest
needs: determine_library_source
steps:
- name: Check the library installation source
run: |
echo "Link to zip for Arduino CLI testing install:"
echo "${{ needs.determine_library_source.outputs.library_install_zip }}"
echo
echo "Git reference for PlatformIO testing install"
echo "${{ needs.determine_library_source.outputs.library_install_git }}"
build_pio:
runs-on: ubuntu-latest
needs: [determine_library_source]
env:
LIBRARY_INSTALL_GIT: ${{ needs.determine_library_source.outputs.library_install_git }}
strategy:
matrix:
@@ -23,6 +80,7 @@ jobs:
[
TINY_GSM_MODEM_A6,
TINY_GSM_MODEM_BG96,
TINY_GSM_MODEM_A7672X,
TINY_GSM_MODEM_ESP8266,
TINY_GSM_MODEM_M95,
TINY_GSM_MODEM_M590,
@@ -36,12 +94,13 @@ jobs:
TINY_GSM_MODEM_SIM7070,
TINY_GSM_MODEM_UBLOX,
TINY_GSM_MODEM_SARAR4,
TINY_GSM_MODEM_SARAR5,
TINY_GSM_MODEM_XBEE,
TINY_GSM_MODEM_SEQUANS_MONARCH,
]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set variables
run: |
@@ -54,7 +113,7 @@ jobs:
fi
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.x'
@@ -64,8 +123,8 @@ jobs:
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Restore or Cache Platforms and Libraries
uses: actions/cache@v3.3.1
- name: Restore or Cache PlatformIO Platforms and Libraries
uses: actions/cache@v4
id: cache_pio
with:
path: ~/.platformio
@@ -75,7 +134,7 @@ jobs:
key: ${{ hashFiles('./examples/example_dependencies.json') }}
# Install cores and library dependencies for the Arduino CLI, iff no cache
- name: Install the Arduino libraries
- name: Install the Arduino libraries for PlatformIO
if: steps.cache_pio.outputs.cache-hit != 'true'
run: pio lib --global install 89 415 1202 1286
@@ -84,8 +143,8 @@ jobs:
PLATFORMIO_CI_SRC: ${{ matrix.example }}
TINYGSM_MODEM_TO_USE: ${{ matrix.modem }}
run: |
echo "${{ env.LIBRARY_INSTALL_SOURCE }}"
pio lib --global install ${{ env.LIBRARY_INSTALL_SOURCE }}
echo "${{ env.LIBRARY_INSTALL_GIT }}"
pio pkg install -g --library ${{ env.LIBRARY_INSTALL_GIT }}
sed -i 's/\/\/ #define TINY_GSM_MODEM_SIM800/#define TINY_GSM_MODEM_SIM800/g' ${{ matrix.example }}/*
platformio ci --project-option='build_flags=-D ${{ env.TINYGSM_MODEM_TO_USE }}' --project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=uno_pic32 --board=esp01 --board=nodemcuv2 --board=esp32dev
pio lib --global uninstall TinyGSM

3
.gitignore vendored
View File

@@ -47,3 +47,6 @@ extras/At Command Manuals - Unsupported/*
filters/*
platformio_extra_envs.ini
*.tar.gz
pioScripts/generate_compile_commands.py
compile_commands.json
src/TinyGsmATDefines.h

60
ChangeLog.md Normal file
View File

@@ -0,0 +1,60 @@
# ChangeLog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and its stricter, better defined, brother [Common Changelog](https://common-changelog.org/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
***
## [Unreleased]
****
### Changed
### Added
### Removed
### Fixed
***
## [v0.12.0]
### Changed
- Moved bulk of waitResponse function to modem template and gave modems handleURCs fxn
- Moved option in waitResponse for verbose outputs.
- setBaud now returns a bool
- Replace new line consts with defines and renamed to AT_NL
- Renamed all RegStatus enums to be unique
- Replaced `NULL` with `nullptr` and replaced c-style casts.
- Moved setCertificates function and the certificate name matrix to the SSL template.
- Changed inputs for (unimplemented) SSL certificate functions.
- All modems will now return the pre-defined manufacturer and model in the name if the function to get the internal name fails.
- Cleaned up code for getting modem names.
- Made battery return types signed.
### Added
- Added support for SSL for the Quentcel BG95 and BG96 from [Aurelien BOUIN](https://github.com/aurelihein) and [George O'Connor](https://github.com/georgeman93)
- Added support for UBLOX SARA-R5 from [Sebastian Bergner](https://github.com/sebastianbergner)
- Added support for SIMCOM A7672X from [Giovanni de Rosso Unruh](https://github.com/giovannirosso)
- Added SIM5320 GPS location from [Bengarman](https://github.com/Bengarman)
- Added functions `getModemSerialNumber`, `getModemModel`, and `getModemRevision`.
- Added deep debugging option
- Added documentation to the FIFO class
### Removed
- Removed non-functional factory reset from SIM70xx series
### Fixed
- Removed extra wait on SIM7000 from [Mikael Fredriksson](https://github.com/Gelemikke)
- Fix status returns on ESP8266/ESP32 AT commands
- Fix length of HEX for Sequans Monarch
- Fix SIM7600 password then user when cid is set from [github0013](https://github.com/github0013)
- Fix cardinal points in location by gps for SIM7600 from [Juxn3](https://github.com/Juxn3)
- Fix NTP server sync for SIM70xx models from [Gonzalo Brusco](https://github.com/gonzabrusco)
- Fixed SIM70xx inheritance
***

View File

@@ -17,7 +17,7 @@ If you like **TinyGSM** - give it a star, or fork it and contribute!
[![GitHub forks](https://img.shields.io/github/forks/vshymanskyy/TinyGSM.svg?style=social&label=Fork)](https://github.com/vshymanskyy/TinyGSM/network)
You can also join our chat:
[![Gitter](https://img.shields.io/gitter/room/vshymanskyy/TinyGSM.svg)](https://gitter.im/tinygsm)
[![Gitter](https://img.shields.io/gitter/room/vshymanskyy/TinyGSM.svg)](https://app.gitter.im/#/room/#tinygsm_Lobby:gitter.im)
- [Supported modems](#supported-modems)
- [Supported boards/modules](#supported-boardsmodules)
@@ -29,7 +29,7 @@ You can also join our chat:
- [How does it work?](#how-does-it-work)
- [API Reference](#api-reference)
- [Troubleshooting](#troubleshooting)
- [Ensure stable data & power connection](#ensure-stable-data--power-connection)
- [Ensure stable data \& power connection](#ensure-stable-data--power-connection)
- [Baud rates](#baud-rates)
- [Broken initial configuration](#broken-initial-configuration)
- [Failed connection or no data received](#failed-connection-or-no-data-received)
@@ -70,34 +70,32 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
- SIMCom LTE Modules (SIM7100E, SIM7500E, SIM7500A, SIM7600C, SIM7600E)
- SIMCom SIM7000E/A/G CAT-M1/NB-IoT Module
- SIMCom SIM7070/SIM7080/SIM7090 CAT-M1/NB-IoT Module
- SIMCom A7672X CAT-M1 Module
- AI-Thinker A6, A6C, A7, A20
- ESP8266/ESP32 (AT commands interface, similar to GSM modems)
- Digi XBee WiFi and Cellular (using XBee command mode)
- Neoway M590
- u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
- u-blox LTE-M/NB-IoT Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_)
- u-blox LTE-M/NB-IoT Modems (SARA-R4xx, SARA-N4xx, SARA-R5xx, _but NOT SARA-N2xx_)
- Sequans Monarch LTE Cat M1/NB1 (VZM20Q)
- Quectel BG96
- Quectel BG95
- Quectel M95
- Quectel MC60 ***(alpha)***
### Supported boards/modules
- EnviroDIY LTE Bee, WiFi Bee
- Arduino MKR GSM 1400
- GPRSbee
- Sodaq GPRSbee, uBee
- Microduino GSM
- Adafruit FONA (Mini Cellular GSM Breakout)
- Adafruit FONA 800/808 Shield
- Adafruit FONA Mini Cellular GSM Breakout, 800/808 Shield, FONA 3G
- Industruino GSM
- Dragino NB-IoT Bee
- Digi XBee S6B, XBee LTE Cat 1, XBee3 LTE Cat 1, XBee3 CatM
- Nimbelink Skywire/Airgain NL-SW-LTE-QBG96, NL-SW-LTE-QBG95
- RAK WisLTE ***(alpha)***
- ... other modules, based on supported modems. Some boards require [**special configuration**](https://github.com/vshymanskyy/TinyGSM/wiki/Board-configuration).
More modems may be supported later:
- [ ] Quectel M10, UG95
- [ ] SIMCom SIM7020
- [ ] Telit GL865
- [ ] ZTE MG2639
- [ ] Hi-Link HLK-RM04
Watch this repo for new updates! And of course, contributions are welcome ;)
## Features
@@ -110,6 +108,7 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
- ESP8266 - 5
- Neoway M590 - 2
- Quectel BG96 - 12
- Quectel BG95 - 12
- Quectel M95 - 6
- Quectel MC60/MC60E - 6
- Sequans Monarch - 6
@@ -118,6 +117,7 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
- SIM7000 - 8 possible without SSL, only 2 with
- SIM 7070/7080/7090 - 12
- SIM 7500/7600/7800 - 10
- SIM A7672X - 10
- u-blox 2G/3G - 7
- u-blox SARA R4/N4 - 7
- Digi XBee - _only 1 connection supported!_
@@ -125,10 +125,10 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
- Not yet supported on any module, though it may be some day
- SSL/TLS (HTTPS)
- Supported on:
- SIM800, SIM7000, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
- SIM800, SIM7000, A7672X, u-Blox, XBee _cellular_, ESP8266, Sequans Monarch and Quectel BG95 and BG96
- Note: **only some device models or firmware revisions have this feature** (SIM8xx R14.18, A7, etc.)
- Not yet supported on:
- Quectel modems, SIM 5360/5320/7100, SIM 7500/7600/7800
- SIM 5360/5320/7100, SIM 7500/7600/7800
- Not possible on:
- SIM900, A6/A7, Neoway M590, XBee _WiFi_
- Like TCP, most modules support simultaneous connections
@@ -151,14 +151,14 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
- Not yet supported on:
- SIM7000, SIM5360/5320/7100, SIM7500/7800, VZM20Q (Monarch)
- Not possible on:
- XBee (any type), u-blox SARA R4/N4, Neoway M590, ESP8266 (obviously)
- XBee (any type), u-blox SARA R4/R5/N4, Neoway M590, ESP8266 (obviously)
- Functions:
- Dial, hangup
- DTMF sending
**Location**
- GPS/GNSS
- SIM808, SIM7000, SIM7500/7600/7800, BG96, u-blox
- SIM808, SIM7000, SIM7500/7600/7800, BG96, BG95, u-blox
- NOTE: u-blox chips do _NOT_ have embedded GPS - this functionality only works if a secondary GPS is connected to primary cellular chip over I2C
- GSM location service
- SIM800, SIM7000, Quectel, u-blox
@@ -176,6 +176,10 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
- [V1pr](https://github.com/V1pr)
- Quectel M95
- [replicadeltd](https://github.com/replicadeltd)
- UBLOX SARA-R5
- [Sebastian Bergner](https://github.com/sebastianbergner)
- SIMCOM A7672X
- [Giovanni de Rosso Unruh](https://github.com/giovannirosso)
- Other Contributors:
- https://github.com/vshymanskyy/TinyGSM/graphs/contributors

View File

@@ -19,9 +19,12 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -29,6 +32,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
@@ -69,17 +73,17 @@ SoftwareSerial SerialAT(2, 3); // RX, TX
#define TINY_GSM_TEST_WIFI false
#define TINY_GSM_TEST_TCP true
#define TINY_GSM_TEST_SSL true
#define TINY_GSM_TEST_CALL false
#define TINY_GSM_TEST_SMS false
#define TINY_GSM_TEST_USSD false
#define TINY_GSM_TEST_CALL true
#define TINY_GSM_TEST_SMS true
#define TINY_GSM_TEST_USSD true
#define TINY_GSM_TEST_BATTERY true
#define TINY_GSM_TEST_TEMPERATURE true
#define TINY_GSM_TEST_GSM_LOCATION false
#define TINY_GSM_TEST_NTP false
#define TINY_GSM_TEST_TIME false
#define TINY_GSM_TEST_GPS false
#define TINY_GSM_TEST_GSM_LOCATION true
#define TINY_GSM_TEST_GPS true
#define TINY_GSM_TEST_NTP true
#define TINY_GSM_TEST_TIME true
// disconnect and power down modem after tests
#define TINY_GSM_POWERDOWN false
#define TINY_GSM_POWERDOWN true
// set GSM PIN, if any
#define GSM_PIN ""
@@ -135,7 +139,7 @@ void setup() {
// !!!!!!!!!!!
DBG("Wait...");
delay(6000);
delay(6000L);
// Set GSM module baud rate
TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
@@ -154,18 +158,32 @@ void loop() {
return;
}
String modemInfo = modem.getModemInfo();
DBG("Modem Info:", modemInfo);
String name = modem.getModemName();
DBG("Modem Name:", name);
String modemInfo = modem.getModemInfo();
DBG("Modem Info:", modemInfo);
String manufacturer = modem.getModemManufacturer();
DBG("Modem Manufacturer:", manufacturer);
String hw_ver = modem.getModemModel();
DBG("Modem Hardware Version:", hw_ver);
String fv_ver = modem.getModemRevision();
DBG("Modem Firware Version:", fv_ver);
#if not defined(TINY_GSM_MODEM_ESP8266) && not defined(TINY_GSM_MODEM_ESP32)
String mod_sn = modem.getModemSerialNumber();
DBG("Modem Serial Number (may be SIM CCID):", mod_sn);
#endif
#if TINY_GSM_TEST_GPRS
// Unlock your SIM card with a PIN if needed
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
#endif
#if TINY_GSM_TEST_WIFI
#if TINY_GSM_TEST_WIFI && defined(TINY_GSM_MODEM_HAS_WIFI)
DBG("Setting SSID/password...");
if (!modem.networkConnect(wifiSSID, wifiPass)) {
DBG(" fail");
@@ -175,7 +193,7 @@ void loop() {
SerialMon.println(" success");
#endif
#if TINY_GSM_TEST_GPRS && defined TINY_GSM_MODEM_XBEE
#if TINY_GSM_TEST_GPRS && defined(TINY_GSM_MODEM_XBEE)
// The XBee must run the gprsConnect function BEFORE waiting for network!
modem.gprsConnect(apn, gprsUser, gprsPass);
#endif
@@ -210,6 +228,9 @@ void loop() {
String cop = modem.getOperator();
DBG("Operator:", cop);
// String prov = modem.getProvider();
// DBG("Provider:", prov);
IPAddress local = modem.localIP();
DBG("Local IP:", local);
@@ -265,6 +286,7 @@ void loop() {
#endif
#if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL
// TODO: Add test of adding certificcate
TinyGsmClientSecure secureClient(modem, 1);
const int securePort = 443;
DBG("Connecting securely to", server);
@@ -303,8 +325,8 @@ void loop() {
}
#endif
#if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \
defined CALL_TARGET
#if TINY_GSM_TEST_CALL && defined(TINY_GSM_MODEM_HAS_CALLING) && \
defined(CALL_TARGET)
DBG("Calling:", CALL_TARGET);
// This is NOT supported on M590
@@ -327,6 +349,7 @@ void loop() {
}
#endif
// Test the SMS functions
#if TINY_GSM_TEST_SMS && defined TINY_GSM_MODEM_HAS_SMS && defined SMS_TARGET
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
DBG("SMS:", res ? "OK" : "fail");
@@ -343,24 +366,27 @@ void loop() {
#endif
// Test the GSM location functions
#if TINY_GSM_TEST_GSM_LOCATION && defined TINY_GSM_MODEM_HAS_GSM_LOCATION
float lat = 0;
float lon = 0;
float accuracy = 0;
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int min = 0;
int sec = 0;
float gsm_latitude = 0;
float gsm_longitude = 0;
float gsm_accuracy = 0;
int gsm_year = 0;
int gsm_month = 0;
int gsm_day = 0;
int gsm_hour = 0;
int gsm_minute = 0;
int gsm_second = 0;
for (int8_t i = 15; i; i--) {
DBG("Requesting current GSM location");
if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
&min, &sec)) {
DBG("Latitude:", String(lat, 8), "\tLongitude:", String(lon, 8));
DBG("Accuracy:", accuracy);
DBG("Year:", year, "\tMonth:", month, "\tDay:", day);
DBG("Hour:", hour, "\tMinute:", min, "\tSecond:", sec);
if (modem.getGsmLocation(&gsm_latitude, &gsm_longitude, &gsm_accuracy,
&gsm_year, &gsm_month, &gsm_day, &gsm_hour,
&gsm_minute, &gsm_second)) {
DBG("Latitude:", String(gsm_latitude, 8),
"\tLongitude:", String(gsm_longitude, 8));
DBG("Accuracy:", gsm_accuracy);
DBG("Year:", gsm_year, "\tMonth:", gsm_month, "\tDay:", gsm_day);
DBG("Hour:", gsm_hour, "\tMinute:", gsm_minute, "\tSecond:", gsm_second);
break;
} else {
DBG("Couldn't get GSM location, retrying in 15s.");
@@ -372,33 +398,38 @@ void loop() {
DBG("GSM Based Location String:", location);
#endif
// Test the GPS functions
#if TINY_GSM_TEST_GPS && defined TINY_GSM_MODEM_HAS_GPS
DBG("Enabling GPS/GNSS/GLONASS and waiting 15s for warm-up");
#if !defined(TINY_GSM_MODEM_SARAR5) // not needed for this module
modem.enableGPS();
#endif
delay(15000L);
float lat2 = 0;
float lon2 = 0;
float speed2 = 0;
float alt2 = 0;
int vsat2 = 0;
int usat2 = 0;
float accuracy2 = 0;
int year2 = 0;
int month2 = 0;
int day2 = 0;
int hour2 = 0;
int min2 = 0;
int sec2 = 0;
float gps_latitude = 0;
float gps_longitude = 0;
float gps_speed = 0;
float gps_altitude = 0;
int gps_vsat = 0;
int gps_usat = 0;
float gps_accuracy = 0;
int gps_year = 0;
int gps_month = 0;
int gps_day = 0;
int gps_hour = 0;
int gps_minute = 0;
int gps_second = 0;
for (int8_t i = 15; i; i--) {
DBG("Requesting current GPS/GNSS/GLONASS location");
if (modem.getGPS(&lat2, &lon2, &speed2, &alt2, &vsat2, &usat2, &accuracy2,
&year2, &month2, &day2, &hour2, &min2, &sec2)) {
DBG("Latitude:", String(lat2, 8), "\tLongitude:", String(lon2, 8));
DBG("Speed:", speed2, "\tAltitude:", alt2);
DBG("Visible Satellites:", vsat2, "\tUsed Satellites:", usat2);
DBG("Accuracy:", accuracy2);
DBG("Year:", year2, "\tMonth:", month2, "\tDay:", day2);
DBG("Hour:", hour2, "\tMinute:", min2, "\tSecond:", sec2);
if (modem.getGPS(&gps_latitude, &gps_longitude, &gps_speed, &gps_altitude,
&gps_vsat, &gps_usat, &gps_accuracy, &gps_year, &gps_month,
&gps_day, &gps_hour, &gps_minute, &gps_second)) {
DBG("Latitude:", String(gps_latitude, 8),
"\tLongitude:", String(gps_longitude, 8));
DBG("Speed:", gps_speed, "\tAltitude:", gps_altitude);
DBG("Visible Satellites:", gps_vsat, "\tUsed Satellites:", gps_usat);
DBG("Accuracy:", gps_accuracy);
DBG("Year:", gps_year, "\tMonth:", gps_month, "\tDay:", gps_day);
DBG("Hour:", gps_hour, "\tMinute:", gps_minute, "\tSecond:", gps_second);
break;
} else {
DBG("Couldn't get GPS/GNSS/GLONASS location, retrying in 15s.");
@@ -407,31 +438,34 @@ void loop() {
}
DBG("Retrieving GPS/GNSS/GLONASS location again as a string");
String gps_raw = modem.getGPSraw();
#if !defined(TINY_GSM_MODEM_SARAR5) // not available for this module
DBG("GPS/GNSS Based Location String:", gps_raw);
DBG("Disabling GPS");
modem.disableGPS();
#endif
#endif
// Test the Network time functions
#if TINY_GSM_TEST_NTP && defined TINY_GSM_MODEM_HAS_NTP
DBG("Asking modem to sync with NTP");
modem.NTPServerSync("132.163.96.5", 20);
modem.NTPServerSync("pool.ntp.org", 20);
#endif
#if TINY_GSM_TEST_TIME && defined TINY_GSM_MODEM_HAS_TIME
int year3 = 0;
int month3 = 0;
int day3 = 0;
int hour3 = 0;
int min3 = 0;
int sec3 = 0;
float timezone = 0;
int ntp_year = 0;
int ntp_month = 0;
int ntp_day = 0;
int ntp_hour = 0;
int ntp_min = 0;
int ntp_sec = 0;
float ntp_timezone = 0;
for (int8_t i = 5; i; i--) {
DBG("Requesting current network time");
if (modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3,
&timezone)) {
DBG("Year:", year3, "\tMonth:", month3, "\tDay:", day3);
DBG("Hour:", hour3, "\tMinute:", min3, "\tSecond:", sec3);
DBG("Timezone:", timezone);
if (modem.getNetworkTime(&ntp_year, &ntp_month, &ntp_day, &ntp_hour,
&ntp_min, &ntp_sec, &ntp_timezone)) {
DBG("Year:", ntp_year, "\tMonth:", ntp_month, "\tDay:", ntp_day);
DBG("Hour:", ntp_hour, "\tMinute:", ntp_min, "\tSecond:", ntp_sec);
DBG("Timezone:", ntp_timezone);
break;
} else {
DBG("Couldn't get network time, retrying in 15s.");
@@ -443,16 +477,18 @@ void loop() {
DBG("Current Network Time:", time);
#endif
// Test Battery functions
#if TINY_GSM_TEST_BATTERY && defined TINY_GSM_MODEM_HAS_BATTERY
uint8_t chargeState = -99;
int8_t percent = -99;
uint16_t milliVolts = -9999;
modem.getBattStats(chargeState, percent, milliVolts);
int8_t chargeState = -99;
int8_t chargePercent = -99;
int16_t milliVolts = -9999;
modem.getBattStats(chargeState, chargePercent, milliVolts);
DBG("Battery charge state:", chargeState);
DBG("Battery charge 'percent':", percent);
DBG("Battery charge 'percent':", chargePercent);
DBG("Battery voltage:", milliVolts / 1000.0F);
#endif
// Test temperature functions
#if TINY_GSM_TEST_TEMPERATURE && defined TINY_GSM_MODEM_HAS_TEMPERATURE
float temp = modem.getTemperature();
DBG("Chip temperature:", temp);

View File

@@ -22,12 +22,11 @@
* Change GPRS apm, user, pass, and Blynk auth token to run :)
**************************************************************/
/* Fill in information from Blynk Device Info here */
#define BLYNK_TEMPLATE_ID "TMPxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#define BLYNK_TEMPLATE_ID "TMPxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
// Default heartbeat interval for GSM is 60
// If you want override this value, uncomment and set this option:
@@ -43,9 +42,12 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -53,6 +55,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
@@ -84,8 +87,7 @@ const char auth[] = "YourAuthToken";
TinyGsm modem(SerialAT);
void setup()
{
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
@@ -104,12 +106,11 @@ void setup()
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
// modem.simUnlock("1234");
Blynk.begin(auth, modem, apn, user, pass);
}
void loop()
{
void loop() {
Blynk.run();
}

View File

@@ -23,9 +23,12 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -33,6 +36,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH

View File

@@ -28,9 +28,12 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -38,6 +41,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH

View File

@@ -30,6 +30,7 @@
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH

View File

@@ -32,9 +32,12 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -42,6 +45,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH

View File

@@ -18,9 +18,12 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -28,6 +31,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
@@ -117,6 +121,10 @@ TinyGsm modem(debugger);
TinyGsm modem(SerialAT);
#endif
#if defined(TINY_GSM_MODEM_HAS_SSL)
#define USE_SSL
#endif
#ifdef USE_SSL
TinyGsmClientSecure client(modem);
const int port = 443;

View File

@@ -32,11 +32,11 @@
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
TinyGsm modem(SerialAT);
#endif
void setup() {
@@ -57,23 +57,21 @@ void setup() {
const int cert_size = sizeof(cert);
modem.sendAT(GF("+FSWRITE=" CERT_FILE ",0,"), cert_size, GF(",10"));
if (modem.waitResponse(GF(">")) != 1) {
return;
}
if (modem.waitResponse(GF(">")) != 1) { return; }
for (int i = 0; i < cert_size; i++) {
char c = pgm_read_byte(&cert[i]);
modem.stream.write(c);
}
modem.stream.write(GSM_NL);
modem.stream.write(AT_NL);
modem.stream.flush();
if (modem.waitResponse(2000) != 1) return;
modem.sendAT(GF("+SSLSETCERT=\"" CERT_FILE "\""));
if (modem.waitResponse() != 1) return;
if (modem.waitResponse(5000L, GF(GSM_NL "+SSLSETCERT:")) != 1) return;
if (modem.waitResponse(5000L, GF(AT_NL "+SSLSETCERT:")) != 1) return;
const int retCode = modem.stream.readStringUntil('\n').toInt();
@@ -86,11 +84,7 @@ void setup() {
}
void loop() {
if (SerialAT.available()) {
SerialMon.write(SerialAT.read());
}
if (SerialMon.available()) {
SerialAT.write(SerialMon.read());
}
if (SerialAT.available()) { SerialMon.write(SerialAT.read()); }
if (SerialMon.available()) { SerialAT.write(SerialMon.read()); }
delay(0);
}

View File

@@ -1,8 +1,8 @@
{
"name": "TinyGSM",
"version": "0.11.7",
"version": "0.12.0",
"description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.",
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M",
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, BG95, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M",
"authors": [
{
"name": "Volodymyr Shymanskyy",

View File

@@ -1,5 +1,5 @@
name=TinyGSM
version=0.11.7
version=0.12.0
author=Volodymyr Shymanskyy
maintainer=Volodymyr Shymanskyy
sentence=A small Arduino library for GPRS modules, that just works.

View File

@@ -15,21 +15,62 @@
template <class modemType>
class TinyGsmBattery {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Battery functions
*/
uint16_t getBattVoltage() {
/**
* @brief Get the current battery voltage.
*
* @note Unless you have a battery directly connected to your modem module,
* this will be the input voltage going to the module from your main processor
* board, not the battery voltage of your main processor.
*
* @return *int16_t* The battery voltage measured by the modem module.
*/
int16_t getBattVoltage() {
return thisModem().getBattVoltageImpl();
}
/**
* @brief Get the current battery percent.
*
* @note Unless you have a battery directly connected to your modem module,
* this will be the percent from the input voltage going to the module from
* your main processor board, not the battery percent of your main processor.
*
* @return *int8_t* The current battery percent.
*/
int8_t getBattPercent() {
return thisModem().getBattPercentImpl();
}
uint8_t getBattChargeState() {
/**
* @brief Get the battery charging state.
*
* @return *int8_t* The battery charge state.
*/
int8_t getBattChargeState() {
return thisModem().getBattChargeStateImpl();
}
bool getBattStats(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
/**
* @brief Get the all battery state
*
* @param chargeState A reference to an int to set to the battery charge state
* @param percent A reference to an int to set to the battery percent
* @param milliVolts A reference to an int to set to the battery voltage
* @return *true* The battery stats were updated by the module.
* @return *false* There was a failure in updating the battery stats from the
* module.
*/
bool getBattStats(int8_t& chargeState, int8_t& percent, int16_t& milliVolts) {
return thisModem().getBattStatsImpl(chargeState, percent, milliVolts);
}
@@ -43,13 +84,20 @@ class TinyGsmBattery {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmBattery() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Battery functions
*/
protected:
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
uint16_t getBattVoltageImpl() {
int16_t getBattVoltageImpl() {
thisModem().sendAT(GF("+CBC"));
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return 0; }
thisModem().streamSkipUntil(','); // Skip battery charge status
@@ -72,7 +120,7 @@ class TinyGsmBattery {
return res;
}
uint8_t getBattChargeStateImpl() {
int8_t getBattChargeStateImpl() {
thisModem().sendAT(GF("+CBC"));
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; }
// Read battery charge status
@@ -82,8 +130,8 @@ class TinyGsmBattery {
return res;
}
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
thisModem().sendAT(GF("+CBC"));
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; }
chargeState = thisModem().streamGetIntBefore(',');

View File

@@ -15,23 +15,59 @@
template <class modemType>
class TinyGsmBluetooth {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Bluetooth functions
*/
/**
* @brief Enable module Bluetooth
*
* @return *true* Bluetooth was succcessfully enabled
* @return *false* Bluetooth failed to enable
*/
bool enableBluetooth() {
return thisModem().enableBluetoothImpl();
}
/**
* @brief Disable module Bluetooth
*
* @return *true* Bluetooth was succcessfully disabled
* @return *false* Bluetooth failed to disable
*/
bool disableBluetooth() {
return thisModem().disableBluetoothImpl();
}
/**
* @brief Set the Bluetooth visibility
*
* @param visible True to make the modem visible over Bluetooth, false to make
* it invisible.
* @return *true* Bluetooth visibility was successfully changed.
* @return *false* Bluetooth visibility failed to change
*/
bool setBluetoothVisibility(bool visible) {
return thisModem().setBluetoothVisibilityImpl(visible);
}
/**
* @brief Set the Bluetooth host name
*
* @param name The name visible to other Bluetooth objects
* @return *true* Bluetooth host name was successfully changed.
* @return *false* Bluetooth host name failed to change
*/
bool setBluetoothHostName(const char* name) {
return thisModem().setBluetoothHostNameImpl(name);
return thisModem().setBluetoothHostNameImpl(name);
}
/*
* CRTP Helper
*/
@@ -42,15 +78,22 @@ class TinyGsmBluetooth {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmBluetooth() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Bluetooth functions
*/
bool enableBluetoothImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool disableBluetoothImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setBluetoothVisibilityImpl(bool visible) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setBluetoothHostNameImpl(const char* name) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool enableBluetoothImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool disableBluetoothImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setBluetoothVisibilityImpl(bool visible) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setBluetoothHostNameImpl(const char* name) TINY_GSM_ATTR_NOT_IMPLEMENTED;
};

View File

@@ -15,19 +15,55 @@
template <class modemType>
class TinyGsmCalling {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Phone Call functions
*/
/**
* @brief Answer an incoming phone call
*
* @return *true* The call was answered.
* @return *false* The call was not answered.
*/
bool callAnswer() {
return thisModem().callAnswerImpl();
}
/**
* @brief Make a phone call
*
* @param number The number to call
* @return *true* The call was successfully made
* @return *false* The call wasn't made
*/
bool callNumber(const String& number) {
return thisModem().callNumberImpl(number);
}
/**
* @brief Hang up an in-progress phone call
*
* @return *true* The call was hung up.
* @return *false* The call was not hung up.
*/
bool callHangup() {
return thisModem().callHangupImpl();
}
/**
* @brief Sent a DTMF (dual tone multi frequency) message over a phone call.
*
* @param cmd The command to send
* @param duration_ms The tone duration
* @return *true* The message was sent
* @return *false* The message failed to send
*/
bool dtmfSend(char cmd, int duration_ms = 100) {
return thisModem().dtmfSendImpl(cmd, duration_ms);
}
@@ -42,6 +78,13 @@ class TinyGsmCalling {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmCalling() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Phone Call functions

View File

@@ -68,15 +68,23 @@ typedef TinyGsmSaraR4 TinyGsm;
typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient;
typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_SARAR5)
#include "TinyGsmClientSaraR5.h"
typedef TinyGsmSaraR5 TinyGsm;
typedef TinyGsmSaraR5::GsmClientSaraR5 TinyGsmClient;
typedef TinyGsmSaraR5::GsmClientSecureR5 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_M95)
#include "TinyGsmClientM95.h"
typedef TinyGsmM95 TinyGsm;
typedef TinyGsmM95::GsmClientM95 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_BG96)
#elif defined(TINY_GSM_MODEM_BG96) || defined(TINY_GSM_MODEM_BG95) || \
defined(TINY_GSM_MODEM_BG95SSL)
#include "TinyGsmClientBG96.h"
typedef TinyGsmBG96 TinyGsm;
typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient;
typedef TinyGsmBG96 TinyGsm;
typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient;
typedef TinyGsmBG96::GsmClientSecureBG96 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
#include "TinyGsmClientA6.h"
@@ -93,7 +101,7 @@ typedef TinyGsmM590::GsmClientM590 TinyGsmClient;
typedef TinyGsmMC60 TinyGsm;
typedef TinyGsmMC60::GsmClientMC60 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_ESP8266)
#elif defined(TINY_GSM_MODEM_ESP8266) || defined(TINY_GSM_MODEM_ESP32)
#define TINY_GSM_MODEM_HAS_WIFI
#include "TinyGsmClientESP8266.h"
typedef TinyGsmESP8266 TinyGsm;
@@ -114,6 +122,12 @@ typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient;
typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch
TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_A7672X)
#include "TinyGsmClientA7672x.h"
typedef TinyGsmA7672X TinyGsm;
typedef TinyGsmA7672X::GsmClientA7672X TinyGsmClient;
typedef TinyGsmA7672X::GsmClientSecureA7672X TinyGsmClientSecure;
#else
#error "Please define GSM modem model"
#endif

View File

@@ -14,24 +14,34 @@
#define TINY_GSM_MUX_COUNT 8
#define TINY_GSM_NO_MODEM_BUFFER
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTime.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Ai-Thinker"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_A7)
#define MODEM_MODEL "A7"
#else
#define MODEM_MODEL "A6"
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmBattery.tpp"
enum A6RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -129,7 +139,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientA6"));
@@ -155,7 +165,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -165,6 +175,15 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
}
}
// Gets the modem serial number
String getModemSerialNumberImpl() {
sendAT(GF("GSN")); // Not CGSN
String res;
if (waitResponse(1000L, res) != 1) { return ""; }
cleanResponseString(res);
return res;
}
bool factoryDefaultImpl() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
@@ -176,7 +195,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+RST=1"));
delay(3000);
@@ -198,13 +217,13 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
A6RegStatus getRegistrationStatus() {
return (A6RegStatus)getRegistrationStatusXREG("CREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
A6RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
@@ -212,18 +231,27 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
sendAT(GF("+CIFSR"));
String res;
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
cleanResponseString(res);
return res;
}
/*
* Secure socket layer (SSL) functions
*/
protected:
// No functions of this type supported
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
sendAT(GF("+CGATT=1"));
@@ -266,7 +294,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
waitResponse();
sendAT(GF("+COPS?"));
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+COPS:")) != 1) { return ""; }
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
waitResponse();
@@ -279,7 +307,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
protected:
String getSimCCIDImpl() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+SCID: SIM Card ID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -300,16 +328,16 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
if (waitResponse(5000L) != 1) { return false; }
if (waitResponse(60000L, GF(GSM_NL "+CIEV: \"CALL\",1"),
GF(GSM_NL "+CIEV: \"CALL\",0"), GFP(GSM_ERROR)) != 1) {
if (waitResponse(60000L, GF(AT_NL "+CIEV: \"CALL\",1"),
GF(AT_NL "+CIEV: \"CALL\",0"), GFP(GSM_ERROR)) != 1) {
return false;
}
int8_t rsp = waitResponse(60000L, GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
GF(GSM_NL "+CIEV: \"CALL\",0"));
int8_t rsp = waitResponse(60000L, GF(AT_NL "+CIEV: \"SOUNDER\",0"),
GF(AT_NL "+CIEV: \"CALL\",0"));
int8_t rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL),
GF(GSM_NL "NO ANSWER" GSM_NL));
int8_t rsp2 = waitResponse(300L, GF(AT_NL "BUSY" AT_NL),
GF(AT_NL "NO ANSWER" AT_NL));
return rsp == 1 && rsp2 == 0;
}
@@ -352,7 +380,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
}
/*
* Messaging functions
* Text messaging (SMS) functions
*/
protected:
String sendUSSDImpl(const String& code) {
@@ -362,7 +390,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
waitResponse();
sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
if (waitResponse(10000L) != 1) { return ""; }
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+CUSD:")) != 1) { return ""; }
streamSkipUntil('"');
String hex = stream.readStringUntil('"');
streamSkipUntil(',');
@@ -377,23 +405,42 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
}
}
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
// Note - the clock probably has to be set manaually first
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
// Needs a '?' after CBC, unlike most
int8_t getBattPercentImpl() {
sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CBC:")) != 1) { return false; }
streamSkipUntil(','); // Skip battery charge status
// Read battery charge level
int8_t res = streamGetIntBefore('\n');
@@ -403,10 +450,10 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
}
// Needs a '?' after CBC, unlike most
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CBC:")) != 1) { return false; }
chargeState = streamGetIntBefore(',');
percent = streamGetIntBefore('\n');
milliVolts = 0;
@@ -415,6 +462,11 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
return true;
}
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
*/
@@ -425,12 +477,12 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; }
if (waitResponse(timeout_ms, GF(AT_NL "+CIPNUM:")) != 1) { return false; }
int8_t newMux = streamGetIntBefore('\n');
int8_t rsp = waitResponse(
(timeout_ms - (millis() - startMillis)), GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL));
int8_t rsp = waitResponse((timeout_ms - (millis() - startMillis)),
GF("CONNECT OK" AT_NL), GF("CONNECT FAIL" AT_NL),
GF("ALREADY CONNECT" AT_NL));
if (waitResponse() != 1) { return false; }
*mux = newMux;
@@ -439,10 +491,10 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { return 0; }
if (waitResponse(2000L, GF(AT_NL ">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { return 0; }
if (waitResponse(10000L, GFP(GSM_OK), GF(AT_NL "FAIL")) != 1) { return 0; }
return len;
}
@@ -458,115 +510,37 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+CIPRCV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore(',');
int16_t len_orig = len;
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
}
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(?) Deal with missing characters
if (len_orig > sockets[mux]->available()) {
DBG("### Fewer characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
}
data = "";
} else if (data.endsWith(GF("+TCPCLOSED:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
bool handleURCs(String& data) {
if (data.endsWith(GF("+CIPRCV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore(',');
int16_t len_orig = len;
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
// reset the len to read to the amount free
len = sockets[mux]->rx.free();
}
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(?) Deal with missing characters
if (len_orig != sockets[mux]->available()) {
DBG("### Different number of characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
DBG("### Got Data: ", len_orig, "on", mux);
return true;
} else if (data.endsWith(GF("+TCPCLOSED:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -574,7 +548,6 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
protected:
GsmClientA6* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTA6_H_

775
src/TinyGsmClientA7672x.h Normal file
View File

@@ -0,0 +1,775 @@
/**
* @file TinyGsmClientA7672x.h
* @author Giovanni de Rosso Unruh
* @license LGPL-3.0
* @copyright Copyright (c) 2022 Giovanni de Rosso Unruh
* @date Oct 2022
*/
#ifndef SRC_TINYGSMCLIENTA7672X_H_
#define SRC_TINYGSMCLIENTA7672X_H_
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 10
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "SIMCom"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "A7672x"
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
#include "TinyGsmTemperature.tpp"
enum A7672xRegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_OK_HOME = 1,
REG_OK_ROAMING = 5,
REG_UNKNOWN = 4,
};
class TinyGsmA7672X : public TinyGsmModem<TinyGsmA7672X>,
public TinyGsmGPRS<TinyGsmA7672X>,
public TinyGsmTCP<TinyGsmA7672X, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmA7672X, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmA7672X>,
public TinyGsmSMS<TinyGsmA7672X>,
public TinyGsmGSMLocation<TinyGsmA7672X>,
public TinyGsmTime<TinyGsmA7672X>,
public TinyGsmNTP<TinyGsmA7672X>,
public TinyGsmBattery<TinyGsmA7672X>,
public TinyGsmTemperature<TinyGsmA7672X> {
friend class TinyGsmModem<TinyGsmA7672X>;
friend class TinyGsmGPRS<TinyGsmA7672X>;
friend class TinyGsmTCP<TinyGsmA7672X, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmA7672X, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmA7672X>;
friend class TinyGsmSMS<TinyGsmA7672X>;
friend class TinyGsmGSMLocation<TinyGsmA7672X>;
friend class TinyGsmTime<TinyGsmA7672X>;
friend class TinyGsmNTP<TinyGsmA7672X>;
friend class TinyGsmBattery<TinyGsmA7672X>;
friend class TinyGsmTemperature<TinyGsmA7672X>;
/*
* Inner Client
*/
public:
class GsmClientA7672X : public GsmClient {
friend class TinyGsmA7672X;
public:
GsmClientA7672X() {}
explicit GsmClientA7672X(TinyGsmA7672X& modem, uint8_t mux = 0) {
init(&modem, mux);
}
bool init(TinyGsmA7672X* modem, uint8_t mux = 0) {
this->at = modem;
sock_available = 0;
prev_check = 0;
sock_connected = false;
got_data = false;
if (mux < TINY_GSM_MUX_COUNT) {
this->mux = mux;
} else {
this->mux = (mux % TINY_GSM_MUX_COUNT);
}
at->sockets[this->mux] = this;
return true;
}
public:
virtual int connect(const char* host, uint16_t port, int timeout_s) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
void stop(uint32_t maxWaitMs) {
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false;
at->waitResponse();
}
void stop() override {
stop(15000L);
}
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Inner Secure Client
*/
public:
class GsmClientSecureA7672X : public GsmClientA7672X {
public:
GsmClientSecureA7672X() {}
explicit GsmClientSecureA7672X(TinyGsmA7672X& modem, uint8_t mux = 0)
: GsmClientA7672X(modem, mux) {}
public:
bool addCertificate(const char* certificateName, const char* cert,
const uint16_t len) {
return at->addCertificate(certificateName, cert, len);
}
bool setCertificate(const char* certificateName) {
return at->setCertificate(certificateName, mux);
}
bool deleteCertificate(const char* certificateName) {
return at->deleteCertificate(certificateName);
}
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
void stop(uint32_t maxWaitMs) {
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+CCHCLOSE="), mux); //, GF(",1")); // Quick close
sock_connected = false;
at->waitResponse();
}
void stop() override {
stop(15000L);
}
};
/*
* Constructor
*/
public:
explicit TinyGsmA7672X(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
protected:
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: A7672X"));
if (!testAT(2000)) { return false; }
// sendAT(GF("&FZ")); // Factory + Reset
// waitResponse();
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("V1")); // turn on verbose error codes
#else
sendAT(GF("V0")); // turn off error codes
#endif
waitResponse();
DBG(GF("### Modem:"), getModemName());
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
bool factoryDefaultImpl() {
sendAT(GF("&F")); // Factory + Reset
waitResponse();
sendAT(GF("+IFC=0,0")); // No Flow Control
waitResponse();
sendAT(GF("+ICF=2,2")); // 8 data 0 parity 1 stop
waitResponse();
sendAT(GF("+CSCLK=0")); // Control UART Sleep always work
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
/*
* Power functions
*/
protected:
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+CRESET"));
waitResponse();
if (!setPhoneFunctionality(0)) { return false; }
if (!setPhoneFunctionality(1, true)) { return false; }
delay(3000);
return init(pin);
}
bool powerOffImpl() {
sendAT(GF("+CPOF"));
return waitResponse(10000L) == 1;
}
// This command is used to enable UART Sleep or always work. If set to 0,
// UART always work. If set to 1, ensure that DTR is pulled high and the
// module can go to DTR sleep. If set to 2, the module will enter RXsleep. RX
// wakeup directly sends data through the serial port (for example: AT) to
// wake up
bool sleepEnableImpl(bool enable = true) {
sendAT(GF("+CSCLK="),
enable ? "2" : "1"); // 2: RXsleep (at wakeup) 1: DTR sleep
return waitResponse() == 1;
}
// <fun> 0 minimum functionality
// <fun> 1 full functionality, online mode
// <fun> 4 disable phone both transmit and receive RF circuits
// <fun> 5 Factory Test Mode (The A7600's 5 and 1 have the same function)
// <fun> 6 Reset
// <fun> 7 Offline Mode
// <rst> 0 do not reset the ME before setting it to <fun> power level
// <rst> 1 reset the ME before setting it to <fun> power level. This
// valueonlytakes effect when <fun> equals 1
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
sendAT(GF("+CFUN="), fun, reset ? ",1" : ",0");
return waitResponse(10000L) == 1;
}
/*
* Generic network functions
*/
public:
A7672xRegStatus getRegistrationStatus() {
return (A7672xRegStatus)getRegistrationStatusXREG("CREG");
}
String getLocalIPImpl() {
if (hasSSL) {
sendAT(GF("+CCHADDR"));
if (waitResponse(GF("+CCHADDR:")) != 1) { return ""; }
} else {
sendAT(GF("+CGPADDR=1"));
if (waitResponse(GF("+CGPADDR:")) != 1) { return ""; }
}
streamSkipUntil(','); // Skip context id
String res = stream.readStringUntil('\r');
if (waitResponse() != 1) { return ""; }
return res;
}
protected:
bool isNetworkConnectedImpl() {
A7672xRegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
/*
* Secure socket layer (SSL) functions
*/
public:
// The name of the certificate/key/password file. The file name must
// havetype like ".pem" or ".der".
// The certificate like - const char ca_cert[] PROGMEM = R"EOF(-----BEGIN...
// len of certificate like - sizeof(ca_cert)
bool addCertificate(const char* certificateName, const char* cert,
const uint16_t len) {
sendAT(GF("+CCERTDOWN="), certificateName, GF(","), len);
if (waitResponse(GF(">")) != 1) { return false; }
stream.write(cert, len);
stream.flush();
return waitResponse() == 1;
}
bool deleteCertificate(const char* certificateName) { // todo test
sendAT(GF("+CCERTDELE="), certificateName);
return waitResponse() == 1;
}
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Define the PDP context
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
waitResponse();
// Activate the PDP context
sendAT(GF("+CGACT=1,1"));
waitResponse(60000L);
// Attach to GPRS
sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1) { return false; }
// Set to get data manually
sendAT(GF("+CIPRXGET=1"));
if (waitResponse() != 1) { return false; }
// Get Local IP Address, only assigned after connection
sendAT(GF("+CGPADDR=1"));
if (waitResponse(10000L) != 1) { return false; }
// Configure Domain Name Server (DNS)
sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\""));
if (waitResponse() != 1) { return false; }
return true;
}
bool gprsDisconnectImpl() {
// Shut the TCP/IP connection
sendAT(GF("+NETCLOSE"));
if (waitResponse(60000L) != 1) { return false; }
sendAT(GF("+CGATT=0")); // Detach from GPRS
if (waitResponse(60000L) != 1) { return false; }
return true;
}
String getProviderImpl() {
sendAT(GF("+CSPN?"));
if (waitResponse(GF("+CSPN:")) != 1) { return ""; }
streamSkipUntil('"'); /* Skip mode and format */
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* SIM card functions
*/
protected:
SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) {
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF("+CPIN:")) != 1) {
delay(1000);
continue;
}
int8_t status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"),
GF("SIM not inserted"), GF("SIM REMOVED"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
String getSimCCIDImpl() {
sendAT(GF("+CICCID"));
if (waitResponse(GF(AT_NL "+ICCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
/*
* Phone Call functions
*/
public:
bool setGsmBusy(bool busy = true) {
sendAT(GF("+CCFC=1,"), busy ? 1 : 0);
return waitResponse() == 1;
}
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
// No functions of this type supported
/*
* Temperature functions
*/
protected:
float getTemperatureImpl() {
String res = "";
sendAT(GF("+CPMUTEMP"));
if (waitResponse(1000L, res)) { return 0; }
res = res.substring(res.indexOf(':'), res.indexOf('\r'));
float temp = res.toFloat();
waitResponse();
return temp;
}
/*
* Client related functions
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) {
int8_t rsp;
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
// +CTCPKA:<keepalive>,<keepidle>,<keepcount>,<keepinterval>
sendAT(GF("+CTCPKA=1,2,5,1"));
if (waitResponse(2000L) != 1) { return false; }
if (ssl) {
hasSSL = true;
// set the ssl version
// AT+CSSLCFG="sslversion",<ssl_ctx_index>,<sslversion>
// <ctxindex> PDP context identifier
// <sslversion> 0: QAPI_NET_SSL_PROTOCOL_UNKNOWN
// 1: QAPI_NET_SSL_PROTOCOL_TLS_1_0
// 2: QAPI_NET_SSL_PROTOCOL_TLS_1_1
// 3: QAPI_NET_SSL_PROTOCOL_TLS_1_2
// 4: QAPI_NET_SSL_PROTOCOL_DTLS_1_0
// 5: QAPI_NET_SSL_PROTOCOL_DTLS_1_2
// NOTE: despite docs using caps, "sslversion" must be in lower case
sendAT(GF("+CSSLCFG=\"sslversion\",0,3")); // TLS 1.2
if (waitResponse(5000L) != 1) return false;
if (certificates[mux] != "") {
/* Configure the server root CA of the specified SSL context
AT + CSSLCFG = "cacert", <ssl_ ctx_index>,<ca_file> */
sendAT(GF("+CSSLCFG=\"cacert\",0,"), certificates[mux].c_str());
if (waitResponse(5000L) != 1) return false;
}
// set the SSL SNI (server name indication)
// AT+CSSLCFG="enableSNI",<ssl_ctx_index>,<enableSNI_flag>
// NOTE: despite docs using caps, "sni" must be in lower case
sendAT(GF("+CSSLCFG=\"enableSNI\",0,1"));
if (waitResponse(2000L) != 1) { return false; }
// Configure the report mode of sending and receiving data
/* +CCHSET=<report_send_result>,<recv_mode>
* <report_send_result> Whether to report result of CCHSEND, the default
* value is 0: 0 No. 1 Yes. Module will report +CCHSEND:
* <session_id>,<err> to MCU when complete sending data.
*
* <recv_mode> The receiving mode, the default value is 0:
* 0 Output the data to MCU whenever received data.
* 1 Module caches the received data and notifies MCU with+CCHEVENT:
* <session_id>,RECV EVENT. MCU can use AT+CCHRECV to receive the cached
* data (only in manual receiving mode).
*/
sendAT(GF("+CCHSET=1,1"));
if (waitResponse(2000L) != 1) { return false; }
sendAT(GF("+CCHSTART"));
if (waitResponse(2000L) != 1) { return false; }
sendAT(GF("+CCHSSLCFG="), mux, GF(",0"));
if (waitResponse(2000L) != 1) { return false; }
sendAT(GF("+CCHOPEN="), 0, GF(",\""), host, GF("\","), port, GF(",2"));
rsp = waitResponse(timeout_ms, GF("+CCHOPEN: 0,0" AT_NL),
GF("+CCHOPEN: 0,1" AT_NL), GF("+CCHOPEN: 0,4" AT_NL),
GF("ERROR" AT_NL), GF("CLOSE OK" AT_NL));
} else {
sendAT(GF("+NETOPEN"));
if (waitResponse(2000L) != 1) { return false; }
sendAT(GF("+NETOPEN?"));
if (waitResponse(2000L) != 1) { return false; }
sendAT(GF("+CIPOPEN="), 0, ',', GF("\"TCP"), GF("\",\""), host, GF("\","),
port);
rsp = waitResponse(
timeout_ms, GF("+CIPOPEN: 0,0" AT_NL), GF("+CIPOPEN: 0,1" AT_NL),
GF("+CIPOPEN: 0,4" AT_NL), GF("ERROR" AT_NL),
GF("CLOSE OK" AT_NL)); // Happens when HTTPS handshake fails
}
return (1 == rsp);
}
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
if (hasSSL)
sendAT(GF("+CCHSEND="), mux, ',', (uint16_t)len);
else
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse() != 1) { return 0; }
if (waitResponse(10000L, GF("+CCHSEND: 0,0" AT_NL),
GF("+CCHSEND: 0,4" AT_NL), GF("+CCHSEND: 0,9" AT_NL),
GF("ERROR" AT_NL), GF("CLOSE OK" AT_NL)) != 1) {
return 0;
}
return len;
}
size_t modemRead(size_t size, uint8_t mux) {
int16_t len_requested = 0;
int16_t len_confirmed = 0;
if (!sockets[mux]) return 0;
if (hasSSL) {
sendAT(GF("+CCHRECV?")); // TODO(Rosso): Optimize this!
String res = "";
waitResponse(2000L, res);
int16_t len =
res.substring(res.indexOf(',') + 1, res.lastIndexOf(',')).toInt();
sendAT(GF("+CCHRECV="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+CCHRECV:")) != 1) { return 0; }
//+CCHRECV: DATA,0,<msg>
streamSkipUntil(','); // Skip DATA
streamSkipUntil(','); // Skip mux
len_requested = streamGetIntBefore('\n');
len_confirmed = len; // streamGetIntBefore(',');
} else {
sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX
streamSkipUntil(','); // Skip mux
len_requested = streamGetIntBefore(',');
// ^^ Requested number of data bytes (1-1460 bytes)to be read
len_confirmed = streamGetIntBefore('\n');
// ^^ Confirmed number of data bytes to be read, which may be less than
// requested. 0 indicates that no data can be read.
// SRGD NOTE: Contrary to above (which is copied from AT command manual)
// this is actually be the number of bytes that will be remaining in the
// buffer after the read.
}
for (int i = 0; i < len_requested; i++) {
uint32_t startMillis = millis();
while (!stream.available() &&
(millis() - startMillis < sockets[mux]->_timeout)) {
TINY_GSM_YIELD();
}
char c = stream.read();
sockets[mux]->rx.put(c);
}
// DBG("### READ:", len_requested, " bytes from connection ", mux);
// sockets[mux]->sock_available = modemGetAvailable(mux);
sockets[mux]->sock_available = len_confirmed;
waitResponse();
return len_requested;
}
size_t modemGetAvailable(uint8_t mux) {
if (!sockets[mux]) return 0;
size_t result = 0;
if (hasSSL) {
sendAT(GF("+CCHRECV?")); // TODO(Rosso): Optimize this!
String res = "";
waitResponse(2000L, res);
result =
res.substring(res.indexOf(',') + 1, res.lastIndexOf(',')).toInt();
} else {
sendAT(GF("+CIPRXGET=4,"), mux);
result = 0;
if (waitResponse(GF("+CIPRXGET:")) == 1) {
streamSkipUntil(','); // Skip mode 4
streamSkipUntil(','); // Skip mux
result = streamGetIntBefore('\n');
waitResponse();
}
}
// DBG("### Available:", result, "on", mux);
if (result == 0) { sockets[mux]->sock_connected = modemGetConnected(mux); }
return result;
}
bool modemGetConnected(uint8_t mux) {
int8_t res = 0;
if (hasSSL) {
bool connected = this->sockets[mux]->sock_connected;
// DBG("### Connected:", connected);
return connected;
} else {
sendAT(GF("+CIPACK="), mux);
waitResponse(GF("+CIPACK:"));
res = waitResponse(2000L); //(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
// GF(",\"CLOSING\""), GF(",\"REMOTE
// CLOSING\""), GF(",\"INITIAL\""));
waitResponse();
}
return 1 == res;
}
/*
* Utilities
*/
public:
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
DBG("### Got Data:", mux);
return true;
} else {
data += mode;
return false;
}
} else if (data.endsWith(GF("RECV EVENT" AT_NL))) {
sendAT(GF("+CCHRECV?"));
String res = "";
waitResponse(2000L, res);
int8_t mux = res.substring(res.lastIndexOf(',') + 1).toInt();
int16_t len =
res.substring(res.indexOf(',') + 1, res.lastIndexOf(',')).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+CCHRECV: 0,0" AT_NL))) {
int8_t mux = data.substring(data.lastIndexOf(',') + 1).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = true;
}
data = "";
DBG("### ACK:", mux);
return true;
} else if (data.endsWith(GF("+IPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
streamSkipUntil('\n');
DBG("### TCP Closed: ", mux);
return true;
} else if (data.endsWith(GF("+CCHCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
streamSkipUntil('\n');
DBG("### SSL Closed: ", mux);
return true;
} else if (data.endsWith(GF("+CCH_PEER_CLOSED:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### SSL Closed: ", mux);
return true;
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
return true;
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
return true;
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
return true;
} else if (data.endsWith(GF("DST:"))) {
streamSkipUntil('\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
return true;
}
return false;
}
public:
Stream& stream;
protected:
GsmClientA7672X* sockets[TINY_GSM_MUX_COUNT];
bool hasSSL = false;
String certificates[TINY_GSM_MUX_COUNT];
};
#endif // SRC_TINYGSMCLIENTA7672X_H_

View File

@@ -1,9 +1,9 @@
/**
* @file TinyGsmClientBG96.h
* @author Volodymyr Shymanskyy
* @author Volodymyr Shymanskyy and Aurelien BOUIN (SSL)
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Apr 2018
* @date Apr 2018, Aug 2023 (SSL)
*/
#ifndef SRC_TINYGSMCLIENTBG96_H_
@@ -14,27 +14,38 @@
#define TINY_GSM_MUX_COUNT 12
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Quectel"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_BG95) || defined(TINY_GSM_MODEM_BG95SSL)
#define MODEM_MODEL "BG95"
#else
#define MODEM_MODEL "BG96"
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
#include "TinyGsmTemperature.tpp"
enum BG96RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -47,21 +58,23 @@ enum RegStatus {
class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
public TinyGsmGPRS<TinyGsmBG96>,
public TinyGsmTCP<TinyGsmBG96, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmBG96, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmBG96>,
public TinyGsmSMS<TinyGsmBG96>,
public TinyGsmGPS<TinyGsmBG96>,
public TinyGsmTime<TinyGsmBG96>,
public TinyGsmNTP<TinyGsmBG96>,
public TinyGsmGPS<TinyGsmBG96>,
public TinyGsmBattery<TinyGsmBG96>,
public TinyGsmTemperature<TinyGsmBG96> {
friend class TinyGsmModem<TinyGsmBG96>;
friend class TinyGsmGPRS<TinyGsmBG96>;
friend class TinyGsmTCP<TinyGsmBG96, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmBG96, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmBG96>;
friend class TinyGsmSMS<TinyGsmBG96>;
friend class TinyGsmGPS<TinyGsmBG96>;
friend class TinyGsmTime<TinyGsmBG96>;
friend class TinyGsmNTP<TinyGsmBG96>;
friend class TinyGsmGPS<TinyGsmBG96>;
friend class TinyGsmBattery<TinyGsmBG96>;
friend class TinyGsmTemperature<TinyGsmBG96>;
@@ -76,6 +89,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
GsmClientBG96() {}
explicit GsmClientBG96(TinyGsmBG96& modem, uint8_t mux = 0) {
ssl_sock = false;
init(&modem, mux);
}
@@ -96,17 +110,16 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
return true;
}
public:
virtual int connect(const char* host, uint16_t port, int timeout_s) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
sock_connected = at->modemConnect(host, port, mux, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
void stop(uint32_t maxWaitMs) {
virtual void stop(uint32_t maxWaitMs) {
uint32_t startMillis = millis();
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+QICLOSE="), mux);
@@ -122,34 +135,39 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
protected:
bool ssl_sock;
};
/*
* Inner Secure Client
*/
public:
class GsmClientSecureBG96 : public GsmClientBG96 {
public:
GsmClientSecureBG96() {}
/*
class GsmClientSecureBG96 : public GsmClientBG96
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 0)
: public GsmClient(modem, mux)
{}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
explicit GsmClientSecureBG96(TinyGsmBG96& modem, uint8_t mux = 0)
: GsmClientBG96(modem, mux) {
ssl_sock = true;
}
bool setCertificate(const String& certificateName) {
return at->setCertificate(certificateName, mux);
}
void stop(uint32_t maxWaitMs) override {
uint32_t startMillis = millis();
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+QSSLCLOSE="), mux);
sock_connected = false;
at->waitResponse((maxWaitMs - (millis() - startMillis)));
}
void stop() override {
stop(15000L);
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
*/
/*
* Constructor
@@ -163,7 +181,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientBG96"));
@@ -191,7 +209,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -205,7 +223,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
if (!setPhoneFunctionality(1, true)) { return false; }
waitResponse(10000L, GF("APP RDY"));
@@ -228,40 +246,51 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
return waitResponse() == 1;
}
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false,
uint32_t timeout_ms = 15500L) {
sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
return waitResponse(10000L, GF("OK")) == 1;
return waitResponse(timeout_ms, GF("OK")) == 1;
}
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
BG96RegStatus getRegistrationStatus() {
// Check first for EPS registration
RegStatus epsStatus = (RegStatus)getRegistrationStatusXREG("CEREG");
BG96RegStatus epsStatus = (BG96RegStatus)getRegistrationStatusXREG("CEREG");
// If we're connected on EPS, great!
if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) {
return epsStatus;
} else {
// Otherwise, check generic network status
return (RegStatus)getRegistrationStatusXREG("CREG");
return (BG96RegStatus)getRegistrationStatusXREG("CREG");
}
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
BG96RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Configure the TCPIP Context
@@ -287,13 +316,22 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
return true;
}
String getProviderImpl() {
sendAT(GF("+QSPN?"));
if (waitResponse(GF("+QSPN:")) != 1) { return ""; }
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"'); // read the provider
waitResponse(); // skip anything else
return res;
}
/*
* SIM card functions
*/
protected:
String getSimCCIDImpl() {
sendAT(GF("+QCCID"));
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+QCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -303,14 +341,17 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
/*
* Phone Call functions
*/
protected:
// Can follow all of the phone call functions from the template
// Follows all phone call functions as inherited from TinyGsmCalling.tpp
/*
* Messaging functions
* Audio functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
@@ -341,7 +382,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
// get the RAW GPS output
String getGPSrawImpl() {
sendAT(GF("+QGPSLOC=2"));
if (waitResponse(10000L, GF(GSM_NL "+QGPSLOC:")) != 1) { return ""; }
if (waitResponse(10000L, GF(AT_NL "+QGPSLOC: ")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -354,7 +395,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) {
sendAT(GF("+QGPSLOC=2"));
if (waitResponse(10000L, GF(GSM_NL "+QGPSLOC: ")) != 1) {
if (waitResponse(10000L, GF(AT_NL "+QGPSLOC: ")) != 1) {
// NOTE: Will return an error if the position isn't fixed
return false;
}
@@ -396,20 +437,20 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
// 0, it is the type of error.
// 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;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr) *vsat = 0;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *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);
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
waitResponse(); // Final OK
return true;
@@ -437,6 +478,49 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
return res;
}
// The BG96 returns UTC time instead of local time as other modules do in
// response to CCLK, so we're using QLTS where we can specifically request
// local time.
bool getNetworkUTCTimeImpl(int* year, int* month, int* day, int* hour,
int* minute, int* second, float* timezone) {
sendAT(GF("+QLTS=1"));
if (waitResponse(2000L, GF("+QLTS: \"")) != 1) { return false; }
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
int isec = 0;
int itimezone = 0;
// Date & Time
iyear = streamGetIntBefore('/');
imonth = streamGetIntBefore('/');
iday = streamGetIntBefore(',');
ihour = streamGetIntBefore(':');
imin = streamGetIntBefore(':');
isec = streamGetIntLength(2);
char tzSign = stream.read();
itimezone = streamGetIntBefore(',');
if (tzSign == '-') { itimezone = itimezone * -1; }
streamSkipUntil('\n'); // DST flag
// Set pointers
if (iyear < 2000) iyear += 2000;
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = isec;
if (timezone != nullptr) *timezone = static_cast<float>(itimezone) / 4.0;
// Final OK
waitResponse(); // Ends with OK
return true;
}
// The BG96 returns UTC time instead of local time as other modules do in
// response to CCLK, so we're using QLTS where we can specifically request
// local time.
@@ -467,13 +551,13 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
// Set pointers
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;
if (timezone != NULL) *timezone = static_cast<float>(itimezone) / 4.0;
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = isec;
if (timezone != nullptr) *timezone = static_cast<float>(itimezone) / 4.0;
// Final OK
waitResponse(); // Ends with OK
@@ -501,11 +585,15 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
String ShowNTPErrorImpl(byte error) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// Can follow CBC as in the template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* Temperature functions
@@ -514,7 +602,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
// get temperature in degree celsius
uint16_t getTemperatureImpl() {
sendAT(GF("+QTEMP"));
if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+QTEMP:")) != 1) { return 0; }
// return temperature in C
uint16_t res =
streamGetIntBefore(','); // read PMIC (primary ic) temperature
@@ -530,39 +618,121 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 150) {
if (ssl) { DBG("SSL not yet supported on this module!"); }
int timeout_s = 150) {
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
bool ssl = sockets[mux]->ssl_sock;
// <PDPcontextID>(1-16), <connectID>(0-11),
// "TCP/UDP/TCP LISTENER/UDPSERVICE", "<IP_address>/<domain_name>",
// <remote_port>,<local_port>,<access_mode>(0-2; 0=buffer)
sendAT(GF("+QIOPEN=1,"), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
GF("\","), port, GF(",0,0"));
waitResponse();
if (ssl) {
// set the ssl version
// AT+QSSLCFG="sslversion",<ctxindex>,<sslversion>
// <ctxindex> PDP context identifier
// <sslversion> 0: QAPI_NET_SSL_3.0
// 1: QAPI_NET_SSL_PROTOCOL_TLS_1_0
// 2: QAPI_NET_SSL_PROTOCOL_TLS_1_1
// 3: QAPI_NET_SSL_PROTOCOL_TLS_1_2
// 4: ALL
// NOTE: despite docs using caps, "sslversion" must be in lower case
sendAT(GF("+QSSLCFG=\"sslversion\",0,3")); // TLS 1.2
if (waitResponse(5000L) != 1) return false;
// set the ssl cipher_suite
// AT+QSSLCFG="ciphersuite",<ctxindex>,<cipher_suite>
// <ctxindex> PDP context identifier
// <cipher_suite> 0: TODO
// 1: TODO
// 0X0035: TLS_RSA_WITH_AES_256_CBC_SHA
// 0XFFFF: ALL
// NOTE: despite docs using caps, "sslversion" must be in lower case
sendAT(GF(
"+QSSLCFG=\"ciphersuite\",0,0X0035")); // TLS_RSA_WITH_AES_256_CBC_SHA
if (waitResponse(5000L) != 1) return false;
// set the ssl sec level
// AT+QSSLCFG="seclevel",<ctxindex>,<sec_level>
// <ctxindex> PDP context identifier
// <sec_level> 0: TODO
// 1: TODO
// 0X0035: TLS_RSA_WITH_AES_256_CBC_SHA
// 0XFFFF: ALL
// NOTE: despite docs using caps, "sslversion" must be in lower case
sendAT(GF("+QSSLCFG=\"seclevel\",0,1"));
if (waitResponse(5000L) != 1) return false;
if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; }
if (streamGetIntBefore(',') != mux) { return false; }
if (certificates[mux] != "") {
// apply the correct certificate to the connection
// AT+QSSLCFG="cacert",<ctxindex>,<caname>
// <ctxindex> PDP context identifier
// <certname> certificate name
// sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"",
// certificates[mux].c_str(),
// "\"");
sendAT(GF("+QSSLCFG=\"cacert\",0,\""), certificates[mux].c_str(),
GF("\""));
if (waitResponse(5000L) != 1) return false;
}
// <PDPcontextID>(1-16), <connectID>(0-11),
// "TCP/UDP/TCP LISTENER/UDPSERVICE", "<IP_address>/<domain_name>",
// <remote_port>,<local_port>,<access_mode>(0-2; 0=buffer)
// may need previous AT+QSSLCFG
sendAT(GF("+QSSLOPEN=1,1,"), mux, GF(",\""), host, GF("\","), port,
GF(",0"));
waitResponse();
if (waitResponse(timeout_ms, GF(AT_NL "+QSSLOPEN:")) != 1) {
return false;
}
// 20230629 -> +QSSLOPEN: <clientID>,<err>
// clientID is mux
// err must be 0
if (streamGetIntBefore(',') != mux) { return false; }
// Read status
return (0 == streamGetIntBefore('\n'));
} else {
// AT+QIOPEN=1,0,"TCP","220.180.239.212",8009,0,0
// <PDPcontextID>(1-16), <connectID>(0-11),
// "TCP/UDP/TCP LISTENER/UDPSERVICE", "<IP_address>/<domain_name>",
// <remote_port>,<local_port>,<access_mode>(0-2; 0=buffer)
sendAT(GF("+QIOPEN=1,"), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
GF("\","), port, GF(",0,0"));
waitResponse();
if (waitResponse(timeout_ms, GF(AT_NL "+QIOPEN:")) != 1) { return false; }
if (streamGetIntBefore(',') != mux) { return false; }
}
// Read status
return (0 == streamGetIntBefore('\n'));
}
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
bool ssl = sockets[mux]->ssl_sock;
if (ssl) {
sendAT(GF("+QSSLSEND="), mux, ',', (uint16_t)len);
} else {
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
}
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
// TODO(?): Wait for ACK? AT+QISEND=id,0
if (waitResponse(GF(AT_NL "SEND OK")) != 1) { return 0; }
// TODO(?): Wait for ACK? (AT+QISEND=id,0 or AT+QSSLSEND=id,0)
return len;
}
size_t modemRead(size_t size, uint8_t mux) {
if (!sockets[mux]) return 0;
sendAT(GF("+QIRD="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+QIRD:")) != 1) { return 0; }
bool ssl = sockets[mux]->ssl_sock;
if (ssl) {
sendAT(GF("+QSSLRECV="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+QSSLRECV:")) != 1) {
DBG("### READ: For unknown reason close");
return 0;
}
} else {
sendAT(GF("+QIRD="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+QIRD:")) != 1) { return 0; }
}
int16_t len = streamGetIntBefore('\n');
for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); }
@@ -574,146 +744,98 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
size_t modemGetAvailable(uint8_t mux) {
if (!sockets[mux]) return 0;
sendAT(GF("+QIRD="), mux, GF(",0"));
bool ssl = sockets[mux]->ssl_sock;
size_t result = 0;
if (waitResponse(GF("+QIRD:")) == 1) {
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip have read
result = streamGetIntBefore('\n');
if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); }
waitResponse();
if (ssl) {
sendAT(GF("+QSSLRECV="), mux, GF(",0"));
if (waitResponse(GF("+QSSLRECV:")) == 1) {
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip have read
result = streamGetIntBefore('\n');
if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); }
waitResponse();
}
} else {
sendAT(GF("+QIRD="), mux, GF(",0"));
if (waitResponse(GF("+QIRD:")) == 1) {
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip have read
result = streamGetIntBefore('\n');
if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); }
waitResponse();
}
}
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
return result;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+QISTATE=1,"), mux);
// +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
bool ssl = sockets[mux]->ssl_sock;
if (ssl) {
sendAT(GF("+QSSLSTATE=1,"), mux);
// +QSSLSTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
if (waitResponse(GF("+QSSLSTATE:")) != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int8_t res = streamGetIntBefore(','); // socket state
streamSkipUntil(','); // Skip clientID
streamSkipUntil(','); // Skip "SSLClient"
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int8_t res = streamGetIntBefore(','); // socket state
waitResponse();
waitResponse();
// 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
return 2 == res;
// 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
return 2 == res;
} else {
sendAT(GF("+QISTATE=1,"), mux);
// +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int8_t res = streamGetIntBefore(','); // socket state
waitResponse();
// 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
return 2 == res;
}
}
/*
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+QIURC:"))) {
streamSkipUntil('\"');
String urc = stream.readStringUntil('\"');
streamSkipUntil(',');
if (urc == "recv") {
int8_t mux = streamGetIntBefore('\n');
DBG("### URC RECV:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
} else if (urc == "closed") {
int8_t mux = streamGetIntBefore('\n');
DBG("### URC CLOSE:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
} else {
streamSkipUntil('\n');
}
data = "";
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+QIURC:"))) {
streamSkipUntil('\"');
String urc = stream.readStringUntil('\"');
streamSkipUntil(',');
if (urc == "recv") {
int8_t mux = streamGetIntBefore('\n');
DBG("### URC RECV:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
} else if (urc == "closed") {
int8_t mux = streamGetIntBefore('\n');
DBG("### URC CLOSE:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
} else {
streamSkipUntil('\n');
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -721,7 +843,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
protected:
GsmClientBG96* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
String certificates[TINY_GSM_MUX_COUNT];
};
#endif // SRC_TINYGSMCLIENTBG96_H_

View File

@@ -14,38 +14,57 @@
#define TINY_GSM_MUX_COUNT 5
#define TINY_GSM_NO_MODEM_BUFFER
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Espressif"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_ESP8266)
#define MODEM_MODEL "ESP8266"
#else
#define MODEM_MODEL "ESP32"
#endif
#include "TinyGsmModem.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmWifi.tpp"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120;
static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120;
// <stat> status of ESP8266 station interface
// 0: ESP8266 station is not initialized.
// 1: ESP8266 station is initialized, but not started a Wi-Fi connection yet.
// 2 : ESP8266 station connected to an AP and has obtained IP
// 3 : ESP8266 station created a TCP or UDP transmission
// 4 : the TCP or UDP transmission of ESP8266 station disconnected
// 5 : ESP8266 station did NOT connect to an AP
enum RegStatus {
REG_OK_IP = 2,
REG_OK_TCP = 3,
REG_OK_NO_TCP = 4,
REG_DENIED = 5,
REG_UNKNOWN = 6,
enum ESP8266RegStatus {
REG_UNINITIALIZED = 0,
REG_UNREGISTERED = 1,
REG_OK_IP = 2,
REG_OK_TCP = 3,
REG_OK_NO_TCP = 4,
REG_DENIED = 5,
REG_UNKNOWN = 6,
};
class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
public TinyGsmWifi<TinyGsmESP8266>,
public TinyGsmTCP<TinyGsmESP8266, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmESP8266> {
public TinyGsmSSL<TinyGsmESP8266, TINY_GSM_MUX_COUNT>,
public TinyGsmWifi<TinyGsmESP8266> {
friend class TinyGsmModem<TinyGsmESP8266>;
friend class TinyGsmWifi<TinyGsmESP8266>;
friend class TinyGsmTCP<TinyGsmESP8266, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmESP8266>;
friend class TinyGsmSSL<TinyGsmESP8266, TINY_GSM_MUX_COUNT>;
friend class TinyGsmWifi<TinyGsmESP8266>;
/*
* Inner Client
@@ -137,7 +156,7 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientESP8266"));
@@ -159,11 +178,7 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
return true;
}
String getModemNameImpl() {
return "ESP8266";
}
void setBaudImpl(uint32_t baud) {
bool setBaudImpl(uint32_t baud) {
sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
if (waitResponse() != 1) {
sendAT(GF("+UART="), baud,
@@ -171,35 +186,69 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
// if (waitResponse() != 1) {
// sendAT(GF("+IPR="), baud); // First release firmwares might need
// this
waitResponse();
return waitResponse() == 1;
// }
}
}
bool factoryDefaultImpl() {
sendAT(GF("+RESTORE"));
return waitResponse() == 1;
return false;
}
String getModemInfoImpl() {
sendAT(GF("+GMR"));
String res;
if (waitResponse(1000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
cleanResponseString(res);
return res;
}
// Gets the modem hardware version
String getModemManufacturerImpl() {
return MODEM_MANUFACTURER;
}
// Gets the modem hardware version
String getModemModelImpl() {
String model = MODEM_MODEL;
sendAT(GF("+GMR"));
streamSkipUntil('\n'); // skip the AT version
streamSkipUntil('\n'); // skip the SDK version
streamSkipUntil('\n'); // skip the compile time
// read the hardware from the Bin version
streamSkipUntil('('); // skip the text "Bin version"
String wroom = stream.readStringUntil(
')'); // read the WRoom version in the parethesis
streamSkipUntil('('); // skip the bin version itself
if (waitResponse(1000L) == 1) { // wait for the ending OK
return wroom;
}
return model;
}
// Gets the modem firmware version
String getModemRevisionImpl() {
sendAT(GF("GMR")); // GMR instead of CGMR
String res;
if (waitResponse(1000L, res) != 1) { return ""; }
cleanResponseString(res);
return res;
}
// Gets the modem serial number
String getModemSerialNumberImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool factoryDefaultImpl() {
sendAT(GF("+RESTORE"));
return waitResponse() == 1;
}
/*
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+RST"));
if (waitResponse(10000L) != 1) { return false; }
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; }
if (waitResponse(10000L, GF(AT_NL "ready" AT_NL)) != 1) { return false; }
delay(500);
return init(pin);
}
@@ -220,13 +269,18 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
ESP8266RegStatus getRegistrationStatus() {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
GF("5"));
waitResponse(); // Returns an OK after the status
return (RegStatus)status;
// after "STATUS:" it should return the status number (0,1,2,3,4,5),
// followed by an OK
// Since there are more possible status number codes than the arguments for
// waitResponse, we'll capture the response in a string and then parse it.
String res;
if (waitResponse(3000L, res) != 1) { return REG_UNKNOWN; }
res.trim();
int8_t status = res.toInt();
return (ESP8266RegStatus)status;
}
protected:
@@ -252,7 +306,7 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
}
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
ESP8266RegStatus s = getRegistrationStatus();
if (s == REG_OK_IP || s == REG_OK_TCP) {
// with these, we're definitely connected
return true;
@@ -285,6 +339,12 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
return res2;
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
@@ -293,9 +353,9 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
// attempt first without than with the 'current' flag used in some firmware
// versions
sendAT(GF("+CWJAP=\""), ssid, GF("\",\""), pwd, GF("\""));
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
if (waitResponse(30000L, GFP(GSM_OK), GF(AT_NL "FAIL" AT_NL)) != 1) {
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
if (waitResponse(30000L, GFP(GSM_OK), GF(AT_NL "FAIL" AT_NL)) != 1) {
return false;
}
}
@@ -310,6 +370,62 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
return retVal;
}
/*
* GPRS functions
*/
// No functions of this type supported
/*
* SIM card functions
*/
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// No functions of this type supported
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
// No functions of this type supported
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
*/
@@ -337,18 +453,19 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
if (waitResponse(10000L, GF(AT_NL "SEND OK" AT_NL)) != 1) { return 0; }
return len;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) { return false; }
int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
GF("5"));
if (status != 3) {
// if the status is anything but 3, there are no connections open
waitResponse(); // Returns an OK after the status
// after "STATUS:" it should return the status number (0,1,2,3,4,5),
// followed by an OK
// Hopefully we'll catch the "3" here, but fall back to the OK or Error
int8_t status = waitResponse(GF("3"), GFP(GSM_OK), GFP(GSM_ERROR));
// if the status is anything but 3, there are no connections open
if (status != 1) {
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
if (sockets[muxNo]) { sockets[muxNo]->sock_connected = false; }
}
@@ -382,96 +499,41 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+IPD,"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore(':');
int16_t len_orig = len;
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "received vs",
sockets[mux]->rx.free(), "available");
} else {
// DBG("### Got Data: ", len, "on", mux);
}
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(SRGDamia1): deal with buffer overflow/missed characters
if (len_orig > sockets[mux]->available()) {
DBG("### Fewer characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
}
data = "";
} else if (data.endsWith(GF("CLOSED"))) {
int8_t muxStart =
TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
int8_t coma = data.indexOf(',', muxStart);
int8_t mux = data.substring(muxStart, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
bool handleURCs(String& data) {
if (data.endsWith(GF("+IPD,"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore(':');
int16_t len_orig = len;
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
// reset the len to read to the amount free
len = sockets[mux]->rx.free();
}
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(SRGDamia1): deal with buffer overflow/missed characters
if (len_orig != sockets[mux]->available()) {
DBG("### Different number of characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
DBG("### Got Data: ", len_orig, "on", mux);
return true;
} else if (data.endsWith(GF("CLOSED"))) {
int8_t muxStart = TinyGsmMax(0,
data.lastIndexOf(AT_NL, data.length() - 8));
int8_t coma = data.indexOf(',', muxStart);
int8_t mux = data.substring(muxStart, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
streamSkipUntil('\n'); // throw away the new line
data = "";
DBG("### Closed: ", mux);
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -479,7 +541,6 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
protected:
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTESP8266_H_

View File

@@ -14,22 +14,28 @@
#define TINY_GSM_MUX_COUNT 2
#define TINY_GSM_NO_MODEM_BUFFER
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Neoway"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "M590"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#endif
enum RegStatus {
enum M590RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 3,
@@ -106,6 +112,11 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Inner Secure Client
*/
// NOT SUPPORTED
/*
* Constructor
*/
@@ -118,7 +129,7 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientM590"));
@@ -138,7 +149,7 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -148,9 +159,50 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
}
}
// Doesn't support CGMI
// This is extracted from the modem info
String getModemNameImpl() {
return "Neoway M590";
sendAT(GF("I"));
String factory = stream.readStringUntil('\n'); // read the factory
factory.trim();
String model = stream.readStringUntil('\n'); // read the model
model.trim();
streamSkipUntil('\n'); // skip the revision
waitResponse(); // wait for the OK
return factory + String(" ") + model;
}
// This is extracted from the modem info
String getModemManufacturerImpl() {
sendAT(GF("I"));
String factory = stream.readStringUntil('\n'); // read the factory
factory.trim();
streamSkipUntil('\n'); // skip the model
streamSkipUntil('\n'); // skip the revision
if (waitResponse() == 1) { return factory; }
return MODEM_MANUFACTURER;
}
// This is extracted from the modem info
String getModemModelImpl() {
sendAT(GF("I"));
streamSkipUntil('\n'); // skip the factory
String model = stream.readStringUntil('\n'); // read the model
model.trim();
streamSkipUntil('\n'); // skip the revision
if (waitResponse() == 1) { return model; }
return MODEM_MODEL;
}
// Gets the modem firmware version
// This is extracted from the modem info
String getModemRevisionImpl() {
sendAT(GF("I"));
streamSkipUntil('\n'); // skip the factory
streamSkipUntil('\n'); // skip the model
String res = stream.readStringUntil('\n'); // read the revision
res.trim();
waitResponse(); // wait for the OK
return res;
}
// Extra stuff here - pwr save, internal stack
@@ -171,11 +223,11 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
if (!setPhoneFunctionality(15)) { return false; }
// MODEM:STARTUP
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
waitResponse(60000L, GF(AT_NL "+PBREADY" AT_NL));
return init(pin);
}
@@ -198,19 +250,19 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
M590RegStatus getRegistrationStatus() {
return (M590RegStatus)getRegistrationStatusXREG("CREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
M590RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
String getLocalIPImpl() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+XIIC:")) != 1) { return ""; }
streamSkipUntil(',');
String res = stream.readStringUntil('\n');
waitResponse();
@@ -218,12 +270,22 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// No functions of this type supported
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
sendAT(GF("+XISP=0"));
@@ -268,7 +330,7 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
bool isGprsConnectedImpl() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+XIIC:")) != 1) { return false; }
int8_t res = streamGetIntBefore(',');
waitResponse();
return res == 1;
@@ -278,20 +340,69 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
* SIM card functions
*/
protected:
// Able to follow all SIM card functions as inherited from the template
// Able to follow all SIM card functions as inherited from TinyGsmGPRS.tpp
/*
* Messaging functions
* Phone Call functions
*/
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
protected:
bool sendSMS_UTF16Impl(const String& number, const void* text,
size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
// No functions of this type supported
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
@@ -304,9 +415,8 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
String ip = dnsIpQuery(host);
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
int8_t rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL),
GF(",FAIL" GSM_NL),
GF("+TCPSETUP:Error" GSM_NL));
int8_t rsp = waitResponse(timeout_ms, GF(",OK" AT_NL), GF(",FAIL" AT_NL),
GF("+TCPSETUP:Error" AT_NL));
if (1 == rsp) {
return true;
} else if (3 == rsp) {
@@ -324,7 +434,7 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.write(static_cast<char>(0x0D));
stream.flush();
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; }
if (waitResponse(30000L, GF(AT_NL "+TCPSEND:")) != 1) { return 0; }
streamSkipUntil('\n');
return len;
}
@@ -339,9 +449,9 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
String dnsIpQuery(const char* host) {
sendAT(GF("+DNS=\""), host, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; }
if (waitResponse(10000L, GF(AT_NL "+DNS:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse(GF("+DNS:OK" GSM_NL));
waitResponse(GF("+DNS:OK" AT_NL));
res.trim();
return res;
}
@@ -350,116 +460,38 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+TCPRECV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore(',');
int16_t len_orig = len;
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
}
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(?): Handle lost characters
if (len_orig > sockets[mux]->available()) {
DBG("### Fewer characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
}
data = "";
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
streamSkipUntil('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
bool handleURCs(String& data) {
if (data.endsWith(GF("+TCPRECV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore(',');
int16_t len_orig = len;
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
// reset the len to read to the amount free
len = sockets[mux]->rx.free();
}
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(?): Handle lost characters
if (len_orig != sockets[mux]->available()) {
DBG("### Different number of characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
DBG("### Got Data: ", len_orig, "on", mux);
return true;
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
streamSkipUntil('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -467,7 +499,6 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
protected:
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTM590_H_

View File

@@ -15,25 +15,31 @@
#define TINY_GSM_MUX_COUNT 6
#define TINY_GSM_BUFFER_READ_NO_CHECK
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
enum RegStatus {
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Quectel"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "M95"
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmBattery.tpp"
#include "TinyGsmTemperature.tpp"
enum M95RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -121,29 +127,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
/*
* Inner Secure Client
*/
/*
class GsmClientSecureM95 : public GsmClientM95
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 0)
: GsmClient(modem, mux)
{}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
*/
// NOT SUPPORTED
/*
* Constructor
@@ -157,7 +141,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientM95"));
@@ -184,7 +168,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -198,7 +182,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) ==
@@ -234,13 +218,13 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
M95RegStatus getRegistrationStatus() {
return (M95RegStatus)getRegistrationStatusXREG("CREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
M95RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
@@ -261,12 +245,22 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// No functions of this type supported
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// select foreground context 0 = VIRTUAL_UART_1
@@ -340,13 +334,22 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
}
String getProviderImpl() {
sendAT(GF("+QSPN?"));
if (waitResponse(GF("+QSPN:")) != 1) { return ""; }
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"'); // read the provider
waitResponse(); // skip anything else
return res;
}
/*
* SIM card functions
*/
protected:
String getSimCCIDImpl() {
sendAT(GF("+QCCID"));
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+QCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -356,14 +359,17 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
/*
* Phone Call functions
*/
protected:
// Can follow all of the phone call functions from the template
// Follows all phone call functions as inherited from TinyGsmCalling.tpp
/*
* Messaging functions
* Audio functions
*/
protected:
// Can follow all template functions
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
public:
/** Delete all SMS */
@@ -375,16 +381,45 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
return false;
}
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
// Can follow the battery functions in the template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* Temperature functions
@@ -392,7 +427,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
protected:
float getTemperatureImpl() {
sendAT(GF("+QTEMP?"));
if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) {
if (waitResponse(GF(AT_NL "+QTEMP:")) != 1) {
return static_cast<float>(-9999);
}
streamSkipUntil(','); // Skip mode
@@ -415,9 +450,9 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
GF("\","), port);
int8_t rsp = waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL));
int8_t rsp = waitResponse(timeout_ms, GF("CONNECT OK" AT_NL),
GF("CONNECT FAIL" AT_NL),
GF("ALREADY CONNECT" AT_NL));
return (1 == rsp);
}
@@ -426,13 +461,13 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "SEND OK")) != 1) { return 0; }
// bool allAcknowledged = false;
// // bool failed = false;
// while ( !allAcknowledged ) {
// sendAT( GF("+QISACK"));
// if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
// if (waitResponse(5000L, GF(AT_NL "+QISACK:")) != 1) {
// return -1;
// } else {
// streamSkipUntil(','); // Skip total length sent on connection
@@ -515,114 +550,36 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+QIRDI:"))) {
streamSkipUntil(','); // Skip the context
streamSkipUntil(','); // Skip the role
int8_t mux = streamGetIntBefore('\n');
// DBG("### Got Data:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
// We have no way of knowing how much data actually came in, so
// we set the value to 1500, the maximum possible size.
sockets[mux]->sock_available = 1500;
}
data = "";
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
} else if (data.endsWith(GF("+QNITZ:"))) {
streamSkipUntil('\n'); // URC for time sync
data = "";
DBG("### Network time updated.");
}
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+QIRDI:"))) {
streamSkipUntil(','); // Skip the context
streamSkipUntil(','); // Skip the role
int8_t mux = streamGetIntBefore('\n');
// DBG("### Got Data:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
// We have no way of knowing how much data actually came in, so
// we set the value to 1500, the maximum possible size.
sockets[mux]->sock_available = 1500;
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
return true;
} else if (data.endsWith(GF("CLOSED" AT_NL))) {
int8_t nl = data.lastIndexOf(AT_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
} else if (data.endsWith(GF("+QNITZ:"))) {
streamSkipUntil('\n'); // URC for time sync
data = "";
DBG("### Network time updated.");
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -630,7 +587,6 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
protected:
GsmClientM95* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTM95_H_

View File

@@ -17,24 +17,34 @@
#define TINY_GSM_MUX_COUNT 6
#define TINY_GSM_BUFFER_READ_NO_CHECK
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTime.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Quectel"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_MC60E)
#define MODEM_MODEL "MC60E"
#else
#define MODEM_MODEL "MC60"
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmBattery.tpp"
enum MC60RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -120,29 +130,7 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
/*
* Inner Secure Client
*/
/*
class GsmClientSecureMC60 : public GsmClientMC60
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 0)
: GsmClient(modem, mux)
{}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
*/
// NOT SUPPORTED
/*
* Constructor
@@ -156,7 +144,7 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientMC60"));
@@ -183,7 +171,7 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -197,7 +185,7 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
if (!setPhoneFunctionality(0)) { return false; }
if (!setPhoneFunctionality(1, true)) { return false; }
@@ -229,13 +217,13 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
MC60RegStatus getRegistrationStatus() {
return (MC60RegStatus)getRegistrationStatusXREG("CREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
MC60RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
@@ -247,12 +235,22 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// No functions of this type supported
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// select foreground context 0 = VIRTUAL_UART_1
@@ -309,6 +307,15 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
}
String getProviderImpl() {
sendAT(GF("+QSPN?"));
if (waitResponse(GF("+QSPN:")) != 1) { return ""; }
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"'); // read the provider
waitResponse(); // skip anything else
return res;
}
/*
* SIM card functions
*/
@@ -316,7 +323,7 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) {
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
if (waitResponse(GF(AT_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
@@ -339,14 +346,17 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
/*
* Phone Call functions
*/
protected:
// Can follow all of the phone call functions from the template
// Follows all phone call functions as inherited from TinyGsmCalling.tpp
/*
* Messaging functions
* Audio functions
*/
protected:
// Can follow all template functions
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
public:
/** Delete all SMS */
@@ -358,16 +368,50 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
return false;
}
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
// Can follow battery functions as in the template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
@@ -388,9 +432,9 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
GF("\","), port);
int8_t rsp = waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL));
int8_t rsp = waitResponse(timeout_ms, GF("CONNECT OK" AT_NL),
GF("CONNECT FAIL" AT_NL),
GF("ALREADY CONNECT" AT_NL));
return (1 == rsp);
}
@@ -399,14 +443,14 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "SEND OK")) != 1) { return 0; }
bool allAcknowledged = false;
// bool failed = false;
while (!allAcknowledged) {
sendAT(GF("+QISACK="), mux); // If 'mux' is not specified, MC60 returns
// 'ERRROR' (for QIMUX == 1)
if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
if (waitResponse(5000L, GF(AT_NL "+QISACK:")) != 1) {
return -1;
} else {
streamSkipUntil(','); /** Skip total */
@@ -488,127 +532,43 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
String r6s(r6); r6s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (r6 && data.endsWith(r6)) {
index = 6;
goto finish;
} else if (data.endsWith(
GF(GSM_NL "+QIRDI:"))) { // TODO(?): QIRD? or QIRDI?
// +QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>
streamSkipUntil(','); // Skip the context
streamSkipUntil(','); // Skip the role
// read the connection id
int8_t mux = streamGetIntBefore(',');
// read the number of packets in the buffer
int8_t num_packets = streamGetIntBefore(',');
// read the length of the current packet
streamSkipUntil(
','); // Skip the length of the current package in the buffer
int16_t len_total =
streamGetIntBefore('\n'); // Total length of all packages
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] &&
num_packets >= 0 && len_total >= 0) {
sockets[mux]->sock_available = len_total;
}
data = "";
// DBG("### Got Data:", len_total, "on", mux);
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
} else if (data.endsWith(GF("+QNITZ:"))) {
streamSkipUntil('\n'); // URC for time sync
DBG("### Network time updated.");
data = "";
}
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+QIRDI:"))) { // TODO(?): QIRD? or QIRDI?
// +QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>
streamSkipUntil(','); // Skip the context
streamSkipUntil(','); // Skip the role
// read the connection id
int8_t mux = streamGetIntBefore(',');
// read the number of packets in the buffer
int8_t num_packets = streamGetIntBefore(',');
// read the length of the current packet
streamSkipUntil(
','); // Skip the length of the current package in the buffer
int16_t len_total =
streamGetIntBefore('\n'); // Total length of all packages
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] &&
num_packets >= 0 && len_total >= 0) {
sockets[mux]->sock_available = len_total;
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
// DBG("### Got Data:", len_total, "on", mux);
return true;
} else if (data.endsWith(GF("CLOSED" AT_NL))) {
int8_t nl = data.lastIndexOf(AT_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
} else if (data.endsWith(GF("+QNITZ:"))) {
streamSkipUntil('\n'); // URC for time sync
DBG("### Network time updated.");
data = "";
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5, r6);
return false;
}
public:
@@ -616,7 +576,6 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
protected:
GsmClientMC60* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTMC60_H_

View File

@@ -14,26 +14,41 @@
#define TINY_GSM_MUX_COUNT 10
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "SIMCom"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_SIM5320)
#define MODEM_MODEL "SIM5320";
#elif defined(TINY_GSM_MODEM_SIM5300)
#define MODEM_MODEL "SIM5300";
#elif defined(TINY_GSM_MODEM_SIM7100)
#define MODEM_MODEL "SIM7100";
#else
#define MODEM_MODEL "SIM5360";
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
#include "TinyGsmTemperature.tpp"
enum SIM5360RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -47,18 +62,20 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
public TinyGsmGPRS<TinyGsmSim5360>,
public TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmSim5360>,
public TinyGsmGSMLocation<TinyGsmSim5360>,
public TinyGsmGPS<TinyGsmSim5360>,
public TinyGsmTime<TinyGsmSim5360>,
public TinyGsmNTP<TinyGsmSim5360>,
public TinyGsmGSMLocation<TinyGsmSim5360>,
public TinyGsmBattery<TinyGsmSim5360>,
public TinyGsmTemperature<TinyGsmSim5360> {
friend class TinyGsmModem<TinyGsmSim5360>;
friend class TinyGsmGPRS<TinyGsmSim5360>;
friend class TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSMS<TinyGsmSim5360>;
friend class TinyGsmGSMLocation<TinyGsmSim5360>;
friend class TinyGsmGPS<TinyGsmSim5360>;
friend class TinyGsmTime<TinyGsmSim5360>;
friend class TinyGsmNTP<TinyGsmSim5360>;
friend class TinyGsmGSMLocation<TinyGsmSim5360>;
friend class TinyGsmBattery<TinyGsmSim5360>;
friend class TinyGsmTemperature<TinyGsmSim5360>;
@@ -123,27 +140,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
/*
* Inner Secure Client
*/
// TODO(?): Add SSL support
/*
class GsmClientSecureSim5360 : public GsmClientSim5360 {
public:
GsmClientSecureSim5360() {}
explicit GsmClientSecureSim5360(TinyGsmSim5360& modem, uint8_t mux = 0)
: GsmClientSim5360(modem, mux) {}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
*/
// NOT SUPPORTED
/*
* Constructor
@@ -157,7 +154,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM5360"));
@@ -185,7 +182,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -195,21 +192,6 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
}
}
String getModemNameImpl() {
String name = "SIMCom SIM5360";
sendAT(GF("+CGMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return name; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.replace("_", " ");
res2.trim();
name = res2;
DBG("### Modem:", name);
return name;
}
bool factoryDefaultImpl() { // these commands aren't supported
return false;
}
@@ -218,14 +200,14 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+REBOOT"));
// Should return an 'OK' after reboot command is sent
if (waitResponse(10000L) != 1) { return false; }
// After booting, modem sends out messages as each of its
// internal modules loads. The final message is "PB DONE".
if (waitResponse(40000L, GF(GSM_NL "PB DONE")) != 1) { return false; }
if (waitResponse(40000L, GF(AT_NL "PB DONE")) != 1) { return false; }
return init(pin);
}
@@ -254,20 +236,20 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CGREG");
SIM5360RegStatus getRegistrationStatus() {
return (SIM5360RegStatus)getRegistrationStatusXREG("CGREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
SIM5360RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
public:
String getNetworkModes() {
sendAT(GF("+CNMP=?"));
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+CNMP:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
return res;
@@ -275,7 +257,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
int16_t getNetworkMode() {
sendAT(GF("+CNMP?"));
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CNMP:")) != 1) { return false; }
int16_t mode = streamGetIntBefore('\n');
waitResponse();
return mode;
@@ -291,18 +273,26 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
// sendAT(GF("+CGPADDR=1")); // Show PDP address
String res;
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
cleanResponseString(res);
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// No functions of this type supported
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect(); // Make sure we're not connected first
// Define the PDP context
@@ -376,7 +366,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
// We to ignore any immediate response and wait for the
// URC to show it's really connected.
sendAT(GF("+NETOPEN"));
if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; }
if (waitResponse(75000L, GF(AT_NL "+NETOPEN: 0")) != 1) { return false; }
return true;
}
@@ -392,7 +382,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
// Note: all sockets should be closed first - on 3G/4G models the sockets
// must be closed manually
sendAT(GF("+NETCLOSE"));
if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; }
if (waitResponse(60000L, GF(AT_NL "+NETCLOSE: 0")) != 1) { return false; }
return true;
}
@@ -400,7 +390,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
bool isGprsConnectedImpl() {
sendAT(GF("+NETOPEN?"));
// May return +NETOPEN: 1, 0. We just confirm that the first number is 1
if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+NETOPEN: 1")) != 1) { return false; }
waitResponse();
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
@@ -410,6 +400,15 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
return true;
}
String getProviderImpl() {
sendAT(GF("+CSPN?"));
if (waitResponse(GF("+CSPN:")) != 1) { return ""; }
streamSkipUntil('"'); /* Skip mode and format */
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* SIM card functions
*/
@@ -417,7 +416,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
// Gets the CCID of a sim card via AT+CCID
String getSimCCIDImpl() {
sendAT(GF("+CICCID"));
if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+ICCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -425,37 +424,148 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
}
/*
* Messaging functions
* Phone Call functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
protected:
// SIM5360 and SIM7100 can return a GSM-based location from CLBS as per the
// template; SIM5320 doesn't not appear to be able to
/*
* Time functions
* GPS/GNSS/GLONASS location functions
*/
protected:
// Can follow the standard CCLK function in the template
// enable GPS
bool enableGPSImpl() {
sendAT(GF("+CGPS=1"));
if (waitResponse() != 1) { return false; }
return true;
}
bool disableGPSImpl() {
sendAT(GF("+CGPS=0"));
if (waitResponse() != 1) { return false; }
return true;
}
// get the RAW GPS output
String getGPSrawImpl() {
sendAT(GF("+CGPSINFO"));
if (waitResponse(GF(AT_NL "+CGPSINFO:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
// get GPS informations
bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
int* vsat = 0, int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) {
sendAT(GF("+CGPSINFO"));
if (waitResponse(GF(AT_NL "+CGPSINFO:")) != 1) { return false; }
delay(30);
float ilat = 0;
char north;
float ilon = 0;
char east;
float ispeed = 0;
float ialt = 0;
int ivsat = 0;
int iusat = 0;
int iyear = 0;
int imonth = 0;
int iday = 0;
int ihour = 0;
int imin = 0;
float secondWithSS = 0;
ilat = streamGetFloatBefore(','); // Latitude in ddmm.mmmmmm
north = stream.read(); // N/S Indicator, N=north or S=south
streamSkipUntil(','); // BEIDOU satellite valid numbers
ilon = streamGetFloatBefore(','); // Longitude in dddmm.mmmmmm
east = stream.read(); // E/W Indicator, E=east or W=west
streamSkipUntil(','); // BEIDOU satellite valid numbers
// Date. Output format is ddmmyy
iday = streamGetIntLength(2); // Two digit day
imonth = streamGetIntLength(2); // Two digit month
iyear = streamGetIntBefore(','); // Two digit year
// UTC Time. Output format is hhmmss.s
ihour = streamGetIntLength(2); // Two digit hour
imin = streamGetIntLength(2); // Two digit minute
secondWithSS = streamGetFloatBefore(','); // 4 digit second with subseconds
ialt = streamGetFloatBefore(','); // MSL Altitude. Unit is meters
ispeed = streamGetFloatBefore(','); // Speed Over Ground. Unit is knots.
if (ilat != -9999.0F) {
if (lat != nullptr)
*lat = (floor(ilat / 100) + fmod(ilat, 100.) / 60) *
(north == 'N' ? 1 : -1);
if (lon != nullptr)
*lon = (floor(ilon / 100) + fmod(ilon, 100.) / 60) *
(east == 'E' ? 1 : -1);
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr) *vsat = ivsat;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *accuracy = -9999;
if (iyear < 2000) iyear += 2000;
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
waitResponse();
return true;
}
waitResponse();
return false;
}
/*
* Time functions
*/
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// SRGD Note: Returns voltage in VOLTS instead of millivolts
uint16_t getBattVoltageImpl() {
int16_t getBattVoltageImpl() {
sendAT(GF("+CBC"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CBC:")) != 1) { return 0; }
streamSkipUntil(','); // Skip battery charge status
streamSkipUntil(','); // Skip battery charge level
// get voltage in VOLTS
@@ -468,10 +578,10 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
}
// SRGD Note: Returns voltage in VOLTS instead of millivolts
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
sendAT(GF("+CBC"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CBC:")) != 1) { return false; }
chargeState = streamGetIntBefore(',');
percent = streamGetIntBefore(',');
// get voltage in VOLTS
@@ -493,7 +603,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
if (waitResponse() != 1) { return 0; }
// Get Temparature Value
sendAT(GF("+CMTE?"));
if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CMTE:")) != 1) { return false; }
float res = streamGetFloatBefore('\n');
// Wait for final OK
waitResponse();
@@ -516,7 +626,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","),
port);
// The reply is +CIPOPEN: ## of socket created
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; }
if (waitResponse(timeout_ms, GF(AT_NL "+CIPOPEN:")) != 1) { return false; }
return true;
}
@@ -525,7 +635,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CIPSEND:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip requested bytes to send
// TODO(?): make sure requested and confirmed bytes match
@@ -559,7 +669,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
};
buf[0] = stream.read();
buf[1] = stream.read();
char c = strtol(buf, NULL, 16);
char c = strtol(buf, nullptr, 16);
#else
while (!stream.available() &&
(millis() - startMillis < sockets[mux]->_timeout)) {
@@ -609,125 +719,49 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
} else {
data += mode;
}
} else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
// DBG("### Got Data:", len, "on", mux);
} else if (data.endsWith(GF("+IPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
streamSkipUntil('\n'); // Skip the reason code
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
} else if (data.endsWith(GF("+CIPEVENT:"))) {
// Need to close all open sockets and release the network library.
// User will then need to reconnect.
DBG("### Network error!");
if (!isGprsConnected()) { gprsDisconnect(); }
data = "";
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
return true;
} else {
data += mode;
return false;
}
} else if (data.endsWith(GF(AT_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
// DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+IPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
streamSkipUntil('\n'); // Skip the reason code
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
} else if (data.endsWith(GF("+CIPEVENT:"))) {
// Need to close all open sockets and release the network library.
// User will then need to reconnect.
DBG("### Network error!");
if (!isGprsConnected()) { gprsDisconnect(); }
data = "";
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -735,7 +769,6 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
protected:
GsmClientSim5360* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTSIM5360_H_

View File

@@ -17,12 +17,29 @@
#include "TinyGsmClientSIM70xx.h"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
public TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT> {
public TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmSim7000>,
public TinyGsmTime<TinyGsmSim7000>,
public TinyGsmNTP<TinyGsmSim7000>,
public TinyGsmGSMLocation<TinyGsmSim7000>,
public TinyGsmBattery<TinyGsmSim7000> {
friend class TinyGsmSim70xx<TinyGsmSim7000>;
friend class TinyGsmModem<TinyGsmSim7000>;
friend class TinyGsmGPRS<TinyGsmSim7000>;
friend class TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSMS<TinyGsmSim7000>;
friend class TinyGsmGSMLocation<TinyGsmSim7000>;
friend class TinyGsmGPS<TinyGsmSim7000>;
friend class TinyGsmTime<TinyGsmSim7000>;
friend class TinyGsmNTP<TinyGsmSim7000>;
friend class TinyGsmBattery<TinyGsmSim7000>;
/*
* Inner Client
@@ -85,7 +102,7 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
/*
* Inner Secure Client
*/
// NOTE: Use modem TINYGSMSIM7000SSL for a secure client!
// NOTE: Use modem TinyGsmSim7000SSL for a secure client!
/*
* Constructor
@@ -100,7 +117,7 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7000"));
@@ -128,7 +145,7 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -141,8 +158,7 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
/*
* Power functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Generic network functions
@@ -152,18 +168,26 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
sendAT(GF("+CIFSR;E0"));
String res;
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
cleanResponseString(res);
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// NOTE: Use modem TinyGsmSim7000SSL for a secure client!
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Bearer settings for applications based on IP
@@ -249,36 +273,58 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
/*
* SIM card functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Messaging functions
* Phone Call functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
// Follows all GSM-based location functions as inherited from
// TinyGsmGSMLocation.tpp
/*
* GPS/GNSS/GLONASS location functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Time functions
*/
// Can follow CCLK as per template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// Follows all battery functions per template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
@@ -293,10 +339,9 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host,
GF("\","), port);
return (1 ==
waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL), GF("ERROR" GSM_NL),
GF("CLOSE OK" GSM_NL)));
waitResponse(timeout_ms, GF("CONNECT OK" AT_NL),
GF("CONNECT FAIL" AT_NL), GF("ALREADY CONNECT" AT_NL),
GF("ERROR" AT_NL), GF("CLOSE OK" AT_NL)));
}
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
@@ -306,7 +351,9 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "DATA ACCEPT:"), GF("SEND FAIL")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip mux
return streamGetIntBefore('\n');
}
@@ -343,7 +390,7 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
};
buf[0] = stream.read();
buf[1] = stream.read();
char c = strtol(buf, NULL, 16);
char c = strtol(buf, nullptr, 16);
#else
while (!stream.available() &&
(millis() - startMillis < sockets[mux]->_timeout)) {
@@ -390,141 +437,68 @@ class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
} else {
data += mode;
}
} else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
// DBG("### Got Data:", len, "on", mux);
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
} else if (data.endsWith(GF("DST: "))) {
streamSkipUntil(
'\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
} else if (data.endsWith(GF(GSM_NL "SMS Ready" GSM_NL))) {
data = "";
DBG("### Unexpected module reset!");
init();
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
return true;
} else {
data += mode;
return false;
}
} else if (data.endsWith(GF(AT_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
// DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("CLOSED" AT_NL))) {
int8_t nl = data.lastIndexOf(AT_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
return true;
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
return true;
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
return true;
} else if (data.endsWith(GF("DST: "))) {
streamSkipUntil('\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
return true;
} else if (data.endsWith(GF(AT_NL "SMS Ready" AT_NL))) {
data = "";
DBG("### Unexpected module reset!");
init();
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
protected:

View File

@@ -18,14 +18,32 @@
#include "TinyGsmClientSIM70xx.h"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
class TinyGsmSim7000SSL
: public TinyGsmSim70xx<TinyGsmSim7000SSL>,
public TinyGsmTCP<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSim7000SSL> {
public TinyGsmSSL<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmSim7000SSL>,
public TinyGsmGSMLocation<TinyGsmSim7000SSL>,
public TinyGsmTime<TinyGsmSim7000SSL>,
public TinyGsmNTP<TinyGsmSim7000SSL>,
public TinyGsmBattery<TinyGsmSim7000SSL> {
friend class TinyGsmSim70xx<TinyGsmSim7000SSL>;
friend class TinyGsmTCP<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSim7000SSL>;
friend class TinyGsmSSL<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>;
friend class TinyGsmModem<TinyGsmSim7000SSL>;
friend class TinyGsmGPRS<TinyGsmSim7000SSL>;
friend class TinyGsmSMS<TinyGsmSim7000SSL>;
friend class TinyGsmGSMLocation<TinyGsmSim7000SSL>;
friend class TinyGsmGPS<TinyGsmSim7000SSL>;
friend class TinyGsmNTP<TinyGsmSim7000SSL>;
friend class TinyGsmTime<TinyGsmSim7000SSL>;
friend class TinyGsmBattery<TinyGsmSim7000SSL>;
/*
* Inner Client
@@ -88,7 +106,7 @@ class TinyGsmSim7000SSL
/*
* Inner Secure Client
*/
public:
class GsmClientSecureSIM7000SSL : public GsmClientSim7000SSL {
public:
GsmClientSecureSIM7000SSL() {}
@@ -97,7 +115,6 @@ class TinyGsmSim7000SSL
uint8_t mux = 0)
: GsmClientSim7000SSL(modem, mux) {}
public:
bool setCertificate(const String& certificateName) {
return at->setCertificate(certificateName, mux);
}
@@ -118,8 +135,7 @@ class TinyGsmSim7000SSL
*/
public:
explicit TinyGsmSim7000SSL(Stream& stream)
: TinyGsmSim70xx<TinyGsmSim7000SSL>(stream),
certificates() {
: TinyGsmSim70xx<TinyGsmSim7000SSL>(stream) {
memset(sockets, 0, sizeof(sockets));
}
@@ -127,7 +143,7 @@ class TinyGsmSim7000SSL
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7000SSL"));
@@ -155,7 +171,7 @@ class TinyGsmSim7000SSL
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -179,14 +195,13 @@ class TinyGsmSim7000SSL
// modemGetAvailable checks all socks, so we only want to do it once
// modemGetAvailable calls modemGetConnected(), which also checks allf
if (check_socks) { modemGetAvailable(0); }
while (stream.available()) { waitResponse(15, NULL, NULL); }
while (stream.available()) { waitResponse(15, nullptr, nullptr); }
}
/*
* Power functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Generic network functions
@@ -194,7 +209,7 @@ class TinyGsmSim7000SSL
protected:
String getLocalIPImpl() {
sendAT(GF("+CNACT?"));
if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+CNACT:")) != 1) { return ""; }
streamSkipUntil('\"');
String res = stream.readStringUntil('\"');
waitResponse();
@@ -202,21 +217,21 @@ class TinyGsmSim7000SSL
}
/*
* Secure socket layer functions
* Secure socket layer (SSL) functions
*/
protected:
bool setCertificate(const String& certificateName, const uint8_t mux = 0) {
if (mux >= TINY_GSM_MUX_COUNT) return false;
certificates[mux] = certificateName;
return true;
}
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Define the PDP context
@@ -242,7 +257,7 @@ class TinyGsmSim7000SSL
// 2: CHAP
// 3: PAP or CHAP
if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) {
sendAT(GF("+CNCFG=1,\""), apn, "\",\"", "\",\"", user, pwd, '"');
sendAT(GF("+CNCFG=1,\""), apn, "\",\"", "\",\"", user, pwd, "\",3");
waitResponse();
} else if (user && strlen(user) > 0) {
// Set the user name only
@@ -265,8 +280,8 @@ class TinyGsmSim7000SSL
int ntries = 0;
while (!res && ntries < 5) {
sendAT(GF("+CNACT=1,\""), apn, GF("\""));
res = waitResponse(60000L, GF(GSM_NL "+APP PDP: ACTIVE"),
GF(GSM_NL "+APP PDP: DEACTIVE")) == 1;
res = waitResponse(60000L, GF(AT_NL "+APP PDP: ACTIVE"),
GF(AT_NL "+APP PDP: DEACTIVE")) == 1;
waitResponse();
ntries++;
}
@@ -289,36 +304,57 @@ class TinyGsmSim7000SSL
/*
* SIM card functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Messaging functions
* Phone Call functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
// Follows all GSM-based location functions as inherited from
// TinyGsmGSMLocation.tpp
/*
* GPS/GNSS/GLONASS location functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Time functions
*/
// Can follow CCLK as per template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// Follows all battery functions per template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
@@ -336,7 +372,9 @@ class TinyGsmSim7000SSL
if (ssl) {
// set the ssl version
// AT+CSSLCFG="SSLVERSION",<ctxindex>,<sslversion>
// <ctxindex> PDP context identifier
// <ctxindex> PDP context identifier - for reasons not understood by me,
// use PDP context identifier of 0 for what we defined as 1 in
// the gprsConnect function
// <sslversion> 0: QAPI_NET_SSL_PROTOCOL_UNKNOWN
// 1: QAPI_NET_SSL_PROTOCOL_TLS_1_0
// 2: QAPI_NET_SSL_PROTOCOL_TLS_1_1
@@ -359,8 +397,11 @@ class TinyGsmSim7000SSL
if (ssl) {
// set the PDP context to apply SSL to
// AT+CSSLCFG="CTXINDEX",<ctxindex>
// <ctxindex> PDP context identifier
// NOTE: despite docs using caps, "ctxindex" must be in lower case
// <ctxindex> PDP context identifier - for reasons not understood by me,
// use PDP context identifier of 0 for what we defined as 1 in
// the gprsConnect function
// NOTE: despite docs using "CRINDEX" in all caps, the module only
// accepts the command "ctxindex" and it must be in lower case
sendAT(GF("+CSSLCFG=\"ctxindex\",0"));
if (waitResponse(5000L, GF("+CSSLCFG:")) != 1) return false;
streamSkipUntil('\n'); // read out the certificate information
@@ -382,8 +423,12 @@ class TinyGsmSim7000SSL
waitResponse();
// set the SSL SNI (server name indication)
// AT+CSSLCFG="SNI",<ctxindex>,<servername>
// <ctxindex> PDP context identifier - for reasons not understood by me,
// use PDP context identifier of 0 for what we defined as 1 in
// the gprsConnect function
// NOTE: despite docs using caps, "sni" must be in lower case
sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\""));
sendAT(GF("+CSSLCFG=\"sni\",0,"), GF("\""), host, GF("\""));
waitResponse();
}
@@ -393,7 +438,7 @@ class TinyGsmSim7000SSL
// <conn_type> "TCP" or "UDP"
// NOTE: the "TCP" can't be included
sendAT(GF("+CAOPEN="), mux, GF(",\""), host, GF("\","), port);
if (waitResponse(timeout_ms, GF(GSM_NL "+CAOPEN:")) != 1) { return 0; }
if (waitResponse(timeout_ms, GF(AT_NL "+CAOPEN:")) != 1) { return 0; }
// returns OK/r/n/r/n+CAOPEN: <cid>,<result>
// <result> 0: Success
// 1: Socket error
@@ -430,7 +475,7 @@ class TinyGsmSim7000SSL
// after posting data, module responds with:
//+CASEND: <cid>,<result>,<sendlen>
if (waitResponse(GF(GSM_NL "+CASEND:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CASEND:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
if (streamGetIntBefore(',') != 0) { return 0; } // If result != success
return streamGetIntBefore('\n');
@@ -588,143 +633,67 @@ class TinyGsmSim7000SSL
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+CARECV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
DBG("### Got Data:", len, "on", mux);
} else if (data.endsWith(GF("+CADATAIND:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
DBG("### Got Data:", mux);
} else if (data.endsWith(GF("+CASTATE:"))) {
int8_t mux = streamGetIntBefore(',');
int8_t state = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (state != 1) {
sockets[mux]->sock_connected = false;
DBG("### Closed: ", mux);
}
}
data = "";
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
} else if (data.endsWith(GF("DST: "))) {
streamSkipUntil(
'\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
} else if (data.endsWith(GF(GSM_NL "SMS Ready" GSM_NL))) {
data = "";
DBG("### Unexpected module reset!");
init();
data = "";
bool handleURCs(String& data) {
if (data.endsWith(GF("+CARECV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+CADATAIND:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
DBG("### Got Data:", mux);
return true;
} else if (data.endsWith(GF("+CASTATE:"))) {
int8_t mux = streamGetIntBefore(',');
int8_t state = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (state != 1) {
sockets[mux]->sock_connected = false;
DBG("### Closed: ", mux);
}
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
return true;
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
return true;
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
return true;
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
return true;
} else if (data.endsWith(GF("DST: "))) {
streamSkipUntil('\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
return true;
} else if (data.endsWith(GF(AT_NL "SMS Ready" AT_NL))) {
data = "";
DBG("### Unexpected module reset!");
init();
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
protected:
GsmClientSim7000SSL* sockets[TINY_GSM_MUX_COUNT];
String certificates[TINY_GSM_MUX_COUNT];
};
#endif // SRC_TINYGSMCLIENTSIM7000SSL_H_

View File

@@ -18,13 +18,31 @@
#include "TinyGsmClientSIM70xx.h"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
public TinyGsmTCP<TinyGsmSim7080, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSim7080> {
public TinyGsmSSL<TinyGsmSim7080, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmSim7080>,
public TinyGsmGSMLocation<TinyGsmSim7080>,
public TinyGsmTime<TinyGsmSim7080>,
public TinyGsmNTP<TinyGsmSim7080>,
public TinyGsmBattery<TinyGsmSim7080> {
friend class TinyGsmSim70xx<TinyGsmSim7080>;
friend class TinyGsmModem<TinyGsmSim7080>;
friend class TinyGsmGPRS<TinyGsmSim7080>;
friend class TinyGsmTCP<TinyGsmSim7080, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSim7080>;
friend class TinyGsmSSL<TinyGsmSim7080, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSMS<TinyGsmSim7080>;
friend class TinyGsmGSMLocation<TinyGsmSim7080>;
friend class TinyGsmGPS<TinyGsmSim7080>;
friend class TinyGsmTime<TinyGsmSim7080>;
friend class TinyGsmNTP<TinyGsmSim7080>;
friend class TinyGsmBattery<TinyGsmSim7080>;
/*
* Inner Client
@@ -87,7 +105,7 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
/*
* Inner Secure Client
*/
public:
class GsmClientSecureSIM7080 : public GsmClientSim7080 {
public:
GsmClientSecureSIM7080() {}
@@ -95,13 +113,11 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
explicit GsmClientSecureSIM7080(TinyGsmSim7080& modem, uint8_t mux = 0)
: GsmClientSim7080(modem, mux) {}
public:
bool setCertificate(const String& certificateName) {
return at->setCertificate(certificateName, mux);
}
virtual int connect(const char* host, uint16_t port,
int timeout_s) override {
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
@@ -116,8 +132,7 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
*/
public:
explicit TinyGsmSim7080(Stream& stream)
: TinyGsmSim70xx<TinyGsmSim7080>(stream),
certificates() {
: TinyGsmSim70xx<TinyGsmSim7080>(stream) {
memset(sockets, 0, sizeof(sockets));
}
@@ -125,14 +140,26 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7080"));
if (!testAT()) { return false; }
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
bool gotATOK = false;
for (uint32_t start = millis(); millis() - start < 10000L;) {
sendAT(GF(""));
int8_t resp = waitResponse(200L, GFP(GSM_OK), GFP(GSM_ERROR), GF("AT"));
if (resp == 1) {
gotATOK = true;
break;
} else if (resp == 3) {
waitResponse(200L); // get the OK
sendAT(GF("E0")); // Echo Off
DBG(GF("## Turning off echo!"));
waitResponse(2000L);
}
delay(100);
}
if (!gotATOK) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
@@ -153,7 +180,7 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -177,14 +204,39 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
// modemGetAvailable checks all socks, so we only want to do it once
// modemGetAvailable calls modemGetConnected(), which also checks allf
if (check_socks) { modemGetAvailable(0); }
while (stream.available()) { waitResponse(15, NULL, NULL); }
while (stream.available()) { waitResponse(15, nullptr, nullptr); }
}
/*
* Power functions
*/
protected:
// Follows the SIM70xx template
bool restartImpl(const char* pin = nullptr) {
bool success = true;
bool gotATOK = false;
for (uint32_t start = millis(); millis() - start < 10000L;) {
sendAT(GF(""));
int8_t resp = waitResponse(200L, GFP(GSM_OK), GFP(GSM_ERROR), GF("AT"));
if (resp == 1) {
gotATOK = true;
break;
} else if (resp == 3) {
waitResponse(200L); // get the OK
DBG(GF("## Turning off echo!"));
sendAT(GF("E0")); // Echo Off
waitResponse(2000L);
}
delay(100);
}
if (!gotATOK) { return false; }
sendAT(GF("+CREBOOT")); // Reboot
success &= waitResponse() == 1;
waitResponse(30000L, GF("SMS Ready"));
success &= initImpl(pin);
return success;
}
/*
* Generic network functions
@@ -192,7 +244,7 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
protected:
String getLocalIPImpl() {
sendAT(GF("+CNACT?"));
if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+CNACT:")) != 1) { return ""; }
streamSkipUntil('\"');
String res = stream.readStringUntil('\"');
waitResponse();
@@ -200,21 +252,21 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
}
/*
* Secure socket layer functions
* Secure socket layer (SSL) functions
*/
protected:
bool setCertificate(const String& certificateName, const uint8_t mux = 0) {
if (mux >= TINY_GSM_MUX_COUNT) return false;
certificates[mux] = certificateName;
return true;
}
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Define the PDP context
@@ -247,7 +299,7 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
// 2: CHAP
// 3: PAP or CHAP
if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) {
sendAT(GF("+CNCFG=0,1,\""), apn, "\",\"", user, "\",\"", pwd, '"');
sendAT(GF("+CNCFG=0,1,\""), apn, "\",\"", user, "\",\"", pwd, "\",3");
waitResponse();
} else if (user && strlen(user) > 0) {
// Set the user name only
@@ -270,8 +322,8 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
int ntries = 0;
while (!res && ntries < 5) {
sendAT(GF("+CNACT=0,1"));
res = waitResponse(60000L, GF(GSM_NL "+APP PDP: 0,ACTIVE"),
GF(GSM_NL "+APP PDP: 0,DEACTIVE"));
res = waitResponse(60000L, GF(AT_NL "+APP PDP: 0,ACTIVE"),
GF(AT_NL "+APP PDP: 0,DEACTIVE"));
waitResponse();
ntries++;
}
@@ -294,36 +346,96 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
/*
* SIM card functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Messaging functions
* Phone Call functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
// Follows all GSM-based location functions as inherited from
// TinyGsmGSMLocation.tpp
/*
* GPS/GNSS/GLONASS location functions
*/
protected:
// Follows the SIM70xx template
// Follows functions as inherited from TinyGsmClientSIM70xx.h
/*
* Time functions
*/
// Can follow CCLK as per template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
protected:
byte NTPServerSyncImpl(String server = "pool.ntp.org", int TimeZone = 0) {
// Set GPRS bearer profile to associate with NTP sync
// this may fail, it's not supported by all modules
sendAT(GF("+CNTPCID=0")); // CID must be 0. With 1 (like other modules)
// does not work!
waitResponse(10000L);
// Set NTP server and timezone
sendAT(GF("+CNTP=\""), server, "\",", String(TimeZone));
if (waitResponse(10000L) != 1) { return -1; }
// Request network synchronization
sendAT(GF("+CNTP"));
if (waitResponse(10000L, GF("+CNTP:"))) {
String result = stream.readStringUntil('\n');
// Check for ',' in case the module appends the time next to the return
// code. Eg: +CNTP: <code>[,<time>]
int index = result.indexOf(',');
if (index > 0) { result.remove(index); }
result.trim();
if (TinyGsmIsValidNumber(result)) { return result.toInt(); }
} else {
return -1;
}
return -1;
}
String ShowNTPErrorImpl(byte error) {
switch (error) {
case 1: return "Network time synchronization is successful";
case 61: return "Network error";
case 62: return "DNS resolution error";
case 63: return "Connection error";
case 64: return "Service response error";
case 65: return "Service response timeout";
default: return "Unknown error: " + String(error);
}
}
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// Follows all battery functions per template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* Temperature functions
*/
// No functions of this type supported
/*
* Client related functions
@@ -341,7 +453,9 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
if (ssl) {
// set the ssl version
// AT+CSSLCFG="SSLVERSION",<ctxindex>,<sslversion>
// <ctxindex> PDP context identifier
// <ctxindex> PDP context identifier - for reasons not understood by me,
// use PDP context identifier of 0 for what we defined as 1 in
// the gprsConnect function
// <sslversion> 0: QAPI_NET_SSL_PROTOCOL_UNKNOWN
// 1: QAPI_NET_SSL_PROTOCOL_TLS_1_0
// 2: QAPI_NET_SSL_PROTOCOL_TLS_1_1
@@ -364,7 +478,9 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
if (ssl) {
// set the PDP context to apply SSL to
// AT+CSSLCFG="CTXINDEX",<ctxindex>
// <ctxindex> PDP context identifier
// <ctxindex> PDP context identifier - for reasons not understood by me,
// use PDP context identifier of 0 for what we defined as 1 in
// the gprsConnect function
// NOTE: despite docs using "CRINDEX" in all caps, the module only
// accepts the command "ctxindex" and it must be in lower case
sendAT(GF("+CSSLCFG=\"ctxindex\",0"));
@@ -383,8 +499,12 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
}
// set the SSL SNI (server name indication)
// AT+CSSLCFG="SNI",<ctxindex>,<servername>
// <ctxindex> PDP context identifier - for reasons not understood by me,
// use PDP context identifier of 0 for what we defined as 1 in
// the gprsConnect function
// NOTE: despite docs using caps, "sni" must be in lower case
sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\""));
sendAT(GF("+CSSLCFG=\"sni\",0,"), GF("\""), host, GF("\""));
waitResponse();
}
@@ -401,7 +521,7 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
// "recv",<id>,<length>,<remoteIP>,<remote_port><CR><LF><data>
// NOTE: including the <recv_mode> fails
sendAT(GF("+CAOPEN="), mux, GF(",0,\"TCP\",\""), host, GF("\","), port);
if (waitResponse(timeout_ms, GF(GSM_NL "+CAOPEN:")) != 1) { return 0; }
if (waitResponse(timeout_ms, GF(AT_NL "+CAOPEN:")) != 1) { return 0; }
// returns OK/r/n/r/n+CAOPEN: <cid>,<result>
// <result> 0: Success
// 1: Socket error
@@ -587,138 +707,64 @@ class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+CARECV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
DBG("### Got Data:", len, "on", mux);
} else if (data.endsWith(GF("+CADATAIND:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
DBG("### Got Data:", mux);
} else if (data.endsWith(GF("+CASTATE:"))) {
int8_t mux = streamGetIntBefore(',');
int8_t state = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (state != 1) {
sockets[mux]->sock_connected = false;
DBG("### Closed: ", mux);
}
}
data = "";
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
} else if (data.endsWith(GF("DST: "))) {
streamSkipUntil(
'\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
} else if (data.endsWith(GF(GSM_NL "SMS Ready" GSM_NL))) {
data = "";
DBG("### Unexpected module reset!");
init();
data = "";
bool handleURCs(String& data) {
if (data.endsWith(GF("+CARECV:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+CADATAIND:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
DBG("### Got Data:", mux);
return true;
} else if (data.endsWith(GF("+CASTATE:"))) {
int8_t mux = streamGetIntBefore(',');
int8_t state = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
if (state != 1) {
sockets[mux]->sock_connected = false;
DBG("### Closed: ", mux);
}
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
return true;
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
return true;
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
return true;
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
return true;
} else if (data.endsWith(GF("DST: "))) {
streamSkipUntil('\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
return true;
} else if (data.endsWith(GF(AT_NL "SMS Ready" AT_NL))) {
data = "";
DBG("### Unexpected module reset!");
init();
data = "";
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
protected:

View File

@@ -11,25 +11,36 @@
// #define TINY_GSM_DEBUG Serial
// #define TINY_GSM_USE_HEX
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmGSMLocation.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "SIMCom"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_SIM7070)
#define MODEM_MODEL "SIM7070";
#elif defined(TINY_GSM_MODEM_SIM7080)
#define MODEM_MODEL "SIM7080";
#elif defined(TINY_GSM_MODEM_SIM7090)
#define MODEM_MODEL "SIM7090";
#elif defined(TINY_GSM_MODEM_SIM7000) || defined(TINY_GSM_MODEM_SIM7000SSL)
#define MODEM_MODEL "SIM7000";
#else
#define MODEM_MODEL "SIM70xx";
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGPS.tpp"
enum SIM70xxRegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -39,34 +50,25 @@ enum RegStatus {
REG_UNKNOWN = 4,
};
template <class modemType>
class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
public TinyGsmGPRS<TinyGsmSim70xx<modemType>>,
public TinyGsmSMS<TinyGsmSim70xx<modemType>>,
public TinyGsmGPS<TinyGsmSim70xx<modemType>>,
public TinyGsmTime<TinyGsmSim70xx<modemType>>,
public TinyGsmNTP<TinyGsmSim70xx<modemType>>,
public TinyGsmBattery<TinyGsmSim70xx<modemType>>,
public TinyGsmGSMLocation<TinyGsmSim70xx<modemType>> {
friend class TinyGsmModem<TinyGsmSim70xx<modemType>>;
friend class TinyGsmGPRS<TinyGsmSim70xx<modemType>>;
friend class TinyGsmSMS<TinyGsmSim70xx<modemType>>;
friend class TinyGsmGPS<TinyGsmSim70xx<modemType>>;
friend class TinyGsmTime<TinyGsmSim70xx<modemType>>;
friend class TinyGsmNTP<TinyGsmSim70xx<modemType>>;
friend class TinyGsmBattery<TinyGsmSim70xx<modemType>>;
friend class TinyGsmGSMLocation<TinyGsmSim70xx<modemType>>;
template <class SIM70xxType>
class TinyGsmSim70xx : public TinyGsmModem<SIM70xxType>,
public TinyGsmGPRS<SIM70xxType>,
public TinyGsmGPS<SIM70xxType> {
friend class TinyGsmModem<SIM70xxType>;
friend class TinyGsmGPRS<SIM70xxType>;
friend class TinyGsmGPS<SIM70xxType>;
/*
* CRTP Helper
*/
protected:
inline const modemType& thisModem() const {
return static_cast<const modemType&>(*this);
inline const SIM70xxType& thisModem() const {
return static_cast<const SIM70xxType&>(*this);
}
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
inline SIM70xxType& thisModem() {
return static_cast<SIM70xxType&>(*this);
}
~TinyGsmSim70xx() {}
/*
* Constructor
@@ -78,44 +80,15 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
return thisModem().initImpl(pin);
}
String getModemNameImpl() {
String name = "SIMCom SIM7000";
thisModem().sendAT(GF("+GMM"));
String res2;
if (thisModem().waitResponse(5000L, res2) != 1) { return name; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.replace("_", " ");
res2.trim();
name = res2;
return name;
}
bool factoryDefaultImpl() { // these commands aren't supported
thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
thisModem().waitResponse();
thisModem().sendAT(GF("+IPR=0")); // Auto-baud
thisModem().waitResponse();
thisModem().sendAT(GF("+IFC=0,0")); // No Flow Control
thisModem().waitResponse();
thisModem().sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
thisModem().waitResponse();
thisModem().sendAT(GF("+CSCLK=0")); // Disable Slow Clock
thisModem().waitResponse();
thisModem().sendAT(GF("&W")); // Write configuration
return thisModem().waitResponse() == 1;
bool factoryDefaultImpl() {
return false;
}
/*
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
thisModem().sendAT(GF("E0")); // Echo Off
thisModem().waitResponse();
if (!thisModem().setPhoneFunctionality(0)) { return false; }
@@ -147,22 +120,22 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
RegStatus epsStatus =
(RegStatus)thisModem().getRegistrationStatusXREG("CEREG");
SIM70xxRegStatus getRegistrationStatus() {
SIM70xxRegStatus epsStatus =
(SIM70xxRegStatus)thisModem().getRegistrationStatusXREG("CEREG");
// If we're connected on EPS, great!
if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) {
return epsStatus;
} else {
// Otherwise, check GPRS network status
// We could be using GPRS fall-back or the board could be being moody
return (RegStatus)thisModem().getRegistrationStatusXREG("CGREG");
return (SIM70xxRegStatus)thisModem().getRegistrationStatusXREG("CGREG");
}
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
SIM70xxRegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
@@ -170,7 +143,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
String getNetworkModes() {
// Get the help string, not the setting value
thisModem().sendAT(GF("+CNMP=?"));
if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
if (thisModem().waitResponse(GF(AT_NL "+CNMP:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
thisModem().waitResponse();
return res;
@@ -178,7 +151,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
int16_t getNetworkMode() {
thisModem().sendAT(GF("+CNMP?"));
if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
if (thisModem().waitResponse(GF(AT_NL "+CNMP:")) != 1) { return false; }
int16_t mode = thisModem().streamGetIntBefore('\n');
thisModem().waitResponse();
return mode;
@@ -196,7 +169,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
String getPreferredModes() {
// Get the help string, not the setting value
thisModem().sendAT(GF("+CMNB=?"));
if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; }
if (thisModem().waitResponse(GF(AT_NL "+CMNB:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
thisModem().waitResponse();
return res;
@@ -204,7 +177,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
int16_t getPreferredMode() {
thisModem().sendAT(GF("+CMNB?"));
if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return false; }
if (thisModem().waitResponse(GF(AT_NL "+CMNB:")) != 1) { return false; }
int16_t mode = thisModem().streamGetIntBefore('\n');
thisModem().waitResponse();
return mode;
@@ -222,7 +195,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
// n: whether to automatically report the system mode info
// stat: the current service. 0 if it not connected
thisModem().sendAT(GF("+CNSMOD?"));
if (thisModem().waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { return false; }
if (thisModem().waitResponse(GF(AT_NL "+CNSMOD:")) != 1) { return false; }
n = thisModem().streamGetIntBefore(',') != 0;
stat = thisModem().streamGetIntBefore('\n');
thisModem().waitResponse();
@@ -235,23 +208,11 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
return thisModem().waitResponse() == 1;
}
String getLocalIPImpl() {
return thisModem().getLocalIPImpl();
}
/*
* GPRS functions
*/
protected:
// should implement in sub-classes
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
return thisModem().gprsConnectImpl(apn, user, pwd);
}
bool gprsDisconnectImpl() {
return thisModem().gprsDisconnectImpl();
}
/*
* SIM card functions
@@ -260,19 +221,13 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
// Doesn't return the "+CCID" before the number
String getSimCCIDImpl() {
thisModem().sendAT(GF("+CCID"));
if (thisModem().waitResponse(GF(GSM_NL)) != 1) { return ""; }
if (thisModem().waitResponse(GF(AT_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
thisModem().waitResponse();
res.trim();
return res;
}
/*
* Messaging functions
*/
protected:
// Follows all messaging functions per template
/*
* GPS/GNSS/GLONASS location functions
*/
@@ -293,7 +248,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
// get the RAW GPS output
String getGPSrawImpl() {
thisModem().sendAT(GF("+CGNSINF"));
if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) {
if (thisModem().waitResponse(10000L, GF(AT_NL "+CGNSINF:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
@@ -308,7 +263,7 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) {
thisModem().sendAT(GF("+CGNSINF"));
if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) {
if (thisModem().waitResponse(10000L, GF(AT_NL "+CGNSINF:")) != 1) {
return false;
}
@@ -361,20 +316,20 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
thisModem().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 (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr) *vsat = ivsat;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *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);
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
thisModem().waitResponse();
return true;
@@ -384,76 +339,12 @@ class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
thisModem().waitResponse();
return false;
}
/*
* Time functions
*/
// Can follow CCLK as per template
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
/*
* Battery functions
*/
protected:
// Follows all battery functions per template
/*
* Client related functions
*/
// should implement in sub-classes
/*
* Utilities
*/
public:
// should implement in sub-classes
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return thisModem().waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return thisModem().waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return thisModem().waitResponse(1000, r1, r2, r3, r4, r5);
bool handleURCs(String& data) {
return thisModem().handleURCs(data);
}
public:
Stream& stream;
protected:
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTSIM70XX_H_

View File

@@ -14,29 +14,41 @@
#define TINY_GSM_MUX_COUNT 10
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "SIMCom"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_SIM7500)
#define MODEM_MODEL "SIM7500";
#elif defined(TINY_GSM_MODEM_SIM7800)
#define MODEM_MODEL "SIM7800";
#else
#define MODEM_MODEL "SIM7600";
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
#include "TinyGsmTemperature.tpp"
enum SIM7600RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -130,28 +142,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
/*
* Inner Secure Client
*/
/*TODO(?))
class GsmClientSecureSIM7600 : public GsmClientSim7600
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmSim7600& modem, uint8_t mux = 0)
: public GsmClient(modem, mux)
{}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
*/
// NOT SUPPORTED
/*
* Constructor
@@ -165,7 +156,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7600"));
@@ -193,7 +184,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -203,21 +194,6 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
}
}
String getModemNameImpl() {
String name = "SIMCom SIM7600";
sendAT(GF("+CGMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return name; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.replace("_", " ");
res2.trim();
name = res2;
DBG("### Modem:", name);
return name;
}
bool factoryDefaultImpl() { // these commands aren't supported
return false;
}
@@ -226,11 +202,11 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+CRESET"));
if (waitResponse(10000L) != 1) { return false; }
delay(5000L); // TODO(?): Test this delay!
delay(24000L);
return init(pin);
}
@@ -259,20 +235,21 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CGREG");
SIM7600RegStatus getRegistrationStatus() {
return (SIM7600RegStatus)getRegistrationStatusXREG("CGREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
SIM7600RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
public:
String getNetworkModes() {
// Get the help string, not the setting value
sendAT(GF("+CNMP=?"));
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+CNMP:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
return res;
@@ -280,7 +257,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
int16_t getNetworkMode() {
sendAT(GF("+CNMP?"));
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CNMP:")) != 1) { return false; }
int16_t mode = streamGetIntBefore('\n');
waitResponse();
return mode;
@@ -291,23 +268,43 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
return waitResponse() == 1;
}
bool getNetworkSystemMode(bool& n, int16_t& stat) {
// n: whether to automatically report the system mode info
// stat: the current service. 0 if it not connected
sendAT(GF("+CNSMOD?"));
if (waitResponse(GF(AT_NL "+CNSMOD:")) != 1) { return false; }
n = streamGetIntBefore(',') != 0;
stat = streamGetIntBefore('\n');
waitResponse();
return true;
}
String getLocalIPImpl() {
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
// sendAT(GF("+CGPADDR=1")); // Show PDP address
String res;
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
cleanResponseString(res);
res.trim();
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// No functions of this type supported
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect(); // Make sure we're not connected first
// Define the PDP context
@@ -316,7 +313,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// Set the external authentication
if (user && strlen(user) > 0) {
sendAT(GF("+CGAUTH=1,0,\""), user, GF("\",\""), pwd, '"');
sendAT(GF("+CGAUTH=1,0,\""), pwd, GF("\",\""), user, '"');
waitResponse();
}
@@ -364,7 +361,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// We to ignore any immediate response and wait for the
// URC to show it's really connected.
sendAT(GF("+NETOPEN"));
if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; }
if (waitResponse(75000L, GF(AT_NL "+NETOPEN: 0")) != 1) { return false; }
return true;
}
@@ -374,7 +371,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// Note: On the LTE models, this single command closes all sockets and the
// service
sendAT(GF("+NETCLOSE"));
if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; }
if (waitResponse(60000L, GF(AT_NL "+NETCLOSE: 0")) != 1) { return false; }
return true;
}
@@ -382,7 +379,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
bool isGprsConnectedImpl() {
sendAT(GF("+NETOPEN?"));
// May return +NETOPEN: 1, 0. We just confirm that the first number is 1
if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+NETOPEN: 1")) != 1) { return false; }
waitResponse();
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
@@ -392,6 +389,15 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
return true;
}
String getProviderImpl() {
sendAT(GF("+CSPN?"));
if (waitResponse(GF("+CSPN:")) != 1) { return ""; }
streamSkipUntil('"'); /* Skip mode and format */
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* SIM card functions
*/
@@ -399,7 +405,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// Gets the CCID of a sim card via AT+CCID
String getSimCCIDImpl() {
sendAT(GF("+CICCID"));
if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+ICCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -416,16 +422,20 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
}
/*
* Messaging functions
* Audio functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
protected:
// Can return a GSM-based location from CLBS as per the template
// Follows all GSM-based location functions as inherited from
// TinyGsmGSMLocation.tpp
/*
* GPS/GNSS/GLONASS location functions
@@ -447,7 +457,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// get the RAW GPS output
String getGPSrawImpl() {
sendAT(GF("+CGNSSINFO"));
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+CGNSSINFO:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -460,7 +470,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) {
sendAT(GF("+CGNSSINFO"));
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CGNSSINFO:")) != 1) { return false; }
uint8_t fixMode = streamGetIntBefore(','); // mode 2=2D Fix or 3=3DFix
// TODO(?) Can 1 be returned
@@ -486,11 +496,11 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
streamSkipUntil(','); // GLONASS satellite valid numbers
streamSkipUntil(','); // BEIDOU satellite valid numbers
ilat = streamGetFloatBefore(','); // Latitude in ddmm.mmmmmm
north = stream.read(); // N/S Indicator, N=north or S=south
streamSkipUntil(',');
north = stream.readStringUntil(',').charAt(
0); // N/S Indicator, N=north or S=south
ilon = streamGetFloatBefore(','); // Longitude in ddmm.mmmmmm
east = stream.read(); // E/W Indicator, E=east or W=west
streamSkipUntil(',');
east = stream.readStringUntil(',').charAt(
0); // E/W Indicator, E=east or W=west
// Date. Output format is ddmmyy
iday = streamGetIntLength(2); // Two digit day
@@ -506,31 +516,29 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
ialt = streamGetFloatBefore(','); // MSL Altitude. Unit is meters
ispeed = streamGetFloatBefore(','); // Speed Over Ground. Unit is knots.
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // After set, will report GPS every x seconds
iaccuracy = streamGetFloatBefore(','); // Position Dilution Of Precision
streamSkipUntil(','); // Horizontal Dilution Of Precision
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil('\n'); // TODO(?) is one more field reported??
streamSkipUntil('\n'); // Vertical Dilution Of Precision
// Set pointers
if (lat != NULL)
if (lat != nullptr)
*lat = (floor(ilat / 100) + fmod(ilat, 100.) / 60) *
(north == 'N' ? 1 : -1);
if (lon != NULL)
if (lon != nullptr)
*lon = (floor(ilon / 100) + fmod(ilon, 100.) / 60) *
(east == 'E' ? 1 : -1);
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 (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr) *vsat = ivsat;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *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);
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
waitResponse();
return true;
@@ -540,7 +548,6 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
return false;
}
/**
* CGNSSMODE: <gnss_mode>,<dpo_mode>
* This command is used to configure GPS, GLONASS, BEIDOU and QZSS support
@@ -551,14 +558,14 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
String res;
sendAT(GF("+CGNSSMODE="), mode, ",", dpo);
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL, "");
res.replace(AT_NL, "");
res.trim();
return res;
}
uint8_t getGNSSModeImpl() {
sendAT(GF("+CGNSSMODE?"));
if (waitResponse(GF(GSM_NL "+CGNSSMODE:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CGNSSMODE:")) != 1) { return 0; }
return stream.readStringUntil(',').toInt();
}
@@ -566,22 +573,26 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// returns volts, multiply by 1000 to get mV
uint16_t getBattVoltageImpl() {
int16_t getBattVoltageImpl() {
sendAT(GF("+CBC"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CBC:")) != 1) { return 0; }
// get voltage in VOLTS
float voltage = streamGetFloatBefore('\n');
@@ -594,10 +605,10 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
chargeState = 0;
percent = 0;
milliVolts = getBattVoltage();
@@ -611,7 +622,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
// get temperature in degree celsius
uint16_t getTemperatureImpl() {
sendAT(GF("+CPMUTEMP"));
if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CPMUTEMP:")) != 1) { return 0; }
// return temperature in C
uint16_t res = streamGetIntBefore('\n');
// Wait for final OK
@@ -636,7 +647,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
port);
// The reply is OK followed by +CIPOPEN: <link_num>,<err> where <link_num>
// is the mux number and <err> should be 0 if there's no error
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; }
if (waitResponse(timeout_ms, GF(AT_NL "+CIPOPEN:")) != 1) { return false; }
uint8_t opened_mux = streamGetIntBefore(',');
uint8_t opened_result = streamGetIntBefore('\n');
if (opened_mux != mux || opened_result != 0) return false;
@@ -648,7 +659,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CIPSEND:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip requested bytes to send
// TODO(?): make sure requested and confirmed bytes match
@@ -682,7 +693,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
};
buf[0] = stream.read();
buf[1] = stream.read();
char c = strtol(buf, NULL, 16);
char c = strtol(buf, nullptr, 16);
#else
while (!stream.available() &&
(millis() - startMillis < sockets[mux]->_timeout)) {
@@ -734,125 +745,49 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
} else {
data += mode;
}
} else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
// DBG("### Got Data:", len, "on", mux);
} else if (data.endsWith(GF("+IPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
streamSkipUntil('\n'); // Skip the reason code
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
} else if (data.endsWith(GF("+CIPEVENT:"))) {
// Need to close all open sockets and release the network library.
// User will then need to reconnect.
DBG("### Network error!");
if (!isGprsConnected()) { gprsDisconnect(); }
data = "";
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
return true;
} else {
data += mode;
return false;
}
} else if (data.endsWith(GF(AT_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
// DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+IPCLOSE:"))) {
int8_t mux = streamGetIntBefore(',');
streamSkipUntil('\n'); // Skip the reason code
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
} else if (data.endsWith(GF("+CIPEVENT:"))) {
// Need to close all open sockets and release the network library.
// User will then need to reconnect.
DBG("### Network error!");
if (!isGprsConnected()) { gprsDisconnect(); }
data = "";
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -860,7 +795,6 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
protected:
GsmClientSim7600* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTSIM7600_H_

View File

@@ -15,27 +15,41 @@
#define TINY_GSM_MUX_COUNT 5
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "unknown"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#if defined(TINY_GSM_MODEM_SIM808)
#define MODEM_MODEL "SIM808";
#elif defined(TINY_GSM_MODEM_SIM868)
#define MODEM_MODEL "SIM868";
#elif defined(TINY_GSM_MODEM_SIM900)
#define MODEM_MODEL "SIM900";
#else
#define MODEM_MODEL "SIM800";
#endif
enum RegStatus {
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmNTP.tpp"
#include "TinyGsmBattery.tpp"
enum SIM800RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -47,7 +61,7 @@ enum RegStatus {
class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
public TinyGsmGPRS<TinyGsmSim800>,
public TinyGsmTCP<TinyGsmSim800, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSim800>,
public TinyGsmSSL<TinyGsmSim800, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmSim800>,
public TinyGsmSMS<TinyGsmSim800>,
public TinyGsmGSMLocation<TinyGsmSim800>,
@@ -57,7 +71,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
friend class TinyGsmModem<TinyGsmSim800>;
friend class TinyGsmGPRS<TinyGsmSim800>;
friend class TinyGsmTCP<TinyGsmSim800, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSim800>;
friend class TinyGsmSSL<TinyGsmSim800, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmSim800>;
friend class TinyGsmSMS<TinyGsmSim800>;
friend class TinyGsmGSMLocation<TinyGsmSim800>;
@@ -134,7 +148,6 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
explicit GsmClientSecureSim800(TinyGsmSim800& modem, uint8_t mux = 0)
: GsmClientSim800(modem, mux) {}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
@@ -157,7 +170,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM800"));
@@ -188,7 +201,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -198,30 +211,6 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
}
}
String getModemNameImpl() {
String name = "";
#if defined(TINY_GSM_MODEM_SIM800)
name = "SIMCom SIM800";
#elif defined(TINY_GSM_MODEM_SIM808)
name = "SIMCom SIM808";
#elif defined(TINY_GSM_MODEM_SIM868)
name = "SIMCom SIM868";
#elif defined(TINY_GSM_MODEM_SIM900)
name = "SIMCom SIM900";
#endif
sendAT(GF("+GMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return name; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.replace("_", " ");
res2.trim();
name = res2;
DBG("### Modem:", name);
return name;
}
bool factoryDefaultImpl() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
@@ -243,7 +232,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
return false;
#else
sendAT(GF("+CIPSSL=?"));
if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+CIPSSL:")) != 1) { return false; }
return waitResponse() == 1;
#endif
}
@@ -253,7 +242,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("&W"));
waitResponse();
@@ -290,13 +279,13 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
SIM800RegStatus getRegistrationStatus() {
return (SIM800RegStatus)getRegistrationStatusXREG("CREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
SIM800RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
@@ -304,18 +293,26 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
sendAT(GF("+CIFSR;E0"));
String res;
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
cleanResponseString(res);
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Bearer settings for applications based on IP
@@ -400,6 +397,15 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
return true;
}
String getProviderImpl() {
sendAT(GF("+CSPN?"));
if (waitResponse(GF("+CSPN:")) != 1) { return ""; }
streamSkipUntil('"'); /* Skip mode and format */
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* SIM card functions
*/
@@ -407,7 +413,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
// May not return the "+CCID" before the number
String getSimCCIDImpl() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
if (waitResponse(GF(AT_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
// Trim out the CCID header in case it is there
@@ -425,26 +431,6 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
return waitResponse() == 1;
}
/*
* Messaging functions
*/
protected:
// Follows all messaging functions per template
/*
* GSM Location functions
*/
protected:
// Depending on the exacty model and firmware revision, should return a
// GSM-based location from CLBS as per the template
// TODO(?): Check number of digits in year (2 or 4)
/*
* GPS/GNSS/GLONASS location functions
*/
protected:
// No functions of this type supported
/*
* Audio functions
*/
@@ -458,7 +444,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
uint8_t getVolume() {
// Get speaker volume
sendAT(GF("+CLVL?"));
if (waitResponse(GF(GSM_NL)) != 1) { return 0; }
if (waitResponse(GF(AT_NL)) != 1) { return 0; }
String res = stream.readStringUntil('\n');
waitResponse();
res.replace("+CLVL:", "");
@@ -484,27 +470,47 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
return waitResponse();
}
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
// Depending on the exacty model and firmware revision, should return a
// GSM-based location from CLBS as as inherited from TinyGsmGSMLocation.tpp
// TODO(?): Check number of digits in year (2 or 4)
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// Can sync with server using CNTP as per template
// Follows all NTP server functions as inherited from TinyGsmNTP.tpp
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// Follows all battery functions per template
// Follows all battery functions as inherited from TinyGsmBattery.tpp
/*
* NTP server functions
* Temperature functions
*/
// Can sync with server using CNTP as per template
// No functions of this type supported
/*
* Client related functions
@@ -534,9 +540,9 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host,
GF("\","), port);
rsp = waitResponse(
timeout_ms, GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL), GF("ERROR" GSM_NL),
GF("CLOSE OK" GSM_NL)); // Happens when HTTPS handshake fails
timeout_ms, GF("CONNECT OK" AT_NL), GF("CONNECT FAIL" AT_NL),
GF("ALREADY CONNECT" AT_NL), GF("ERROR" AT_NL),
GF("CLOSE OK" AT_NL)); // Happens when HTTPS handshake fails
return (1 == rsp);
}
@@ -545,7 +551,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "DATA ACCEPT:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
return streamGetIntBefore('\n');
}
@@ -581,7 +587,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
};
buf[0] = stream.read();
buf[1] = stream.read();
char c = strtol(buf, NULL, 16);
char c = strtol(buf, nullptr, 16);
#else
while (!stream.available() &&
(millis() - startMillis < sockets[mux]->_timeout)) {
@@ -627,137 +633,63 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
} else {
data += mode;
}
} else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
// DBG("### Got Data:", len, "on", mux);
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
} else if (data.endsWith(GF("DST:"))) {
streamSkipUntil(
'\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+CIPRXGET:"))) {
int8_t mode = streamGetIntBefore(',');
if (mode == 1) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
data = "";
// DBG("### Got Data:", mux);
return true;
} else {
data += mode;
return false;
}
} else if (data.endsWith(GF(AT_NL "+RECEIVE:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
// DBG("### Got Data:", len, "on", mux);
return true;
} else if (data.endsWith(GF("CLOSED" AT_NL))) {
int8_t nl = data.lastIndexOf(AT_NL, data.length() - 8);
int8_t coma = data.indexOf(',', nl + 2);
int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
return true;
} else if (data.endsWith(GF("*PSNWID:"))) {
streamSkipUntil('\n'); // Refresh network name by network
data = "";
DBG("### Network name updated.");
return true;
} else if (data.endsWith(GF("*PSUTTZ:"))) {
streamSkipUntil('\n'); // Refresh time and time zone by network
data = "";
DBG("### Network time and time zone updated.");
return true;
} else if (data.endsWith(GF("+CTZV:"))) {
streamSkipUntil('\n'); // Refresh network time zone by network
data = "";
DBG("### Network time zone updated.");
return true;
} else if (data.endsWith(GF("DST:"))) {
streamSkipUntil('\n'); // Refresh Network Daylight Saving Time by network
data = "";
DBG("### Daylight savings time state updated.");
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -765,7 +697,6 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
protected:
GsmClientSim800* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTSIM800_H_

View File

@@ -14,7 +14,9 @@
#include "TinyGsmGPS.tpp"
#include "TinyGsmBluetooth.tpp"
class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, public TinyGsmBluetooth<TinyGsmSim808> {
class TinyGsmSim808 : public TinyGsmSim800,
public TinyGsmGPS<TinyGsmSim808>,
public TinyGsmBluetooth<TinyGsmSim808> {
friend class TinyGsmGPS<TinyGsmSim808>;
friend class TinyGsmBluetooth<TinyGsmSim808>;
@@ -43,7 +45,7 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, pu
// works only with ans SIM808 V2
String getGPSrawImpl() {
sendAT(GF("+CGNSINF"));
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
if (waitResponse(10000L, GF(AT_NL "+CGNSINF:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -57,7 +59,7 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, pu
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) {
sendAT(GF("+CGNSINF"));
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
if (waitResponse(10000L, GF(AT_NL "+CGNSINF:")) != 1) { return false; }
streamSkipUntil(','); // GNSS run status
if (streamGetIntBefore(',') == 1) { // fix status
@@ -106,20 +108,20 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, pu
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 (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr) *vsat = ivsat;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *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);
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
waitResponse();
return true;
@@ -129,11 +131,11 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, pu
waitResponse();
return false;
}
/*
/*
* Bluetooth functions
*/
bool enableBluetoothImpl() {
sendAT(GF("+BTPOWER=1"));
if (waitResponse() != 1) { return false; }
@@ -145,22 +147,18 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, pu
if (waitResponse() != 1) { return false; }
return true;
}
bool setBluetoothVisibilityImpl(bool visible) {
sendAT(GF("+BTVIS="), visible);
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
return true;
}
bool setBluetoothHostNameImpl(const char* name) {
sendAT(GF("+BTHOST="), name);
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
return true;
}
};

View File

@@ -14,27 +14,33 @@
#define TINY_GSM_MUX_COUNT 7
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#include "TinyGsmBattery.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
enum RegStatus {
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "u-blox"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "SARA-R4"
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmBattery.tpp"
#include "TinyGsmTemperature.tpp"
enum SaraR4RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -47,23 +53,23 @@ enum RegStatus {
class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
public TinyGsmGPRS<TinyGsmSaraR4>,
public TinyGsmTCP<TinyGsmSaraR4, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSaraR4>,
public TinyGsmBattery<TinyGsmSaraR4>,
public TinyGsmSSL<TinyGsmSaraR4, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmSaraR4>,
public TinyGsmGSMLocation<TinyGsmSaraR4>,
public TinyGsmGPS<TinyGsmSaraR4>,
public TinyGsmSMS<TinyGsmSaraR4>,
public TinyGsmTemperature<TinyGsmSaraR4>,
public TinyGsmTime<TinyGsmSaraR4> {
public TinyGsmTime<TinyGsmSaraR4>,
public TinyGsmBattery<TinyGsmSaraR4>,
public TinyGsmTemperature<TinyGsmSaraR4> {
friend class TinyGsmModem<TinyGsmSaraR4>;
friend class TinyGsmGPRS<TinyGsmSaraR4>;
friend class TinyGsmTCP<TinyGsmSaraR4, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSaraR4>;
friend class TinyGsmBattery<TinyGsmSaraR4>;
friend class TinyGsmSSL<TinyGsmSaraR4, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSMS<TinyGsmSaraR4>;
friend class TinyGsmGSMLocation<TinyGsmSaraR4>;
friend class TinyGsmGPS<TinyGsmSaraR4>;
friend class TinyGsmSMS<TinyGsmSaraR4>;
friend class TinyGsmTemperature<TinyGsmSaraR4>;
friend class TinyGsmTime<TinyGsmSaraR4>;
friend class TinyGsmTemperature<TinyGsmSaraR4>;
friend class TinyGsmBattery<TinyGsmSaraR4>;
/*
* Inner Client
@@ -106,7 +112,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
sock_connected = at->modemConnect(host, port, &mux, false, timeout_s);
if (mux != oldMux) {
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
at->sockets[oldMux] = NULL;
at->sockets[oldMux] = nullptr;
}
at->sockets[mux] = this;
at->maintain();
@@ -185,7 +191,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
sock_connected = at->modemConnect(host, port, &mux, true, timeout_s);
if (mux != oldMux) {
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
at->sockets[oldMux] = NULL;
at->sockets[oldMux] = nullptr;
}
at->sockets[mux] = this;
at->maintain();
@@ -217,7 +223,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSaraR4"));
@@ -253,7 +259,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -265,25 +271,14 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// only difference in implementation is the warning on the wrong type
String getModemNameImpl() {
sendAT(GF("+CGMI"));
String res1;
if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; }
res1.replace(GSM_NL "OK" GSM_NL, "");
res1.trim();
sendAT(GF("+GMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.trim();
String name = res1 + String(' ') + res2;
String manufacturer = getModemManufacturer();
String model = getModemModel();
String name = manufacturer + String(" ") + model;
DBG("### Modem:", name);
if (!name.startsWith("u-blox SARA-R4") &&
!name.startsWith("u-blox SARA-N4")) {
DBG("### WARNING: You are using the wrong TinyGSM modem!");
}
return name;
}
@@ -297,7 +292,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
*/
protected:
// using +CFUN=15 instead of the more common CFUN=1,1
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
if (!setPhoneFunctionality(15)) { return false; }
delay(3000); // TODO(?): Verify delay timing here
@@ -320,22 +315,23 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
SaraR4RegStatus getRegistrationStatus() {
// Check first for EPS registration
RegStatus epsStatus = (RegStatus)getRegistrationStatusXREG("CEREG");
SaraR4RegStatus epsStatus =
(SaraR4RegStatus)getRegistrationStatusXREG("CEREG");
// If we're connected on EPS, great!
if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) {
return epsStatus;
} else {
// Otherwise, check generic network status
return (RegStatus)getRegistrationStatusXREG("CREG");
return (SaraR4RegStatus)getRegistrationStatusXREG("CREG");
}
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
SaraR4RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
@@ -352,12 +348,22 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
return restart();
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
// gprsDisconnect();
sendAT(GF("+CGATT=1")); // attach to GPRS
@@ -410,7 +416,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// This uses "CGSN" instead of "GSN"
String getIMEIImpl() {
sendAT(GF("+CGSN"));
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
if (waitResponse(GF(AT_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -418,7 +424,17 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
}
/*
* Messaging functions
* Phone Call functions
*/
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
protected:
String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
@@ -440,12 +456,12 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// <aid_mode> - 0: no aiding (default)
// <GNSS_systems> - 3: GPS + SBAS (default)
sendAT(GF("+UGPS=1,0,3"));
if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; }
if (waitResponse(10000L, GF(AT_NL "+UGPS:")) != 1) { return false; }
return waitResponse(10000L) == 1;
}
bool disableGPSImpl() {
sendAT(GF("+UGPS=0"));
if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; }
if (waitResponse(10000L, GF(AT_NL "+UGPS:")) != 1) { return false; }
return waitResponse(10000L) == 1;
}
String inline getUbloxLocationRaw(int8_t sensor) {
@@ -465,7 +481,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// wait for first "OK"
if (waitResponse(10000L) != 1) { return ""; }
// wait for the final result - wait full timeout time
if (waitResponse(120000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; }
if (waitResponse(120000L, GF(AT_NL "+UULOC:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -500,7 +516,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// wait for first "OK"
if (waitResponse(10000L) != 1) { return false; }
// wait for the final result - wait full timeout time
if (waitResponse(120000L, GF(GSM_NL "+UULOC: ")) != 1) { return false; }
if (waitResponse(120000L, GF(AT_NL "+UULOC: ")) != 1) { return false; }
// +UULOC: <date>, <time>, <lat>, <long>, <alt>, <uncertainty>, <speed>,
// <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>,
@@ -549,20 +565,21 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
}
// 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 (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr)
*vsat = 0; // Number of satellites viewed not reported;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *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);
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
// final ok
waitResponse();
@@ -585,18 +602,37 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercentImpl() {
sendAT(GF("+CIND?"));
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CIND:")) != 1) { return 0; }
int8_t res = streamGetIntBefore(',');
int8_t percent = res * 20; // return is 0-5
@@ -605,10 +641,10 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
return percent;
}
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
chargeState = 0;
percent = getBattPercent();
milliVolts = 0;
@@ -624,7 +660,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
sendAT(GF("+UTEMP=0")); // Would use 1 for Fahrenheit
if (waitResponse() != 1) { return static_cast<float>(-9999); }
sendAT(GF("+UTEMP?"));
if (waitResponse(GF(GSM_NL "+UTEMP:")) != 1) {
if (waitResponse(GF(AT_NL "+UTEMP:")) != 1) {
return static_cast<float>(-9999);
}
int16_t res = streamGetIntBefore('\n');
@@ -645,7 +681,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// create a socket
sendAT(GF("+USOCR=6"));
// reply is +USOCR: ## of socket created
if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+USOCR:")) != 1) { return false; }
*mux = streamGetIntBefore('\n');
waitResponse();
@@ -679,7 +715,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
"the URC '+UUSOCO' appears.");
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1");
if (waitResponse(timeout_ms - (millis() - startMillis),
GF(GSM_NL "+UUSOCO:")) == 1) {
GF(AT_NL "+UUSOCO:")) == 1) {
streamGetIntBefore(','); // skip repeated mux
int8_t connection_status = streamGetIntBefore('\n');
DBG("### Waited", millis() - startMillis, "ms for socket to open");
@@ -704,7 +740,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
delay(50);
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+USOWR:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int16_t sent = streamGetIntBefore('\n');
waitResponse(); // sends back OK after the confirmation of number sent
@@ -714,7 +750,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
size_t modemRead(size_t size, uint8_t mux) {
if (!sockets[mux]) return 0;
sendAT(GF("+USORD="), mux, ',', (uint16_t)size);
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+USORD:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int16_t len = streamGetIntBefore(',');
streamSkipUntil('\"');
@@ -732,7 +768,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USORD="), mux, ",0");
size_t result = 0;
uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
uint8_t res = waitResponse(GF(AT_NL "+USORD:"));
// Will give error "operation not allowed" when attempting to read a socket
// that you have already told to close
if (res == 1) {
@@ -749,7 +785,7 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
bool modemGetConnected(uint8_t mux) {
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USOCTL="), mux, ",10");
uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:"));
uint8_t res = waitResponse(GF(AT_NL "+USOCTL:"));
if (res != 1) { return false; }
streamSkipUntil(','); // Skip mux
@@ -775,116 +811,38 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+UUSORD:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
// max size is 1024
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
DBG("### URC Data Received:", len, "on", mux);
} else if (data.endsWith(GF("+UUSOCL:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
} else if (data.endsWith(GF("+UUSOCO:"))) {
int8_t mux = streamGetIntBefore('\n');
int8_t socket_error = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] &&
socket_error == 0) {
sockets[mux]->sock_connected = true;
}
data = "";
DBG("### URC Sock Opened: ", mux);
}
bool handleURCs(String& data) {
if (data.endsWith(GF("+UUSORD:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
// max size is 1024
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
DBG("### URC Data Received:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+UUSOCL:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
return true;
} else if (data.endsWith(GF("+UUSOCO:"))) {
int8_t mux = streamGetIntBefore('\n');
int8_t socket_error = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] &&
socket_error == 0) {
sockets[mux]->sock_connected = true;
}
data = "";
DBG("### URC Sock Opened: ", mux);
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -892,7 +850,6 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
protected:
GsmClientSaraR4* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
bool has2GFallback;
bool supportsAsyncSockets;
};

823
src/TinyGsmClientSaraR5.h Normal file
View File

@@ -0,0 +1,823 @@
/**
* @file TinyGsmClientSaraR5.h
* @author Sebastian Bergner, Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Aug 2023
*/
#ifndef SRC_TINYGSMCLIENTSARAR5_H_
#define SRC_TINYGSMCLIENTSARAR5_H_
// #pragma message("TinyGSM: TinyGsmClientSaraR5")
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 7
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "u-blox"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "SARA-R5"
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmBattery.tpp"
enum SaraR5RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_OK_HOME = 1,
REG_OK_ROAMING = 5,
REG_UNKNOWN = 4,
REG_SMS_ONLY_HOME = 6,
REG_SMS_ONLY_ROAMING = 7,
REG_EMERGENCY_ONLY =
8, // blox AT command manual states: attached for emergency bearer
// services only (see 3GPP TS 24.008 [85] and 3GPP TS 24.301 [120]
// that specify the condition when the MS is considered as attached
// for emergency bearer services)
REG_NO_FALLBACK_LTE_HOME =
9, // not 100% certain, ublox AT command manual states: registered for
// "CSFB not preferred", home network (applicable only when
// <AcTStatus> indicates E-UTRAN)
REG_NO_FALLBACK_LTE_ROAMING =
10 // not 100% certain, ublox AT command manual states: registered for
// "CSFB not preferred", roaming (applicable only when <AcTStatus>
// indicates E-UTRAN)
};
class TinyGsmSaraR5 : public TinyGsmModem<TinyGsmSaraR5>,
public TinyGsmGPRS<TinyGsmSaraR5>,
public TinyGsmTCP<TinyGsmSaraR5, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSaraR5, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmSaraR5>,
public TinyGsmSMS<TinyGsmSaraR5>,
public TinyGsmGSMLocation<TinyGsmSaraR5>,
public TinyGsmGPS<TinyGsmSaraR5>,
public TinyGsmTime<TinyGsmSaraR5>,
public TinyGsmBattery<TinyGsmSaraR5> {
friend class TinyGsmModem<TinyGsmSaraR5>;
friend class TinyGsmGPRS<TinyGsmSaraR5>;
friend class TinyGsmTCP<TinyGsmSaraR5, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSaraR5, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmSaraR5>;
friend class TinyGsmSMS<TinyGsmSaraR5>;
friend class TinyGsmGSMLocation<TinyGsmSaraR5>;
friend class TinyGsmGPS<TinyGsmSaraR5>;
friend class TinyGsmTime<TinyGsmSaraR5>;
friend class TinyGsmBattery<TinyGsmSaraR5>;
/*
* Inner Client
*/
public:
class GsmClientSaraR5 : public GsmClient {
friend class TinyGsmSaraR5;
public:
GsmClientSaraR5() {}
explicit GsmClientSaraR5(TinyGsmSaraR5& modem, uint8_t mux = 0) {
init(&modem, mux);
}
bool init(TinyGsmSaraR5* modem, uint8_t mux = 0) {
this->at = modem;
sock_available = 0;
prev_check = 0;
sock_connected = false;
got_data = false;
if (mux < TINY_GSM_MUX_COUNT) {
this->mux = mux;
} else {
this->mux = (mux % TINY_GSM_MUX_COUNT);
}
at->sockets[this->mux] = this;
return true;
}
public:
virtual int connect(const char* host, uint16_t port, int timeout_s) {
// stop(); // DON'T stop!
TINY_GSM_YIELD();
rx.clear();
uint8_t oldMux = mux;
sock_connected = at->modemConnect(host, port, &mux, false, timeout_s);
if (mux != oldMux) {
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
at->sockets[oldMux] = nullptr;
}
at->sockets[mux] = this;
at->maintain();
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
void stop(uint32_t maxWaitMs) {
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+USOCL="), mux);
at->waitResponse(); // should return within 1s
sock_connected = false;
}
void stop() override {
stop(15000L);
}
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Inner Secure Client
*/
public:
class GsmClientSecureR5 : public GsmClientSaraR5 {
public:
GsmClientSecureR5() {}
explicit GsmClientSecureR5(TinyGsmSaraR5& modem, uint8_t mux = 0)
: GsmClientSaraR5(modem, mux) {}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
// stop(); // DON'T stop!
TINY_GSM_YIELD();
rx.clear();
uint8_t oldMux = mux;
sock_connected = at->modemConnect(host, port, &mux, true, timeout_s);
if (mux != oldMux) {
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
at->sockets[oldMux] = nullptr;
}
at->sockets[mux] = this;
at->maintain();
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
/*
* Constructor
*/
public:
explicit TinyGsmSaraR5(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
protected:
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSaraR5"));
if (!testAT()) { return false; }
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
#else
sendAT(GF("+CMEE=0")); // turn off error codes
#endif
waitResponse();
DBG(GF("### Modem:"), getModemName());
// Enable automatic time zome update
sendAT(GF("+CTZU=1"));
waitResponse(10000L);
// Ignore the response, in case the network doesn't support it.
// if (waitResponse(10000L) != 1) { return false; }
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
// only difference in implementation is the warning on the wrong type
String getModemNameImpl() {
String manufacturer = getModemManufacturer();
String model = getModemModel();
String name = manufacturer + String(" ") + model;
if (name.startsWith("u-blox SARA-R4") ||
name.startsWith("u-blox SARA-N4")) {
DBG("### WARNING: You are using the wrong TinyGSM modem!");
} else if (name.startsWith("u-blox SARA-N2")) {
DBG("### SARA N2 NB-IoT modems not supported!");
}
return name;
}
bool factoryDefaultImpl() {
sendAT(GF("+UFACTORY=0,1")); // No factory restore, erase NVM
waitResponse();
return setPhoneFunctionality(16); // Reset
}
/*
* Power functions
*/
protected:
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
if (!setPhoneFunctionality(16)) { return false; }
delay(3000); // TODO(?): Verify delay timing here
return init(pin);
}
bool powerOffImpl() {
sendAT(GF("+CPWROFF"));
return waitResponse(40000L) == 1;
}
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
return waitResponse(10000L) == 1;
}
/*
* Generic network functions
*/
public:
SaraR5RegStatus getRegistrationStatus() {
// Check first for EPS registration
SaraR5RegStatus epsStatus =
(SaraR5RegStatus)getRegistrationStatusXREG("CEREG");
// If we're connected on EPS, great!
if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) {
return epsStatus;
} else {
// Otherwise, check generic network status
return (SaraR5RegStatus)getRegistrationStatusXREG("CREG");
}
}
bool setRadioAccessTechnology(int selected, int preferred) {
// selected:
// 0: GSM / GPRS / eGPRS (single mode)
// 1: GSM / UMTS (dual mode)
// 2: UMTS (single mode)
// 3: LTE (single mode)
// 4: GSM / UMTS / LTE (tri mode)
// 5: GSM / LTE (dual mode)
// 6: UMTS / LTE (dual mode)
// preferred:
// 0: GSM / GPRS / eGPRS
// 2: UTRAN
// 3: LTE
sendAT(GF("+URAT="), selected, GF(","), preferred);
if (waitResponse() != 1) { return false; }
return true;
}
bool getCurrentRadioAccessTechnology() {
sendAT(GF("+URAT?"));
String response;
if (waitResponse(10000L, response) != 1) { return false; }
return true;
}
protected:
bool isNetworkConnectedImpl() {
SaraR5RegStatus s = getRegistrationStatus();
if (s == REG_OK_HOME || s == REG_OK_ROAMING || s == REG_SMS_ONLY_ROAMING ||
s == REG_SMS_ONLY_HOME)
return true;
else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown..
return isGprsConnected();
else
return false;
}
String getLocalIPImpl() {
sendAT(GF("+UPSND=0,0"));
if (waitResponse(GF(AT_NL "+UPSND:")) != 1) { return ""; }
streamSkipUntil(','); // Skip PSD profile
streamSkipUntil('\"'); // Skip request type
String res = stream.readStringUntil('\"');
if (waitResponse() != 1) { return ""; }
return res;
}
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
sendAT(GF("+CGATT=1")); // attach to GPRS
if (waitResponse(360000L) != 1) { return false; }
// Setting up the PSD profile/PDP context with the UPSD commands sets up an
// "internal" PDP context, i.e. a data connection using the internal IP
// stack and related AT commands for sockets.
// Packet switched data configuration
// AT+UPSD=<profile_id>,<param_tag>,<param_val>
// profile_id = 0 - PSD profile identifier, in range 0-6 (NOT PDP context)
// param_tag = 1: APN
// param_tag = 2: username -> not working for SARA-R5
// param_tag = 3: password -> not working for SARA-R5
// param_tag = 7: IP address Note: IP address set as "0.0.0.0" means
// dynamic IP address assigned during PDP context activation
// check all available PDP context identifiers
String response;
response.reserve(1024);
sendAT(GF("+CGDCONT?"));
waitResponseUntilEndStream(1000, response);
if (response.length() == 0) {
return false; // no apn at all found
}
// parse string & look for apn -> modified from SparkFun u-blox SARA-R5 lib
// Example:
// +CGDCONT: 0,"IP","payandgo.o2.co.uk","0.0.0.0",0,0,0,0,0,0,0,0,0,0
// +CGDCONT:
// 1,"IP","payandgo.o2.co.uk.mnc010.mcc234.gprs","10.160.182.234",0,0,0,2,0,0,0,0,0,0
// create search buffer where we can search
char* searchBuf = (char*)malloc(response.length() + 1);
response.toCharArray(searchBuf, response.length() + 1);
int rcid = -1;
char* searchPtr = searchBuf;
for (size_t index = 0; index <= response.length(); index++) {
int scanned = 0;
// Find the first/next occurrence of +CGDCONT:
searchPtr = strstr(searchPtr, "+CGDCONT:");
if (searchPtr != nullptr) {
char strPdpType[10];
char strApn[128];
int ipOct[4];
searchPtr += strlen("+CGDCONT:");
while (*searchPtr == ' ') searchPtr++; // skip spaces
scanned = sscanf(searchPtr, "%d,\"%[^\"]\",\"%[^\"]\",\"%d.%d.%d.%d",
&rcid, strPdpType, strApn, &ipOct[0], &ipOct[1],
&ipOct[2], &ipOct[3]);
if (!strcmp(strApn, apn)) {
// found the configuration that we want to connect to
break;
}
}
}
free(searchBuf);
sendAT(GF(
"+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
waitResponse(360000L); // Can return an error if previously not activated
sendAT(GF("+UPSD=0,100,"),
rcid); // Deactivate the PDP context associated with profile 0
waitResponse();
sendAT(GF(
"+UPSDA=0,3")); // Activate the PDP context associated with profile 0
if (waitResponse(360000L) != 1) { return false; }
sendAT(GF("+UPSD=0,0,2")); // Set protocol type to IPv4v6 with IPv4
// preferred for internal sockets
waitResponse();
return true;
}
bool gprsDisconnectImpl() {
sendAT(GF(
"+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
if (waitResponse(360000L) != 1) { return false; }
sendAT(GF("+CGATT=0")); // detach from GPRS
if (waitResponse(360000L) != 1) { return false; }
return true;
}
/*
* SIM card functions
*/
protected:
// This uses "CGSN" instead of "GSN"
String getIMEIImpl() {
sendAT(GF("+CGSN"));
if (waitResponse(GF(AT_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
/*
* Phone Call functions
*/
// Follows all phone call functions as inherited from TinyGsmCalling.tpp
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM/GPS/GNSS/GLONASS Location functions
* NOTE: u-blox modules use the same function to get location data from both
* GSM tower triangulation and from dedicated GPS/GNSS/GLONASS receivers. The
* only difference in which sensor the data is requested from. If a GNSS
* location is requested from a modem without a GNSS receiver installed on the
* I2C port, the GSM-based "Cell Locate" location will be returned instead.
*/
protected:
String inline getUbloxLocationRaw(int8_t sensor) {
// AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy>
// <mode> - 2: single shot position
// <sensor> - 0: use the last fix in the internal database and stop the GNSS
// receiver
// - 1: use the GNSS receiver for localization
// - 2: use cellular CellLocate location information
// - 3: ?? use the combined GNSS receiver and CellLocate service
// information ?? - Docs show using sensor 3 and it's
// documented for the +UTIME command but not for +ULOC
// <response_type> - 0: standard (single-hypothesis) response
// <timeout> - Timeout period in seconds
// <accuracy> - Target accuracy in meters (1 - 999999)
sendAT(GF("+ULOC=2,"), sensor, GF(",0,120,1"));
// wait for first "OK"
// waitResponse(10000L) ;
if (waitResponse(10000L) != 1) { return ""; }
// wait for the final result - wait full timeout time
if (waitResponse(120000L, GF(AT_NL "+UULOC:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
String getGsmLocationRawImpl() {
return getUbloxLocationRaw(2);
}
String getGPSrawImpl() {
return getUbloxLocationRaw(1);
}
inline bool getUbloxLocation(int8_t sensor, float* lat, float* lon,
float* speed = 0, float* alt = 0, int* vsat = 0,
int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0,
int* hour = 0, int* minute = 0,
int* second = 0) {
// AT+ULOC=<mode>,<sensor>,<response_type>,<timeout>,<accuracy>
// <mode> - 2: single shot position
// <sensor> - 2: use cellular CellLocate location information
// - 0: use the last fix in the internal database and stop the GNSS
// receiver
// - 1: use the GNSS receiver for localization
// - 3: ?? use the combined GNSS receiver and CellLocate service
// information ?? - Docs show using sensor 3 and it's documented
// for the +UTIME command but not for +ULOC
// <response_type> - 0: standard (single-hypothesis) response -> +UULOC:
// <date>,<time>,<lat>,<long>,<alt>,<uncertainty>
// 1: detailed (single-hypothesis) response -> +UULOC:
// <date>,<time>,<lat>,<long>,<alt>,<uncertainty>,<speed>,<direction>,<vertical_acc>,<sensor_used>,<SV_used>,<antenna_status>,<jamming_status>
// <timeout> - Timeout period in seconds
// <accuracy> - Target accuracy in meters (1 - 999999)
sendAT(GF("+ULOC=2,"), sensor, GF(",1,120,1"));
// wait for first "OK"
if (waitResponse(10000L) != 1) { return false; }
// wait for the final result - wait full timeout time
if (waitResponse(120000L, GF(AT_NL "+UULOC: ")) != 1) { return false; }
// +UULOC: <date>, <time>, <lat>, <long>, <alt>, <uncertainty>, <speed>,
// <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>,
// <jamming_status>
// init variables
float ilat = 0;
float ilon = 0;
float ispeed = 0;
float 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
iday = streamGetIntBefore('/'); // Two digit day
imonth = streamGetIntBefore('/'); // Two digit month
iyear = streamGetIntBefore(','); // Four digit year
ihour = streamGetIntBefore(':'); // Two digit hour
imin = streamGetIntBefore(':'); // Two digit minute
secondWithSS = streamGetFloatBefore(','); // 6 digit second with subseconds
ilat = streamGetFloatBefore(','); // Estimated latitude, in degrees
ilon = streamGetFloatBefore(','); // Estimated longitude, in degrees
ialt = streamGetFloatBefore(
','); // Estimated altitude, in meters - only forGNSS
// positioning, 0 in case of CellLocate
if (ialt != 0) { // values not returned for CellLocate
iaccuracy =
streamGetFloatBefore(','); // Maximum possible error, in meters
ispeed = streamGetFloatBefore(','); // Speed over ground m/s3
streamSkipUntil(','); // Course over ground in degree (0 deg - 360 deg)
streamSkipUntil(','); // Vertical accuracy, in meters
streamSkipUntil(','); // Sensor used for the position calculation
iusat = streamGetIntBefore(','); // Number of satellite used
streamSkipUntil(','); // Antenna status
streamSkipUntil('\n'); // Jamming status
} else {
iaccuracy =
streamGetFloatBefore('\n'); // Maximum possible error, in meters
}
// Set pointers
if (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr)
*vsat = 0; // Number of satellites viewed not reported;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
// final ok
waitResponse();
return true;
}
bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0,
int* hour = 0, int* minute = 0, int* second = 0) {
return getUbloxLocation(2, lat, lon, 0, 0, 0, 0, accuracy, year, month, day,
hour, minute, second);
}
bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
int* vsat = 0, int* usat = 0, float* accuracy = 0,
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
int* minute = 0, int* second = 0) {
return getUbloxLocation(1, lat, lon, speed, alt, vsat, usat, accuracy, year,
month, day, hour, minute, second);
}
/*
* Time functions
*/
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* Battery functions
*/
protected:
int16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercentImpl() {
sendAT(GF("+CIND?"));
if (waitResponse(GF(AT_NL "+CIND:")) != 1) { return 0; }
int8_t res = streamGetIntBefore(',');
int8_t percent = res * 20; // return is 0-5
// Wait for final OK
waitResponse();
return percent;
}
int8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
chargeState = 0;
percent = getBattPercent();
milliVolts = 0;
return true;
}
/*
* Temperature functions
*/
// This would only available for a small number of modules in this group
// (TOBY-L)
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Client related functions
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
bool ssl = false, int timeout_s = 120) {
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
uint32_t startMillis = millis();
// create a socket
sendAT(GF("+USOCR=6"));
// reply is +USOCR: ## of socket created
if (waitResponse(GF(AT_NL "+USOCR:")) != 1) { return false; }
*mux = streamGetIntBefore('\n');
waitResponse();
if (ssl) {
sendAT(GF("+USOSEC="), *mux, ",1");
waitResponse();
}
// Enable NODELAY
// AT+USOSO=<socket>,<level>,<opt_name>,<opt_val>[,<opt_val2>]
// <level> - 0 for IP, 6 for TCP, 65535 for socket level options
// <opt_name> TCP/1 = no delay (do not delay send to coalesce packets)
// NOTE: Enabling this may increase data plan usage
// sendAT(GF("+USOSO="), *mux, GF(",6,1,1"));
// waitResponse();
// Enable KEEPALIVE, 30 sec
// sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
// waitResponse();
// connect on the allocated socket
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
int8_t rsp = waitResponse(timeout_ms - (millis() - startMillis));
return (1 == rsp);
}
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+USOWR="), mux, ',', (uint16_t)len);
if (waitResponse(GF("@")) != 1) { return 0; }
// 50ms delay, see AT manual section 25.10.4
delay(50);
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(AT_NL "+USOWR:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int16_t sent = streamGetIntBefore('\n');
waitResponse(); // sends back OK after the confirmation of number sent
return sent;
}
size_t modemRead(size_t size, uint8_t mux) {
if (!sockets[mux]) return 0;
sendAT(GF("+USORD="), mux, ',', (uint16_t)size);
if (waitResponse(GF(AT_NL "+USORD:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int16_t len = streamGetIntBefore(',');
streamSkipUntil('\"');
for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); }
streamSkipUntil('\"');
waitResponse();
// DBG("### READ:", len, "from", mux);
sockets[mux]->sock_available = modemGetAvailable(mux);
return len;
}
size_t modemGetAvailable(uint8_t mux) {
if (!sockets[mux]) return 0;
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USORD="), mux, ",0");
size_t result = 0;
uint8_t res = waitResponse(GF(AT_NL "+USORD:"));
// Will give error "operation not allowed" when attempting to read a socket
// that you have already told to close
if (res == 1) {
streamSkipUntil(','); // Skip mux
result = streamGetIntBefore('\n');
// if (result) DBG("### DATA AVAILABLE:", result, "on", mux);
waitResponse();
}
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
// DBG("### Available:", result, "on", mux);
return result;
}
bool modemGetConnected(uint8_t mux) {
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USOCTL="), mux, ",10");
uint8_t res = waitResponse(GF(AT_NL "+USOCTL:"));
if (res != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type
int8_t result = streamGetIntBefore('\n');
// 0: the socket is in INACTIVE status (it corresponds to CLOSED status
// defined in RFC793 "TCP Protocol Specification" [112])
// 1: the socket is in LISTEN status
// 2: the socket is in SYN_SENT status
// 3: the socket is in SYN_RCVD status
// 4: the socket is in ESTABILISHED status
// 5: the socket is in FIN_WAIT_1 status
// 6: the socket is in FIN_WAIT_2 status
// 7: the sokcet is in CLOSE_WAIT status
// 8: the socket is in CLOSING status
// 9: the socket is in LAST_ACK status
// 10: the socket is in TIME_WAIT status
waitResponse();
return (result != 0);
}
/*
* Utilities
*/
public:
bool handleURCs(String& data) {
if (data.endsWith(GF("+UUSORD:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
// max size is 1024
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
// DBG("### URC Data Received:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+UUSOCL:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
return true;
}
return false;
}
private: // basically the same as waitResponse but without preemptive exiting
// (except when time runs out) this is used for +CGDCONT? as it can
// return multiple cid/apn configurations each terminated with OK\r\n
int8_t waitResponseUntilEndStream(uint32_t timeout_ms, String& data) {
data.reserve(1024); // buffer of the same size as in the SparkFun lib
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
}
} while (millis() - startMillis < timeout_ms);
return index;
}
public:
Stream& stream;
protected:
GsmClientSaraR5* sockets[TINY_GSM_MUX_COUNT];
};
#endif // SRC_TINYGSMCLIENTSARAR5_H_

View File

@@ -13,25 +13,31 @@
#define TINY_GSM_MUX_COUNT 6
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
enum RegStatus {
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Sequans"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "Monarch"
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmTemperature.tpp"
enum MonarchRegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -55,7 +61,7 @@ class TinyGsmSequansMonarch
: public TinyGsmModem<TinyGsmSequansMonarch>,
public TinyGsmGPRS<TinyGsmSequansMonarch>,
public TinyGsmTCP<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSequansMonarch>,
public TinyGsmSSL<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmSequansMonarch>,
public TinyGsmSMS<TinyGsmSequansMonarch>,
public TinyGsmTime<TinyGsmSequansMonarch>,
@@ -63,7 +69,7 @@ class TinyGsmSequansMonarch
friend class TinyGsmModem<TinyGsmSequansMonarch>;
friend class TinyGsmGPRS<TinyGsmSequansMonarch>;
friend class TinyGsmTCP<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSequansMonarch>;
friend class TinyGsmSSL<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmSequansMonarch>;
friend class TinyGsmSMS<TinyGsmSequansMonarch>;
friend class TinyGsmTime<TinyGsmSequansMonarch>;
@@ -191,7 +197,7 @@ class TinyGsmSequansMonarch
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSequansMonarch"));
@@ -227,7 +233,7 @@ class TinyGsmSequansMonarch
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -237,26 +243,6 @@ class TinyGsmSequansMonarch
}
}
String getModemNameImpl() {
sendAT(GF("+CGMI"));
String res1;
if (waitResponse(1000L, res1) != 1) { return "unknown"; }
res1.replace("\r\nOK\r\n", "");
res1.replace("\rOK\r", "");
res1.trim();
sendAT(GF("+CGMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return "unknown"; }
res2.replace("\r\nOK\r\n", "");
res2.replace("\rOK\r", "");
res2.trim();
String name = res1 + String(' ') + res2;
DBG("### Modem:", name);
return name;
}
bool factoryDefaultImpl() {
sendAT(GF("&F0")); // Factory
waitResponse();
@@ -276,14 +262,14 @@ class TinyGsmSequansMonarch
modemGetConnected();
}
}
while (stream.available()) { waitResponse(15, NULL, NULL); }
while (stream.available()) { waitResponse(15, nullptr, nullptr); }
}
/*
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=0"));
@@ -316,20 +302,20 @@ class TinyGsmSequansMonarch
return waitResponse() == 1;
}
bool setPhoneFunctionality(uint8_t fun,
bool reset = false) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false)
TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CEREG");
MonarchRegStatus getRegistrationStatus() {
return (MonarchRegStatus)getRegistrationStatusXREG("CEREG");
}
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
MonarchRegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
String getLocalIPImpl() {
@@ -340,12 +326,22 @@ class TinyGsmSequansMonarch
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
gprsDisconnect();
// Define the PDP context (This uses context #3!)
@@ -386,7 +382,7 @@ class TinyGsmSequansMonarch
protected:
String getSimCCIDImpl() {
sendAT(GF("+SQNCCID"));
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+SQNCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -401,17 +397,55 @@ class TinyGsmSequansMonarch
bool dtmfSendImpl(char cmd,
int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Messaging functions
* Audio functions
*/
protected:
// Follows all messaging functions per template
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
// No functions of this type supportedp
/*
* Temperature functions
@@ -428,6 +462,9 @@ class TinyGsmSequansMonarch
return res.toFloat();
}
/*
* Client related functions
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) {
@@ -486,7 +523,7 @@ class TinyGsmSequansMonarch
sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""),
",0,0,1");
rsp = waitResponse((timeout_ms - (millis() - startMillis)), GFP(GSM_OK),
GFP(GSM_ERROR), GF("NO CARRIER" GSM_NL));
GFP(GSM_ERROR), GF("NO CARRIER" AT_NL));
// creation of socket failed immediately.
if (rsp != 1) { return false; }
@@ -507,12 +544,13 @@ class TinyGsmSequansMonarch
}
sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len);
waitResponse(10000L, GF(GSM_NL "> "));
waitResponse(10000L, GF(AT_NL "> "));
// Translate bytes into char to be able to send them as an hex string
char char_command[2];
for (size_t i=0; i<len; i++) {
char char_command[3];
for (size_t i = 0; i < len; i++) {
memset(&char_command, 0, sizeof(char_command));
sprintf(&char_command[0], "%02X", reinterpret_cast<const uint8_t*>(buff)[i]);
sprintf(&char_command[0], "%02X",
reinterpret_cast<const uint8_t*>(buff)[i]);
stream.write(char_command, sizeof(char_command));
}
stream.flush();
@@ -526,7 +564,7 @@ class TinyGsmSequansMonarch
// bool gotPrompt = false;
// while (nAttempts > 0 && !gotPrompt) {
// sendAT(GF("+SQNSSEND="), mux);
// if (waitResponse(5000, GF(GSM_NL "> ")) == 1) {
// if (waitResponse(5000, GF(AT_NL "> ")) == 1) {
// gotPrompt = true;
// }
// nAttempts--;
@@ -585,7 +623,7 @@ class TinyGsmSequansMonarch
// six possible sockets.
sendAT(GF("+SQNSS"));
for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; }
if (waitResponse(GFP(GSM_OK), GF(AT_NL "+SQNSS: ")) != 2) { break; }
uint8_t status = 0;
// if (streamGetIntBefore(',') != muxNo) { // check the mux no
// DBG("### Warning: misaligned mux numbers!");
@@ -617,108 +655,29 @@ class TinyGsmSequansMonarch
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
}
data = "";
DBG("### URC Data Received:", len, "on", mux);
} else if (data.endsWith(GF("SQNSH: "))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
}
bool handleURCs(String& data) {
if (data.endsWith(GF(AT_NL "+SQNSRING:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
DBG("### URC Data Received:", len, "on", mux);
return true;
} else if (data.endsWith(GF("SQNSH: "))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -726,8 +685,8 @@ class TinyGsmSequansMonarch
protected:
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
// GSM_NL (\r\n) is not accepted with SQNSSENDEXT in data mode so use \n
const char* gsmNL = "\n";
// AT_NL (\r\n) is not accepted with SQNSSENDEXT in data mode so use \n
const char* gsmNL = "\n";
};
#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_

View File

@@ -14,27 +14,33 @@
#define TINY_GSM_MUX_COUNT 7
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r\n"
enum RegStatus {
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "u-blox"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "unknown"
#include "TinyGsmModem.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmGSMLocation.tpp"
#include "TinyGsmGPS.tpp"
#include "TinyGsmTime.tpp"
#include "TinyGsmBattery.tpp"
enum UBLOXRegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
@@ -47,7 +53,7 @@ enum RegStatus {
class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
public TinyGsmGPRS<TinyGsmUBLOX>,
public TinyGsmTCP<TinyGsmUBLOX, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmUBLOX>,
public TinyGsmSSL<TinyGsmUBLOX, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmUBLOX>,
public TinyGsmSMS<TinyGsmUBLOX>,
public TinyGsmGSMLocation<TinyGsmUBLOX>,
@@ -57,7 +63,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
friend class TinyGsmModem<TinyGsmUBLOX>;
friend class TinyGsmGPRS<TinyGsmUBLOX>;
friend class TinyGsmTCP<TinyGsmUBLOX, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmUBLOX>;
friend class TinyGsmSSL<TinyGsmUBLOX, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmUBLOX>;
friend class TinyGsmSMS<TinyGsmUBLOX>;
friend class TinyGsmGSMLocation<TinyGsmUBLOX>;
@@ -106,7 +112,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
sock_connected = at->modemConnect(host, port, &mux, false, timeout_s);
if (mux != oldMux) {
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
at->sockets[oldMux] = NULL;
at->sockets[oldMux] = nullptr;
}
at->sockets[mux] = this;
at->maintain();
@@ -143,7 +149,6 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
explicit GsmClientSecureUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 0)
: GsmClientUBLOX(modem, mux) {}
public:
int connect(const char* host, uint16_t port, int timeout_s) override {
// stop(); // DON'T stop!
TINY_GSM_YIELD();
@@ -152,7 +157,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
sock_connected = at->modemConnect(host, port, &mux, true, timeout_s);
if (mux != oldMux) {
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
at->sockets[oldMux] = NULL;
at->sockets[oldMux] = nullptr;
}
at->sockets[mux] = this;
at->maintain();
@@ -173,7 +178,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
* Basic functions
*/
protected:
bool initImpl(const char* pin = NULL) {
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientUBLOX"));
@@ -199,7 +204,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
if (ret != SIM_READY && pin != nullptr && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
} else {
@@ -211,26 +216,15 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// only difference in implementation is the warning on the wrong type
String getModemNameImpl() {
sendAT(GF("+CGMI"));
String res1;
if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; }
res1.replace(GSM_NL "OK" GSM_NL, "");
res1.trim();
sendAT(GF("+GMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.trim();
String name = res1 + String(' ') + res2;
String manufacturer = getModemManufacturer();
String model = getModemModel();
String name = manufacturer + String(" ") + model;
if (name.startsWith("u-blox SARA-R4") ||
name.startsWith("u-blox SARA-N4")) {
DBG("### WARNING: You are using the wrong TinyGSM modem!");
} else if (name.startsWith("u-blox SARA-N2")) {
DBG("### SARA N2 NB-IoT modems not supported!");
}
return name;
}
@@ -244,7 +238,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
* Power functions
*/
protected:
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!testAT()) { return false; }
if (!setPhoneFunctionality(16)) { return false; }
delay(3000); // TODO(?): Verify delay timing here
@@ -267,8 +261,8 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CGREG");
UBLOXRegStatus getRegistrationStatus() {
return (UBLOXRegStatus)getRegistrationStatusXREG("CGREG");
}
bool setRadioAccessTecnology(int selected, int preferred) {
@@ -296,7 +290,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
UBLOXRegStatus s = getRegistrationStatus();
if (s == REG_OK_HOME || s == REG_OK_ROAMING)
return true;
else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown..
@@ -307,7 +301,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
String getLocalIPImpl() {
sendAT(GF("+UPSND=0,0"));
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { return ""; }
if (waitResponse(GF(AT_NL "+UPSND:")) != 1) { return ""; }
streamSkipUntil(','); // Skip PSD profile
streamSkipUntil('\"'); // Skip request type
String res = stream.readStringUntil('\"');
@@ -315,12 +309,22 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
return res;
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
// No functions of this type supported
/*
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
// gprsDisconnect();
sendAT(GF("+CGATT=1")); // attach to GPRS
@@ -406,7 +410,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// This uses "CGSN" instead of "GSN"
String getIMEIImpl() {
sendAT(GF("+CGSN"));
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
if (waitResponse(GF(AT_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -416,14 +420,17 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
/*
* Phone Call functions
*/
protected:
// Can follow all of the phone call functions from the template
// Follows all phone call functions as inherited from TinyGsmCalling.tpp
/*
* Messaging functions
* Audio functions
*/
protected:
// Can follow all template functions
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
// Follows all text messaging (SMS) functions as inherited from TinyGsmSMS.tpp
/*
* GSM/GPS/GNSS/GLONASS Location functions
@@ -440,12 +447,12 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// <aid_mode> - 0: no aiding (default)
// <GNSS_systems> - 3: GPS + SBAS (default)
sendAT(GF("+UGPS=1,0,3"));
if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; }
if (waitResponse(10000L, GF(AT_NL "+UGPS:")) != 1) { return false; }
return waitResponse(10000L) == 1;
}
bool disableGPSImpl() {
sendAT(GF("+UGPS=0"));
if (waitResponse(10000L, GF(GSM_NL "+UGPS:")) != 1) { return false; }
if (waitResponse(10000L, GF(AT_NL "+UGPS:")) != 1) { return false; }
return waitResponse(10000L) == 1;
}
String inline getUbloxLocationRaw(int8_t sensor) {
@@ -465,7 +472,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// wait for first "OK"
if (waitResponse(10000L) != 1) { return ""; }
// wait for the final result - wait full timeout time
if (waitResponse(120000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; }
if (waitResponse(120000L, GF(AT_NL "+UULOC:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@@ -500,7 +507,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// wait for first "OK"
if (waitResponse(10000L) != 1) { return false; }
// wait for the final result - wait full timeout time
if (waitResponse(120000L, GF(GSM_NL "+UULOC: ")) != 1) { return false; }
if (waitResponse(120000L, GF(AT_NL "+UULOC: ")) != 1) { return false; }
// +UULOC: <date>, <time>, <lat>, <long>, <alt>, <uncertainty>, <speed>,
// <direction>, <vertical_acc>, <sensor_used>, <SV_used>, <antenna_status>,
@@ -549,20 +556,21 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
}
// 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 (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (speed != nullptr) *speed = ispeed;
if (alt != nullptr) *alt = ialt;
if (vsat != nullptr)
*vsat = 0; // Number of satellites viewed not reported;
if (usat != nullptr) *usat = iusat;
if (accuracy != nullptr) *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);
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = static_cast<int>(secondWithSS);
// final ok
waitResponse();
@@ -585,18 +593,27 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
// Follows all clock functions as inherited from TinyGsmTime.tpp
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercentImpl() {
sendAT(GF("+CIND?"));
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+CIND:")) != 1) { return 0; }
int8_t res = streamGetIntBefore(',');
int8_t percent = res * 20; // return is 0-5
@@ -605,10 +622,10 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
return percent;
}
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
chargeState = 0;
percent = getBattPercent();
milliVolts = 0;
@@ -618,7 +635,6 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
/*
* Temperature functions
*/
// This would only available for a small number of modules in this group
// (TOBY-L)
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
@@ -635,7 +651,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// create a socket
sendAT(GF("+USOCR=6"));
// reply is +USOCR: ## of socket created
if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { return false; }
if (waitResponse(GF(AT_NL "+USOCR:")) != 1) { return false; }
*mux = streamGetIntBefore('\n');
waitResponse();
@@ -669,7 +685,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
delay(50);
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+USOWR:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int16_t sent = streamGetIntBefore('\n');
waitResponse(); // sends back OK after the confirmation of number sent
@@ -679,7 +695,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
size_t modemRead(size_t size, uint8_t mux) {
if (!sockets[mux]) return 0;
sendAT(GF("+USORD="), mux, ',', (uint16_t)size);
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; }
if (waitResponse(GF(AT_NL "+USORD:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int16_t len = streamGetIntBefore(',');
streamSkipUntil('\"');
@@ -697,7 +713,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USORD="), mux, ",0");
size_t result = 0;
uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
uint8_t res = waitResponse(GF(AT_NL "+USORD:"));
// Will give error "operation not allowed" when attempting to read a socket
// that you have already told to close
if (res == 1) {
@@ -714,7 +730,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
bool modemGetConnected(uint8_t mux) {
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USOCTL="), mux, ",10");
uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:"));
uint8_t res = waitResponse(GF(AT_NL "+USOCTL:"));
if (res != 1) { return false; }
streamSkipUntil(','); // Skip mux
@@ -740,107 +756,28 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
* Utilities
*/
public:
// TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+UUSORD:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
// max size is 1024
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
data = "";
// DBG("### URC Data Received:", len, "on", mux);
} else if (data.endsWith(GF("+UUSOCL:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
}
bool handleURCs(String& data) {
if (data.endsWith(GF("+UUSORD:"))) {
int8_t mux = streamGetIntBefore(',');
int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
// max size is 1024
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
// DBG("### URC Data Received:", len, "on", mux);
return true;
} else if (data.endsWith(GF("+UUSOCL:"))) {
int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### URC Sock Closed: ", mux);
return true;
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
#if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = GFP(GSM_CMS_ERROR),
#else
GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
#endif
GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
return false;
}
public:
@@ -848,7 +785,6 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
protected:
GsmClientUBLOX* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif // SRC_TINYGSMCLIENTUBLOX_H_

View File

@@ -21,18 +21,29 @@
// here)
#define TINY_GSM_XBEE_GUARD_TIME 1010
#include "TinyGsmBattery.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmWifi.tpp"
#ifdef AT_NL
#undef AT_NL
#endif
#define AT_NL "\r"
#define GSM_NL "\r"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#ifdef MODEM_MANUFACTURER
#undef MODEM_MANUFACTURER
#endif
#define MODEM_MANUFACTURER "Digi"
#ifdef MODEM_MODEL
#undef MODEM_MODEL
#endif
#define MODEM_MODEL "XBee"
#include "TinyGsmModem.tpp"
#include "TinyGsmWifi.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmBattery.tpp"
// Use this to avoid too many entrances and exits from command mode.
// The cellular Bee's often freeze up and won't respond when attempting
@@ -48,7 +59,7 @@ static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
exitCommand(); \
}
enum RegStatus {
enum XBeeRegStatus {
REG_OK = 0,
REG_UNREGISTERED = 1,
REG_SEARCHING = 2,
@@ -70,7 +81,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
public TinyGsmGPRS<TinyGsmXBee>,
public TinyGsmWifi<TinyGsmXBee>,
public TinyGsmTCP<TinyGsmXBee, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmXBee>,
public TinyGsmSSL<TinyGsmXBee, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmXBee>,
public TinyGsmBattery<TinyGsmXBee>,
public TinyGsmTemperature<TinyGsmXBee> {
@@ -78,7 +89,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
friend class TinyGsmGPRS<TinyGsmXBee>;
friend class TinyGsmWifi<TinyGsmXBee>;
friend class TinyGsmTCP<TinyGsmXBee, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmXBee>;
friend class TinyGsmSSL<TinyGsmXBee, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSMS<TinyGsmXBee>;
friend class TinyGsmBattery<TinyGsmXBee>;
friend class TinyGsmTemperature<TinyGsmXBee>;
@@ -164,7 +175,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
}
size_t write(const char* str) {
if (str == NULL) return 0;
if (str == nullptr) return 0;
return write((const uint8_t*)str, strlen(str));
}
@@ -319,11 +330,12 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
// Start with the default guard time of 1 second
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool initImpl(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = nullptr) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientXBee"));
@@ -381,8 +393,44 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
return getBeeName();
}
void setBaudImpl(uint32_t baud) {
XBEE_COMMAND_START_DECORATOR(5, )
String getModemModelImpl() {
switch (beeType) {
case XBEE_S6B_WIFI: return "XBee Wi-Fi";
case XBEE_LTE1_VZN: return "XBee Cellular LTE Cat 1";
case XBEE_3G: return "XBee Cellular 3G";
case XBEE3_LTE1_ATT: return "XBee3 Cellular LTE CAT 1";
case XBEE3_LTEM_ATT: return "XBee3 Cellular LTE-M";
default: return "XBee Unknown";
}
}
// Gets the modem serial number
String getModemSerialNumberImpl() {
String xbeeSnLow =
sendATGetString(GF("SL")); // Request Module MAC/Serial Number Low
String xbeeSnHigh =
sendATGetString(GF("SH")); // Request Module MAC/Serial Number High
return xbeeSnLow + String(" ") + xbeeSnHigh;
}
// Gets the modem hardware version
String getModemHardwareVersion() {
return sendATGetString(GF("HV"));
}
// Gets the modem firmware version
String getModemFirmwareVersion() {
return sendATGetString(GF("VR"));
}
// Gets the modem combined version
String getModemRevisionImpl() {
String hw_ver = getModemHardwareVersion();
String fw_ver = getModemFirmwareVersion();
return hw_ver + String(" ") + fw_ver;
}
bool setBaudImpl(uint32_t baud) {
XBEE_COMMAND_START_DECORATOR(5, false)
bool changesMade = false;
switch (baud) {
case 2400: changesMade |= changeSettingIfNeeded(GF("BD"), 0x1); break;
@@ -404,6 +452,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
}
if (changesMade) { writeChanges(); }
XBEE_COMMAND_END_DECORATOR
return true;
}
bool testATImpl(uint32_t timeout_ms = 10000L) {
@@ -512,7 +561,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
}
}
bool restartImpl(const char* pin = NULL) {
bool restartImpl(const char* pin = nullptr) {
if (!commandMode()) {
DBG("### XBee not in command mode for restart; Exit");
return false;
@@ -610,7 +659,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
XBeeRegStatus getRegistrationStatus() {
XBEE_COMMAND_START_DECORATOR(5, REG_UNKNOWN)
if (!inCommandMode) return REG_UNKNOWN; // Return immediately
@@ -619,8 +668,8 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
getSeries(); // Need to know the bee type to interpret response
sendAT(GF("AI"));
int16_t intRes = readResponseInt(10000L);
RegStatus stat = REG_UNKNOWN;
int16_t intRes = readResponseInt(10000L);
XBeeRegStatus stat = REG_UNKNOWN;
switch (beeType) {
case XBEE_S6B_WIFI: {
@@ -730,7 +779,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
bool isNetworkConnectedImpl() {
// first check for association indicator
RegStatus s = getRegistrationStatus();
XBeeRegStatus s = getRegistrationStatus();
if (s == REG_OK) {
if (beeType == XBEE_S6B_WIFI) {
// For wifi bees, if the association indicator is ok, check that a both
@@ -803,6 +852,11 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
return TinyGsmIpFromString(getDNS());
}
/*
* Secure socket layer (SSL) functions
*/
// Follows functions as inherited from TinyGsmSSL.tpp
/*
* WiFi functions
*/
@@ -813,7 +867,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
XBEE_COMMAND_START_DECORATOR(5, false)
if (ssid == NULL) retVal = false;
if (ssid == nullptr) retVal = false;
changesMade |= changeSettingIfNeeded(GF("ID"), ssid);
@@ -856,8 +910,8 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
* GPRS functions
*/
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnectImpl(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
bool success = true;
bool changesMade = false;
XBEE_COMMAND_START_DECORATOR(5, false)
@@ -939,7 +993,17 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
}
/*
* Messaging functions
* Phone Call functions
*/
// No functions of this type supported
/*
* Audio functions
*/
// No functions of this type supported
/*
* Text messaging (SMS) functions
*/
protected:
String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE;
@@ -992,12 +1056,37 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
return true;
}
/*
* GSM Location functions
*/
// No functions of this type supported
/*
* GPS/GNSS/GLONASS location functions
*/
// No functions of this type supported
/*
* Time functions
*/
// No functions of this type supported
/*
* NTP server functions
*/
// No functions of this type supported
/*
* BLE functions
*/
// No functions of this type supported
/*
* Battery functions
*/
protected:
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
uint16_t getBattVoltageImpl() {
int16_t getBattVoltageImpl() {
int16_t intRes = 0;
XBEE_COMMAND_START_DECORATOR(5, false)
if (beeType == XBEE_UNKNOWN) getSeries();
@@ -1009,11 +1098,11 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
return intRes;
}
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
bool getBattStatsImpl(int8_t& chargeState, int8_t& percent,
int16_t& milliVolts) {
chargeState = 0;
percent = 0;
milliVolts = getBattVoltage();
@@ -1023,7 +1112,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
/*
* Temperature functions
*/
protected:
float getTemperatureImpl() {
XBEE_COMMAND_START_DECORATOR(5, static_cast<float>(-9999))
String res = sendATGetString(GF("TP"));
@@ -1256,7 +1345,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
switch (beeType) {
// The wifi be can only say if it's connected to the netowrk
case XBEE_S6B_WIFI: {
RegStatus s = getRegistrationStatus();
XBeeRegStatus s = getRegistrationStatus();
XBEE_COMMAND_END_DECORATOR
if (s != REG_OK) {
sockets[0]->sock_connected = false; // no multiplex
@@ -1314,7 +1403,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
// // Ask for information about any open sockets
// sendAT(GF("SI"));
// String open_socks = stream.readStringUntil('\r');
// open_socks.replace(GSM_NL, "");
// open_socks.replace(AT_NL, "");
// open_socks.trim();
// if (open_socks != "") {
// // In transparent mode, only socket 0 should be possible
@@ -1381,80 +1470,9 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
TINY_GSM_YIELD();
}
}
// TODO(vshymanskyy): Optimize this!
// NOTE: This function is used while INSIDE command mode, so we're only
// waiting for requested responses. The XBee has no unsoliliced responses
// (URC's) when in command mode.
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(16); // Should never be getting much here for the XBee
int8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
}
}
} while (millis() - startMillis < timeout_ms);
finish:
if (!index) {
data.trim();
data.replace(GSM_NL GSM_NL, GSM_NL);
data.replace(GSM_NL, "\r\n ");
if (data.length()) {
DBG("### Unhandled:", data, "\r\n");
} else {
DBG("### NO RESPONSE FROM MODEM!\r\n");
}
} else {
data.trim();
data.replace(GSM_NL GSM_NL, GSM_NL);
data.replace(GSM_NL, "\r\n ");
}
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5);
// The XBee has no unsoliliced responses (URC's) when in command mode.
bool handleURCs(String&) {
return false;
}
bool commandMode(uint8_t retries = 5) {
@@ -1623,7 +1641,6 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
protected:
GsmClientXBee* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
int16_t guardTime;
XBeeType beeType;
int8_t resetPin;

View File

@@ -10,7 +10,7 @@
#define SRC_TINYGSMCOMMON_H_
// The current library version number
#define TINYGSM_VERSION "0.11.7"
#define TINYGSM_VERSION "0.12.0"
#if defined(SPARK) || defined(PARTICLE)
#include "Particle.h"
@@ -80,6 +80,26 @@ static void DBG(Args... args) {
#define DBG(...)
#endif
/*
* CRTP Helper
*/
template <typename modemType, template <typename> class crtpType>
struct tinygsm_crtp {
modemType& thisModem() {
return static_cast<modemType&>(*this);
}
modemType const& thisModem() const {
return static_cast<modemType const&>(*this);
}
private:
tinygsm_crtp() {}
friend crtpType<modemType>;
};
/*
* Min/Max Helpers
*/
template <class T>
const T& TinyGsmMin(const T& a, const T& b) {
return (b < a) ? b : a;
@@ -90,6 +110,9 @@ const T& TinyGsmMax(const T& a, const T& b) {
return (b < a) ? a : b;
}
/*
* Automatically find baud rate
*/
template <class T>
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600,
uint32_t maximum = 115200) {

View File

@@ -2,140 +2,166 @@
#define TinyGsmFifo_h
template <class T, unsigned N>
class TinyGsmFifo
{
public:
TinyGsmFifo()
{
clear();
class TinyGsmFifo {
public:
/**
* @brief Construct a new Tiny Gsm Fifo object, setting the head and tail to
* 0.
*/
TinyGsmFifo() {
clear();
}
/**
* @brief Clear the FIFO - set the read and write positions to 0
*/
void clear() {
_r = 0;
_w = 0;
}
// writing thread/context API
//-------------------------------------------------------------
/**
* @brief Check if the buffer is writable - that is if it has any space left
*
* @return *true* The buffer has free space.
* @return *false* There is no space left in the buffer.
*/
bool writeable(void) {
return free() > 0;
}
/**
* @brief Check the number of free positions in the buffer.
*
* @return *int* The number number of free positions in the buffer
*/
int free(void) {
int s = _r - _w; // Check if the read is ahead of the write
if (s <= 0) s += N; // if not wrap
return s - 1; // return the difference between r and w, accounting for wrap
}
/**
* @brief Add a single item to the buffer. This is non-blocking.
*
* @param c Reference of the item of type 'T' to add to the buffer
* @return *true* The item was successfully added to the buffer
* @return *false* Nothing was added to the buffer
*/
bool put(const T& c) {
int i = _w; // check the write position
int j = i; // set the spot for the new item to the write position
i = _inc(i); // check where the next increment of the write will be
if (i == _r) // make sure the next spot isn't the position of the read (ie,
// the buffer is full)
return false;
_b[j] = c; // add the item at position j
_w = i; // bump the write position
return true;
}
/**
* @brief Add multiple items to be buffer
*
* @param p Pointer to the items to add
* @param n The number of items to add
* @param t Whether to block while waiting for space enough space to clear to
* add all items
* @return *int* The number of items successfully added
*/
int put(const T* p, int n, bool t = false) {
int c = n;
while (c) {
int f;
while ((f = free()) == 0) // wait for space
{
if (!t) return n - c; // no more space and not blocking
/* nothing / just wait */;
}
// check free space
if (c < f) f = c;
int w = _w;
int m = N - w;
// check wrap
if (f > m) f = m;
memcpy(&_b[w], p, f);
_w = _inc(w, f);
c -= f;
p += f;
}
return n - c;
}
void clear()
{
_r = 0;
_w = 0;
// reading thread/context API
// --------------------------------------------------------
bool readable(void) {
return (_r != _w);
}
size_t size(void) {
int s = _w - _r;
if (s < 0) s += N;
return s;
}
bool get(T* p) {
int r = _r;
if (r == _w) // !readable()
return false;
*p = _b[r];
_r = _inc(r);
return true;
}
int get(T* p, int n, bool t = false) {
int c = n;
while (c) {
int f;
for (;;) // wait for data
{
f = size();
if (f) break; // free space
if (!t) return n - c; // no space and not blocking
/* nothing / just wait */;
}
// check available data
if (c < f) f = c;
int r = _r;
int m = N - r;
// check wrap
if (f > m) f = m;
memcpy(p, &_b[r], f);
_r = _inc(r, f);
c -= f;
p += f;
}
return n - c;
}
// writing thread/context API
//-------------------------------------------------------------
uint8_t peek() {
return _b[_r];
}
bool writeable(void)
{
return free() > 0;
}
private:
/**
* @brief Get the next increment spot in the buffer, accounting for the size
* of each item in the buffer
*
* @param i
* @param n
* @return *int*
*/
int _inc(int i, int n = 1) {
return (i + n) % N;
}
int free(void)
{
int s = _r - _w;
if (s <= 0)
s += N;
return s - 1;
}
bool put(const T& c)
{
int i = _w;
int j = i;
i = _inc(i);
if (i == _r) // !writeable()
return false;
_b[j] = c;
_w = i;
return true;
}
int put(const T* p, int n, bool t = false)
{
int c = n;
while (c)
{
int f;
while ((f = free()) == 0) // wait for space
{
if (!t) return n - c; // no more space and not blocking
/* nothing / just wait */;
}
// check free space
if (c < f) f = c;
int w = _w;
int m = N - w;
// check wrap
if (f > m) f = m;
memcpy(&_b[w], p, f);
_w = _inc(w, f);
c -= f;
p += f;
}
return n - c;
}
// reading thread/context API
// --------------------------------------------------------
bool readable(void)
{
return (_r != _w);
}
size_t size(void)
{
int s = _w - _r;
if (s < 0)
s += N;
return s;
}
bool get(T* p)
{
int r = _r;
if (r == _w) // !readable()
return false;
*p = _b[r];
_r = _inc(r);
return true;
}
int get(T* p, int n, bool t = false)
{
int c = n;
while (c)
{
int f;
for (;;) // wait for data
{
f = size();
if (f) break; // free space
if (!t) return n - c; // no space and not blocking
/* nothing / just wait */;
}
// check available data
if (c < f) f = c;
int r = _r;
int m = N - r;
// check wrap
if (f > m) f = m;
memcpy(p, &_b[r], f);
_r = _inc(r, f);
c -= f;
p += f;
}
return n - c;
}
uint8_t peek()
{
return _b[_r];
}
private:
int _inc(int i, int n = 1)
{
return (i + n) % N;
}
T _b[N];
int _w;
int _r;
T _b[N]; /// The buffer, containing 'N' items of type 'T'
int _w; /// The write position in the buffer
int _r; /// The read position in the buffer
};
#endif

View File

@@ -22,6 +22,11 @@ enum SimStatus {
template <class modemType>
class TinyGsmGPRS {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* SIM card functions
@@ -49,8 +54,8 @@ class TinyGsmGPRS {
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
bool gprsConnect(const char* apn, const char* user = nullptr,
const char* pwd = nullptr) {
return thisModem().gprsConnectImpl(apn, user, pwd);
}
bool gprsDisconnect() {
@@ -65,6 +70,11 @@ class TinyGsmGPRS {
return thisModem().getOperatorImpl();
}
// Gets the current network provider
String getProvider() {
return thisModem().getProviderImpl();
}
/*
* CRTP Helper
*/
@@ -75,6 +85,13 @@ class TinyGsmGPRS {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmGPRS() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* SIM card functions
@@ -166,6 +183,8 @@ class TinyGsmGPRS {
thisModem().waitResponse();
return res;
}
String getProviderImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
#endif // SRC_TINYGSMGPRS_H_

View File

@@ -15,6 +15,11 @@
template <class modemType>
class TinyGsmGPS {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* GPS/GNSS/GLONASS location functions
@@ -61,6 +66,13 @@ class TinyGsmGPS {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmGPS() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* GPS/GNSS/GLONASS location functions

View File

@@ -15,6 +15,11 @@
template <class modemType>
class TinyGsmGSMLocation {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* GSM Location functions
@@ -53,6 +58,13 @@ class TinyGsmGSMLocation {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmGSMLocation() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* GSM Location functions
@@ -129,16 +141,16 @@ class TinyGsmGSMLocation {
isec = thisModem().streamGetIntBefore('\n');
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (accuracy != NULL) *accuracy = iaccuracy;
if (lat != nullptr) *lat = ilat;
if (lon != nullptr) *lon = ilon;
if (accuracy != nullptr) *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;
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = isec;
// Final OK
thisModem().waitResponse();

View File

@@ -11,89 +11,408 @@
#include "TinyGsmCommon.h"
#ifndef AT_NL
#define AT_NL "\r\n"
#endif
#ifndef AT_OK
#define AT_OK "OK"
#endif
#ifndef AT_ERROR
#define AT_ERROR "ERROR"
#endif
#if defined TINY_GSM_DEBUG
#ifndef AT_VERBOSE
#define AT_VERBOSE "+CME ERROR:"
#endif
#ifndef AT_VERBOSE_2
#define AT_VERBOSE_2 "+CMS ERROR:"
#endif
#endif
#ifndef MODEM_MANUFACTURER
#define MODEM_MANUFACTURER "unknown"
#endif
#ifndef MODEM_MODEL
#define MODEM_MODEL "unknown"
#endif
static const char GSM_OK[] TINY_GSM_PROGMEM = AT_OK AT_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = AT_ERROR AT_NL;
#if defined TINY_GSM_DEBUG
static const char GSM_VERBOSE[] TINY_GSM_PROGMEM = AT_VERBOSE;
static const char GSM_VERBOSE_2[] TINY_GSM_PROGMEM = AT_VERBOSE_2;
#endif
template <class modemType>
class TinyGsmModem {
public:
/* =========================================== */
/* =========================================== */
/*
* Basic functions
* Define the interface
*/
bool begin(const char* pin = NULL) {
public:
/**
* @anchor basic_functions
* @name Basic functions
*/
/**@{*/
/**
* @brief Sets up the GSM module
*
* @param pin A pin code to unlock the SIM, if necessary
*
* @return *true* The module was set up as expected
* @return *false* Something failed in module set up
*/
bool begin(const char* pin = nullptr) {
return thisModem().initImpl(pin);
}
bool init(const char* pin = NULL) {
/**
* @copydoc TinyGsmModem::begin()
*/
bool init(const char* pin = nullptr) {
return thisModem().initImpl(pin);
}
/**
* @brief Recursive variadic template to send AT commands
*
* @tparam Args
* @param cmd The commands to send
*/
template <typename... Args>
inline void sendAT(Args... cmd) {
thisModem().streamWrite("AT", cmd..., thisModem().gsmNL);
thisModem().streamWrite("AT", cmd..., AT_NL);
thisModem().stream.flush();
TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */
}
void setBaud(uint32_t baud) {
thisModem().setBaudImpl(baud);
/**
* @brief Set the module baud rate
*
* @param baud The baud rate the use
*
* @note After setting and applying the new baud rate, you will have to end()
* and begin() the serial object.
*/
bool setBaud(uint32_t baud) {
return thisModem().setBaudImpl(baud);
}
// Test response to AT commands
/**
* @brief Test response to AT commands
*
* @param timeout_ms The the amount of time to test for; optional with a
* default value of 10s.
* @return *true* The module responeded to AT commands
* @return *false* The module failed to respond
*/
bool testAT(uint32_t timeout_ms = 10000L) {
return thisModem().testATImpl(timeout_ms);
}
// Asks for modem information via the V.25TER standard ATI command
// NOTE: The actual value and style of the response is quite varied
/**
* @brief Listen for responses to commands and handle URCs
*
* @param timeout_ms The time to wait for a response
* @param data A string of data to fill in with response results
* @param r1 The first output to test against, optional with a default value
* of "OK"
* @param r2 The second output to test against, optional with a default value
* of "ERROR"
* @param r3 The third output to test against, optional with a default value
* of NULL
* @param r4 The fourth output to test against, optional with a default value
* of NULL
* @param r5 The fifth output to test against, optional with a default value
* of NULL
* @param r6 The sixth output to test against, optional with a default value
* of NULL
* @param r7 The seventh output to test against, optional with a default value
* of NULL
* @return *int8_t* the index of the response input
*/
int8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = nullptr,
GsmConstStr r4 = nullptr, GsmConstStr r5 = nullptr,
GsmConstStr r6 = nullptr, GsmConstStr r7 = nullptr) {
return thisModem().waitResponseImpl(timeout_ms, data, r1, r2, r3, r4, r5,
r6, r7);
}
/**
* @brief Listen for responses to commands and handle URCs
*
* @param timeout_ms The time to wait for a response
* @param r1 The first output to test against, optional with a default value
* of "OK"
* @param r2 The second output to test against, optional with a default value
* of "ERROR"
* @param r3 The third output to test against, optional with a default value
* of NULL
* @param r4 The fourth output to test against, optional with a default value
* of NULL
* @param r5 The fifth output to test against, optional with a default value
* of NULL
* @param r6 The sixth output to test against, optional with a default value
* of NULL
* @param r7 The seventh output to test against, optional with a default value
* of NULL
* @return *int8_t* the index of the response input
*/
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = nullptr,
GsmConstStr r4 = nullptr, GsmConstStr r5 = nullptr,
GsmConstStr r6 = nullptr, GsmConstStr r7 = nullptr) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6, r7);
}
/**
* @brief Listen for responses to commands and handle URCs; listening for 1
* second.
*
* @param r1 The first output to test against, optional with a default value
* of "OK"
* @param r2 The second output to test against, optional with a default value
* of "ERROR"
* @param r3 The third output to test against, optional with a default value
* of NULL
* @param r4 The fourth output to test against, optional with a default value
* of NULL
* @param r5 The fifth output to test against, optional with a default value
* of NULL
* @param r6 The sixth output to test against, optional with a default value
* of NULL
* @param r7 The seventh output to test against, optional with a default value
* of NULL
* @return *int8_t* the index of the response input
*/
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = nullptr,
GsmConstStr r4 = nullptr, GsmConstStr r5 = nullptr,
GsmConstStr r6 = nullptr, GsmConstStr r7 = nullptr) {
return waitResponse(1000L, r1, r2, r3, r4, r5, r6, r7);
}
/**
* @brief Asks for modem information via the 3GPP TS 27.007 standard ATI
* command
*
* @note The actual value and style of the response is quite varied
* @return *String* Some info about the GSM module.
*/
String getModemInfo() {
return thisModem().getModemInfoImpl();
}
// Gets the modem name (as it calls itself)
/**
* @brief Get the modem name - a combination of the manufacturer and model, as
* the modem calls itself
*
* @return *String* The modem name
*/
String getModemName() {
return thisModem().getModemNameImpl();
}
/**
* @brief Get the modem manufacturer
*
* @return *String* The modem manufacturer
*/
String getModemManufacturer() {
return thisModem().getModemManufacturerImpl();
}
/**
* @brief Get the modem model
*
* @return *String* The modem model, as it calls itself
*/
String getModemModel() {
return thisModem().getModemModelImpl();
}
/**
* @brief Get the modem revision information.
*
* What is returned as the revision may be either a hardware or a firmware
* version or some combination of both.
*
* @return *String* The modem revision information
*/
String getModemRevision() {
return thisModem().getModemRevisionImpl();
}
/**
* @brief Get the modem serial number
*
* @return *String* The modem serial number
*/
String getModemSerialNumber() {
return thisModem().getModemSerialNumberImpl();
}
/**
* @brief Reset the module to factory defaults.
*
* This generally restarts the module as well.
*
* @return *true* The module successfully reset to default.
* @return *false* The module failed to reset to default.
*/
bool factoryDefault() {
return thisModem().factoryDefaultImpl();
}
/**@}*/
/*
* Power functions
/**
* @anchor power_functions
* @name Power functions
*/
bool restart(const char* pin = NULL) {
/**@{*/
/**
* @brief Restart the module
*
* @param pin A pin code to unlock the SIM, if necessary
*
* @return *true* The module was successfully restarted.
* @return *false* There was an error in restarting the module.
*/
bool restart(const char* pin = nullptr) {
return thisModem().restartImpl(pin);
}
/**
* @brief Power off the module
*
* @return *true* The module was successfully powered down.
* @return *false* There was an error in powering down module.
*/
bool poweroff() {
return thisModem().powerOffImpl();
}
/**
* @brief Turn off the module radio
*
* @return *true* The module radio was successfully turned off.
* @return *false* There was an error in turning off the radio.
*/
bool radioOff() {
return thisModem().radioOffImpl();
}
/**
* @brief Enable sleep on the module.
*
* For some modules this immediately puts
* the module to sleep, for others this sets them to be able to sleep based on
* pin levels.
*
* @param enable True to enable sleep, false to disable
* @return *true* Sleep was successfully enabled or disabled
* @return *false* There was a problem setting sleep
*/
bool sleepEnable(bool enable = true) {
return thisModem().sleepEnableImpl(enable);
}
/**
* @brief Set the phone functionality
*
* @param fun The phone functionality setting. The value and meaning of this
* varies by module; check your documentation.
* @param reset True to reset the module before changing the functionality.
* @return *true* The phone functionalilty was successfully changed.
* @return *false* There was a problem changing the functionality.
*/
bool setPhoneFunctionality(uint8_t fun, bool reset = false) {
return thisModem().setPhoneFunctionalityImpl(fun, reset);
}
/**@}*/
/*
* Generic network functions
/**
* @anchor network_functions
* @name Generic Network Functions
*/
/**@{*/
// RegStatus getRegistrationStatus() {}
/**
* @brief Confirm whether the module is currently connected to the
* GSM/GPRS/LTE network.
*
* @return *true* The module is connected to the network
* @return *false* The module is not connected to the network
*/
bool isNetworkConnected() {
return thisModem().isNetworkConnectedImpl();
}
// Waits for network attachment
/**
* @brief Wait until the module has connected to the network
*
* @param timeout_ms The time to wait for attachment in milliseconds. Optional
* with a default value of 1 minute.
* @param check_signal True to alternate between checking for connection and
* checking the signal strength.
* @return *true* The module is now connected to the network.
* @return *false* The module did not connect to the network even after
* waiting.
*/
bool waitForNetwork(uint32_t timeout_ms = 60000L, bool check_signal = false) {
return thisModem().waitForNetworkImpl(timeout_ms, check_signal);
}
// Gets signal quality report
/**
* @brief Get the signal quality report
*
* This is often a "CSQ" value ranging from 0 to 32, but may be an RSSI or a
* percent.
*
* @return *int16_t* The signal quality
*/
int16_t getSignalQuality() {
return thisModem().getSignalQualityImpl();
}
/**
* @brief Get the Local IP address assigned to the module by the network as a
* String
*
* @return *String* The local IP address
*/
String getLocalIP() {
return thisModem().getLocalIPImpl();
}
/**
* @brief Get the Local IP address assigned to the module by the network as an
* IPAddress object.
*
* @return *IPAddress* The local IP address
*/
IPAddress localIP() {
return thisModem().TinyGsmIpFromString(thisModem().getLocalIP());
}
/**@}*/
/*
* CRTP Helper
/**
* @anchor crtp_helper
* @name CRTP Helper
*/
/**@{*/
protected:
inline const modemType& thisModem() const {
return static_cast<const modemType&>(*this);
@@ -101,154 +420,15 @@ class TinyGsmModem {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
/**@}*/
~TinyGsmModem() {}
/*
* Basic functions
*/
protected:
void setBaudImpl(uint32_t baud) {
thisModem().sendAT(GF("+IPR="), baud);
thisModem().waitResponse();
}
bool testATImpl(uint32_t timeout_ms = 10000L) {
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
thisModem().sendAT(GF(""));
if (thisModem().waitResponse(200) == 1) { return true; }
delay(100);
}
return false;
}
String getModemInfoImpl() {
thisModem().sendAT(GF("I"));
String res;
if (thisModem().waitResponse(1000L, res) != 1) { return ""; }
// Do the replaces twice so we cover both \r and \r\n type endings
res.replace("\r\nOK\r\n", "");
res.replace("\rOK\r", "");
res.replace("\r\n", " ");
res.replace("\r", " ");
res.trim();
return res;
}
String getModemNameImpl() {
thisModem().sendAT(GF("+CGMI"));
String res1;
if (thisModem().waitResponse(1000L, res1) != 1) { return "unknown"; }
res1.replace("\r\nOK\r\n", "");
res1.replace("\rOK\r", "");
res1.trim();
thisModem().sendAT(GF("+GMM"));
String res2;
if (thisModem().waitResponse(1000L, res2) != 1) { return "unknown"; }
res2.replace("\r\nOK\r\n", "");
res2.replace("\rOK\r", "");
res2.trim();
String name = res1 + String(' ') + res2;
DBG("### Modem:", name);
return name;
}
bool factoryDefaultImpl() {
thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
thisModem().waitResponse();
thisModem().sendAT(GF("+IPR=0")); // Auto-baud
thisModem().waitResponse();
thisModem().sendAT(GF("&W")); // Write configuration
return thisModem().waitResponse() == 1;
}
/*
* Power functions
*/
protected:
bool radioOffImpl() {
if (!thisModem().setPhoneFunctionality(0)) { return false; }
delay(3000);
return true;
}
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false)
TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Generic network functions
*/
protected:
// Gets the modem's registration status via CREG/CGREG/CEREG
// CREG = Generic network registration
// CGREG = GPRS service registration
// CEREG = EPS registration for LTE modules
int8_t getRegistrationStatusXREG(const char* regCommand) {
thisModem().sendAT('+', regCommand, '?');
// check for any of the three for simplicity
int8_t resp = thisModem().waitResponse(GF("+CREG:"), GF("+CGREG:"),
GF("+CEREG:"));
if (resp != 1 && resp != 2 && resp != 3) { return -1; }
thisModem().streamSkipUntil(','); /* Skip format (0) */
int status = thisModem().stream.parseInt();
thisModem().waitResponse();
return status;
}
bool waitForNetworkImpl(uint32_t timeout_ms = 60000L,
bool check_signal = false) {
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
if (check_signal) { thisModem().getSignalQuality(); }
if (thisModem().isNetworkConnected()) { return true; }
delay(250);
}
return false;
}
// Gets signal quality report according to 3GPP TS command AT+CSQ
int8_t getSignalQualityImpl() {
thisModem().sendAT(GF("+CSQ"));
if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; }
int8_t res = thisModem().streamGetIntBefore(',');
thisModem().waitResponse();
return res;
}
String getLocalIPImpl() {
thisModem().sendAT(GF("+CGPADDR=1"));
if (thisModem().waitResponse(GF("+CGPADDR:")) != 1) { return ""; }
thisModem().streamSkipUntil(','); // Skip context id
String res = thisModem().stream.readStringUntil('\r');
if (thisModem().waitResponse() != 1) { return ""; }
return res;
}
static inline IPAddress TinyGsmIpFromString(const String& strIP) {
int Parts[4] = {
0,
};
int Part = 0;
for (uint8_t i = 0; i < strIP.length(); i++) {
char c = strIP[i];
if (c == '.') {
Part++;
if (Part > 3) { return IPAddress(0, 0, 0, 0); }
continue;
} else if (c >= '0' && c <= '9') {
Parts[Part] *= 10;
Parts[Part] += c - '0';
} else {
if (Part == 3) break;
}
}
return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
}
/*
Utilities
/**
* @anchor modem_utilities
* @name Utilities
*/
/**@{*/
public:
// Utility templates for writing/skipping characters on a stream
template <typename T>
@@ -264,7 +444,7 @@ class TinyGsmModem {
inline void streamClear() {
while (thisModem().stream.available()) {
thisModem().waitResponse(50, NULL, NULL);
thisModem().waitResponse(50, nullptr, nullptr);
}
}
@@ -349,6 +529,275 @@ class TinyGsmModem {
}
return false;
}
inline void cleanResponseString(String& res) {
// Do the replaces twice so we cover both \r and \r\n type endings
res.replace("\r\nOK\r\n", "");
res.replace("\rOK\r", "");
res.replace("\r\n", " ");
res.replace("\r", " ");
res.trim();
}
static inline IPAddress TinyGsmIpFromString(const String& strIP) {
int Parts[4] = {
0,
};
int Part = 0;
for (uint8_t i = 0; i < strIP.length(); i++) {
char c = strIP[i];
if (c == '.') {
Part++;
if (Part > 3) { return IPAddress(0, 0, 0, 0); }
continue;
} else if (c >= '0' && c <= '9') {
Parts[Part] *= 10;
Parts[Part] += c - '0';
} else {
if (Part == 3) break;
}
}
return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
}
/**@}*/
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Basic functions
*/
protected:
bool initImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setBaudImpl(uint32_t baud) {
thisModem().sendAT(GF("+IPR="), baud);
return thisModem().waitResponse() == 1;
}
bool testATImpl(uint32_t timeout_ms = 10000L) {
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
thisModem().sendAT(GF(""));
if (thisModem().waitResponse(200) == 1) { return true; }
delay(100);
}
return false;
}
// TODO(vshymanskyy): Optimize this!
int8_t waitResponseImpl(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = nullptr, GsmConstStr r4 = nullptr,
GsmConstStr r5 = nullptr, GsmConstStr r6 = nullptr,
GsmConstStr r7 = nullptr) {
data.reserve(64);
#ifdef TINY_GSM_DEBUG_DEEP
DBG(GF("r1 <"), r1 ? r1 : GF("NULL"), GF("> r2 <"), r2 ? r2 : GF("NULL"),
GF("> r3 <"), r3 ? r3 : GF("NULL"), GF("> r4 <"), r4 ? r4 : GF("NULL"),
GF("> r5 <"), r5 ? r5 : GF("NULL"), GF("> r6 <"), r6 ? r6 : GF("NULL"),
GF("> r7 <"), r7 ? r7 : GF("NULL"), '>');
#endif
uint8_t index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (thisModem().stream.available() > 0) {
TINY_GSM_YIELD();
int8_t a = thisModem().stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (r6 && data.endsWith(r6)) {
index = 6;
goto finish;
} else if (r7 && data.endsWith(r7)) {
index = 7;
goto finish;
}
#if defined TINY_GSM_DEBUG
else if (data.endsWith(GFP(GSM_VERBOSE)) ||
data.endsWith(GFP(GSM_VERBOSE_2))) {
// check how long the new line is
// should be either 1 ('\r' or '\n') or 2 ("\r\n"))
int len_atnl = strnlen(AT_NL, 3);
// Read out the verbose message, until the last character of the new
// line
data += thisModem().stream.readStringUntil(AT_NL[len_atnl]);
#ifdef TINY_GSM_DEBUG_DEEP
data.trim();
DBG(GF("Verbose details <<<"), data, GF(">>>"));
#endif
data = "";
goto finish;
}
#endif
else if (thisModem().handleURCs(data)) {
data = "";
}
}
} while (millis() - startMillis < timeout_ms);
finish:
#ifdef TINY_GSM_DEBUG_DEEP
data.replace("\r", "");
data.replace("\n", "");
#endif
if (!index) {
data.trim();
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
} else {
#ifdef TINY_GSM_DEBUG_DEEP
DBG('<', index, '>', data);
#endif
}
return index;
}
String getModemInfoImpl() {
thisModem().sendAT(GF("I")); // 3GPP TS 27.007
String res;
if (thisModem().waitResponse(1000L, res) != 1) { return ""; }
thisModem().cleanResponseString(res);
return res;
}
String getModemNameImpl() {
String manufacturer = getModemManufacturer();
String model = getModemModel();
String name = manufacturer + String(" ") + model;
DBG("### Modem:", name);
return name;
}
// Gets the modem manufacturer
String getModemManufacturerImpl() {
String manufacturer = MODEM_MANUFACTURER;
thisModem().sendAT(GF("+CGMI")); // 3GPP TS 27.007 standard
String res;
if (thisModem().waitResponse(1000L, res) != 1) { return manufacturer; }
thisModem().cleanResponseString(res);
return res;
}
// Gets the modem hardware version
String getModemModelImpl() {
String model = MODEM_MODEL;
thisModem().sendAT(GF("+CGMM")); // 3GPP TS 27.007 standard
String res;
if (thisModem().waitResponse(1000L, res) != 1) { return model; }
thisModem().cleanResponseString(res);
return res;
}
// Gets the modem firmware version
String getModemRevisionImpl() {
thisModem().sendAT(GF("+CGMR")); // 3GPP TS 27.007 standard
String res;
if (thisModem().waitResponse(1000L, res) != 1) { return "unknown"; }
thisModem().cleanResponseString(res);
return res;
}
// Gets the modem serial number
String getModemSerialNumberImpl() {
thisModem().sendAT(GF("+CGSN")); // 3GPP TS 27.007 standard
String res;
if (thisModem().waitResponse(1000L, res) != 1) { return "unknown"; }
thisModem().cleanResponseString(res);
return res;
}
bool factoryDefaultImpl() {
thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
thisModem().waitResponse();
thisModem().sendAT(GF("+IPR=0")); // Auto-baud
thisModem().waitResponse();
thisModem().sendAT(GF("&W")); // Write configuration
return thisModem().waitResponse() == 1;
}
/*
* Power functions
*/
protected:
bool radioOffImpl() {
if (!thisModem().setPhoneFunctionality(0)) { return false; }
delay(3000);
return true;
}
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false)
TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Generic network functions
*/
protected:
// Gets the modem's registration status via CREG/CGREG/CEREG
// CREG = Generic network registration
// CGREG = GPRS service registration
// CEREG = EPS registration for LTE modules
int8_t getRegistrationStatusXREG(const char* regCommand) {
thisModem().sendAT('+', regCommand, '?');
// check for any of the three for simplicity
int8_t resp = thisModem().waitResponse(GF("+CREG:"), GF("+CGREG:"),
GF("+CEREG:"));
if (resp != 1 && resp != 2 && resp != 3) { return -1; }
thisModem().streamSkipUntil(','); /* Skip format (0) */
int status = thisModem().stream.parseInt();
thisModem().waitResponse();
return status;
}
bool waitForNetworkImpl(uint32_t timeout_ms = 60000L,
bool check_signal = false) {
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
if (check_signal) { thisModem().getSignalQuality(); }
if (thisModem().isNetworkConnected()) { return true; }
delay(250);
}
return false;
}
// Gets signal quality report according to 3GPP TS command AT+CSQ
int8_t getSignalQualityImpl() {
thisModem().sendAT(GF("+CSQ"));
if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; }
int8_t res = thisModem().streamGetIntBefore(',');
thisModem().waitResponse();
return res;
}
String getLocalIPImpl() {
thisModem().sendAT(GF("+CGPADDR=1"));
if (thisModem().waitResponse(GF("+CGPADDR:")) != 1) { return ""; }
thisModem().streamSkipUntil(','); // Skip context id
String res = thisModem().stream.readStringUntil('\r');
if (thisModem().waitResponse() != 1) { return ""; }
return res;
}
};
#endif // SRC_TINYGSMMODEM_H_

View File

@@ -15,12 +15,27 @@
template <class modemType>
class TinyGsmNTP {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* NTP server functions
*/
public:
byte NTPServerSync(String server = "pool.ntp.org", int TimeZone = 0) {
return thisModem().NTPServerSyncImpl(server, TimeZone);
}
String ShowNTPError(byte error) {
return thisModem().ShowNTPErrorImpl(error);
}
/*
* Utilities
*/
bool TinyGsmIsValidNumber(String str) {
if (!(str.charAt(0) == '+' || str.charAt(0) == '-' ||
isDigit(str.charAt(0))))
@@ -32,13 +47,6 @@ class TinyGsmNTP {
return true;
}
byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
return thisModem().NTPServerSyncImpl(server, TimeZone);
}
String ShowNTPError(byte error) {
return thisModem().ShowNTPErrorImpl(error);
}
/*
* CRTP Helper
*/
@@ -49,12 +57,19 @@ class TinyGsmNTP {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmNTP() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* NTP server functions
*/
protected:
byte NTPServerSyncImpl(String server = "pool.ntp.org", byte TimeZone = 3) {
byte NTPServerSyncImpl(String server = "pool.ntp.org", int TimeZone = 0) {
// Set GPRS bearer profile to associate with NTP sync
// this may fail, it's not supported by all modules
thisModem().sendAT(GF("+CNTPCID=1"));
@@ -68,6 +83,10 @@ class TinyGsmNTP {
thisModem().sendAT(GF("+CNTP"));
if (thisModem().waitResponse(10000L, GF("+CNTP:"))) {
String result = thisModem().stream.readStringUntil('\n');
// Check for ',' in case the module appends the time next to the return
// code. Eg: +CNTP: <code>[,<time>]
int index = result.indexOf(',');
if (index > 0) { result.remove(index); }
result.trim();
if (TinyGsmIsValidNumber(result)) { return result.toInt(); }
} else {

View File

@@ -15,9 +15,14 @@
template <class modemType>
class TinyGsmSMS {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Messaging functions
* Text messaging (SMS) functions
*/
String sendUSSD(const String& code) {
return thisModem().sendUSSDImpl(code);
@@ -39,9 +44,10 @@ class TinyGsmSMS {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmSMS() {}
/*
* Messaging functions
* Utilities
*/
protected:
static inline String TinyGsmDecodeHex7bit(String& instr) {
@@ -54,7 +60,7 @@ class TinyGsmSMS {
};
buf[0] = instr[i];
buf[1] = instr[i + 1];
byte b = strtol(buf, NULL, 16);
byte b = strtol(buf, nullptr, 16);
byte bb = b << (7 - bitstate);
char c = (bb + reminder) & 0x7F;
@@ -79,7 +85,7 @@ class TinyGsmSMS {
};
buf[0] = instr[i];
buf[1] = instr[i + 1];
char b = strtol(buf, NULL, 16);
char b = strtol(buf, nullptr, 16);
result += b;
}
return result;
@@ -93,7 +99,7 @@ class TinyGsmSMS {
};
buf[0] = instr[i];
buf[1] = instr[i + 1];
char b = strtol(buf, NULL, 16);
char b = strtol(buf, nullptr, 16);
if (b) { // If high byte is non-zero, we can't handle it ;(
#if defined(TINY_GSM_UNICODE_TO_HEX)
result += "\\x";
@@ -104,13 +110,23 @@ class TinyGsmSMS {
} else {
buf[0] = instr[i + 2];
buf[1] = instr[i + 3];
b = strtol(buf, NULL, 16);
b = strtol(buf, nullptr, 16);
result += b;
}
}
return result;
}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Text messaging (SMS) functions
*/
String sendUSSDImpl(const String& code) {
// Set preferred message format to text mode
thisModem().sendAT(GF("+CMGF=1"));
@@ -173,11 +189,11 @@ class TinyGsmSMS {
Print& p;
uint8_t prv = 0;
void printHex(const uint16_t v) {
uint8_t c = v >> 8;
if (c < 0x10) p.print('0');
uint8_t c = v >> 8;
if (c < 0x10) p.print('0');
p.print(c, HEX);
c = v & 0xFF;
if (c < 0x10) p.print('0');
c = v & 0xFF;
if (c < 0x10) p.print('0');
p.print(c, HEX);
}
};

View File

@@ -13,18 +13,40 @@
#define TINY_GSM_MODEM_HAS_SSL
template <class modemType>
template <class modemType, uint8_t muxCount>
class TinyGsmSSL {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* SSL functions
* Secure socket layer (SSL) functions
*/
bool addCertificate(const char* filename) {
return thisModem().addCertificateImpl(filename);
}
bool deleteCertificate() {
return thisModem().deleteCertificateImpl();
bool addCertificate(const String& filename) {
return addCertificate(filename.c_str());
}
bool addCertificate(const char* certificateName, const char* cert,
const uint16_t len) {
return thisModem().addCertificateImpl(certificateName, cert, len);
}
bool addCertificate(const String& certificateName, const String& cert,
const uint16_t len) {
return addCertificate(certificateName.c_str(), cert.c_str(), len);
}
bool deleteCertificate(const char* filename) {
return thisModem().deleteCertificateImpl(filename);
}
bool setCertificate(const String& certificateName, const uint8_t mux = 0) {
if (mux >= muxCount) return false;
certificates[mux] = certificateName;
return true;
}
/*
@@ -37,35 +59,25 @@ class TinyGsmSSL {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmSSL() {}
/* =========================================== */
/* =========================================== */
/*
* Inner Secure Client
* Define the default function implementations
*/
/*
public:
class GsmClientSecure : public GsmClient {
public:
GsmClientSecureSim800() {}
explicit GsmClientSecureSim800(TinyGsmSim800& modem, uint8_t mux = 0)
: GsmClientSim800(modem, mux) {}
public:
int connect(const char* host, uint16_t port, int timeout_s) overide {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
};*/
/*
* SSL functions
* Secure socket layer (SSL) functions
*/
protected:
bool addCertificateImpl(const char* filename) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool deleteCertificateImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool addCertificateImpl(const char* certificateName, const char* cert,
const uint16_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool
deleteCertificateImpl(const char* filename) TINY_GSM_ATTR_NOT_IMPLEMENTED;
String certificates[muxCount];
};
#endif // SRC_TINYGSMSSL_H_

View File

@@ -43,6 +43,11 @@
template <class modemType, uint8_t muxCount>
class TinyGsmTCP {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Basic functions
@@ -61,6 +66,7 @@ class TinyGsmTCP {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmTCP() {}
/*
* Inner Client
@@ -118,7 +124,7 @@ class TinyGsmTCP {
}
size_t write(const char* str) {
if (str == NULL) return 0;
if (str == nullptr) return 0;
return write((const uint8_t*)str, strlen(str));
}
@@ -241,9 +247,9 @@ class TinyGsmTCP {
return -1;
}
int peek() override {
return (uint8_t)rx.peek();
}
int peek() override {
return (uint8_t)rx.peek();
}
void flush() override {
at->stream.flush();
@@ -315,6 +321,12 @@ class TinyGsmTCP {
RxFifo rx;
};
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Basic functions
*/
@@ -331,12 +343,12 @@ class TinyGsmTCP {
}
}
while (thisModem().stream.available()) {
thisModem().waitResponse(15, NULL, NULL);
thisModem().waitResponse(15, nullptr, nullptr);
}
#elif defined TINY_GSM_NO_MODEM_BUFFER || defined TINY_GSM_BUFFER_READ_NO_CHECK
// Just listen for any URC's
thisModem().waitResponse(100, NULL, NULL);
thisModem().waitResponse(100, nullptr, nullptr);
#else
#error Modem client has been incorrectly created
@@ -345,7 +357,7 @@ class TinyGsmTCP {
// Yields up to a time-out period and then reads a character from the stream
// into the mux FIFO
// TODO(SRGDamia1): Do we need to wait two _timeout periods for no
// TODO(SRGDamia1): Do we really need to wait _two_ timeout periods for no
// character return? Will wait once in the first "while
// !stream.available()" and then will wait again in the stream.read()
// function.

View File

@@ -15,10 +15,21 @@
template <class modemType>
class TinyGsmTemperature {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Temperature functions
*/
/**
* @brief Get the modem chip temperature in degrees celsius.
*
* @return *float* The modem chip temperature in degrees celsius.
*/
float getTemperature() {
return thisModem().getTemperatureImpl();
}
@@ -33,6 +44,17 @@ class TinyGsmTemperature {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmTemperature() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Temperature functions
*/
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};

View File

@@ -17,19 +17,67 @@ enum TinyGSMDateTimeFormat { DATE_FULL = 0, DATE_TIME = 1, DATE_DATE = 2 };
template <class modemType>
class TinyGsmTime {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* Time functions
*/
/**
* @brief Get the Date Time as a String
*
* @param format The date or time part to get: DATE_FULL,
* DATE_TIME, or DATE_DATE
* @return *String* The date and/or time from the module
*/
String getGSMDateTime(TinyGSMDateTimeFormat format) {
return thisModem().getGSMDateTimeImpl(format);
}
/**
* @brief Get the date and time as parts
*
* @param year Reference to an int for the year
* @param month Reference to an int for the month
* @param day Reference to an int for the day
* @param hour Reference to an int for the hour
* @param minute Reference to an int for the minute
* @param second Reference to an int for the second
* @param timezone Reference to a float for the timezone
* @return *true* The references have been filled with valid values from the
* GSM module.
* @return *false* There was a problem getting the time from the module.
*/
bool getNetworkTime(int* year, int* month, int* day, int* hour, int* minute,
int* second, float* timezone) {
return thisModem().getNetworkTimeImpl(year, month, day, hour, minute,
second, timezone);
}
/**
* @brief Get the date and time as parts in UTC
*
* @param year Reference to an int for the year
* @param month Reference to an int for the month
* @param day Reference to an int for the day
* @param hour Reference to an int for the hour
* @param minute Reference to an int for the minute
* @param second Reference to an int for the second
* @param timezone Reference to a float for the timezone
* @return *true* The references have been filled with valid values from the
* GSM module.
* @return *false* There was a problem getting the time from the module.
*/
bool getNetworkUTCTime(int* year, int* month, int* day, int* hour,
int* minute, int* second, float* timezone) {
return thisModem().getNetworkUTCTimeImpl(year, month, day, hour, minute,
second, timezone);
}
/*
* CRTP Helper
*/
@@ -40,6 +88,13 @@ class TinyGsmTime {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmTime() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* Time functions
@@ -89,18 +144,22 @@ class TinyGsmTime {
// Set pointers
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;
if (timezone != NULL) *timezone = static_cast<float>(itimezone) / 4.0;
if (year != nullptr) *year = iyear;
if (month != nullptr) *month = imonth;
if (day != nullptr) *day = iday;
if (hour != nullptr) *hour = ihour;
if (minute != nullptr) *minute = imin;
if (second != nullptr) *second = isec;
if (timezone != nullptr) *timezone = static_cast<float>(itimezone) / 4.0;
// Final OK
thisModem().waitResponse();
return true;
}
bool getNetworkUTCTimeImpl(int* year, int* month, int* day, int* hour,
int* minute, int* second,
float* timezone) TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
#endif // SRC_TINYGSMTIME_H_

View File

@@ -15,6 +15,11 @@
template <class modemType>
class TinyGsmWifi {
/* =========================================== */
/* =========================================== */
/*
* Define the interface
*/
public:
/*
* WiFi functions
@@ -36,6 +41,13 @@ class TinyGsmWifi {
inline modemType& thisModem() {
return static_cast<modemType&>(*this);
}
~TinyGsmWifi() {}
/* =========================================== */
/* =========================================== */
/*
* Define the default function implementations
*/
/*
* WiFi functions

View File

@@ -10,11 +10,20 @@
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM868
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_SIM7000
// #define TINY_GSM_MODEM_SIM7000SSL
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_SARAR5
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -22,7 +31,9 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
@@ -43,7 +54,7 @@ SoftwareSerial SerialAT(2, 3); // RX, TX
#include <TinyGsmClient.h>
// Module baud rate
uint32_t rate = 0; // Set to 0 for Auto-Detect
uint32_t rate = 0; // Set to 0 for Auto-Detect
void setup() {
// Set console baud rate
@@ -52,17 +63,17 @@ void setup() {
}
void loop() {
if (!rate) { rate = TinyGsmAutoBaud(SerialAT); }
if (!rate) {
rate = TinyGsmAutoBaud(SerialAT);
}
if (!rate) {
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F("***********************************************************"));
SerialMon.println(F(" Module does not respond!"));
SerialMon.println(F(" Check your Serial wiring"));
SerialMon.println(F(" Check the module is correctly powered and turned on"));
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F(" Check the module is correctly powered and turned on"));
SerialMon.println(
F("***********************************************************"));
delay(30000L);
return;
}
@@ -70,19 +81,19 @@ void loop() {
SerialAT.begin(rate);
// Access AT commands from Serial Monitor
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F("***********************************************************"));
SerialMon.println(F(" You can now send AT commands"));
SerialMon.println(F(" Enter \"AT\" (without quotes), and you should see \"OK\""));
SerialMon.println(F(" If it doesn't work, select \"Both NL & CR\" in Serial Monitor"));
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F(" Enter \"AT\" (without quotes), and you should see \"OK\""));
SerialMon.println(
F(" If it doesn't work, select \"Both NL & CR\" in Serial Monitor"));
SerialMon.println(
F("***********************************************************"));
while(true) {
if (SerialAT.available()) {
SerialMon.write(SerialAT.read());
}
if (SerialMon.available()) {
SerialAT.write(SerialMon.read());
}
while (true) {
if (SerialAT.available()) { SerialMon.write(SerialAT.read()); }
if (SerialMon.available()) { SerialAT.write(SerialMon.read()); }
delay(0);
}
}

View File

@@ -19,9 +19,11 @@
// #define TINY_GSM_MODEM_SIM7080
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_A7672X
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -29,6 +31,7 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
@@ -115,9 +118,13 @@ TinyGsm modem(debugger);
TinyGsm modem(SerialAT);
#endif
#ifdef USE_SSL&& defined TINY_GSM_MODEM_HAS_SSL
TinyGsmClientSecure client(modem);
const int port = 443;
#if defined(TINY_GSM_MODEM_HAS_SSL)
#define USE_SSL
#endif
#ifdef USE_SSL
TinyGsmClientSecure client(modem);
const int port = 443;
#else
TinyGsmClient client(modem);
const int port = 80;
@@ -152,7 +159,8 @@ void loop() {
SerialMon.println(F(" Is your serial speed (baud rate) correct?"));
SerialMon.println(F(" Is your modem powered on?"));
SerialMon.println(F(" Do you use a good, stable power source?"));
SerialMon.println(F(" Try using File -> Examples -> TinyGSM -> tools -> AT_Debug to find correct configuration"));
SerialMon.println(F(" Try using File -> Examples -> TinyGSM -> tools -> "
"AT_Debug to find correct configuration"));
SerialMon.println(F("************************"));
delay(10000);
return;

View File

@@ -11,11 +11,14 @@
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM868
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
@@ -23,7 +26,9 @@
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_ESP32
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
#include <TinyGsmClient.h>
@@ -43,7 +48,7 @@ SoftwareSerial SerialAT(2, 3); // RX, TX
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
TinyGsm modem(debugger);
void setup() {
// Set console baud rate
@@ -55,22 +60,25 @@ void setup() {
delay(6000);
if (!modem.init()) {
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F("***********************************************************"));
SerialMon.println(F(" Cannot initialize modem!"));
SerialMon.println(F(" Use File -> Examples -> TinyGSM -> tools -> AT_Debug"));
SerialMon.println(
F(" Use File -> Examples -> TinyGSM -> tools -> AT_Debug"));
SerialMon.println(F(" to find correct configuration"));
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F("***********************************************************"));
return;
}
bool ret = modem.factoryDefault();
SerialMon.println(F("***********************************************************"));
SerialMon.print (F(" Return settings to Factory Defaults: "));
SerialMon.println(
F("***********************************************************"));
SerialMon.print(F(" Return settings to Factory Defaults: "));
SerialMon.println((ret) ? "OK" : "FAIL");
SerialMon.println(F("***********************************************************"));
SerialMon.println(
F("***********************************************************"));
}
void loop() {
}
void loop() {}

View File

@@ -24,13 +24,21 @@ void loop() {
modem.getModemInfo();
modem.getModemName();
modem.getModemManufacturer();
modem.getModemModel();
modem.getModemRevision();
modem.factoryDefault();
#if not defined(TINY_GSM_MODEM_ESP8266) && not defined(TINY_GSM_MODEM_ESP32)
modem.getModemSerialNumber();
#endif
// Test Power functions
modem.restart();
// modem.sleepEnable(); // Not available for all modems
// modem.radioOff(); // Not available for all modems
// modem.radioOff(); // Not available for all modems
modem.poweroff();
// modem.setPhoneFunctionality(1, 1); // Not available for all modems
// Test generic network functions
modem.getRegistrationStatus();
@@ -42,26 +50,31 @@ void loop() {
modem.getLocalIP();
modem.localIP();
// Test WiFi Functions
#if defined(TINY_GSM_MODEM_HAS_WIFI)
modem.networkConnect("mySSID", "mySSIDPassword");
modem.networkDisconnect();
#endif
// Test the GPRS and SIM card functions
#if defined(TINY_GSM_MODEM_HAS_GPRS)
modem.simUnlock("1234");
modem.getSimCCID();
modem.getIMEI();
modem.getIMSI();
modem.getSimStatus();
modem.gprsConnect("myAPN");
modem.gprsConnect("myAPN", "myUser");
modem.gprsConnect("myAPN", "myAPNUser", "myAPNPass");
modem.gprsDisconnect();
modem.getSimCCID();
modem.getIMEI();
modem.getIMSI();
modem.getOperator();
// modem.getProvider(); // Not available for all modems
#endif
// Test WiFi Functions
#if defined(TINY_GSM_MODEM_HAS_WIFI)
modem.networkConnect("mySSID", "mySSIDPassword");
modem.networkDisconnect();
#endif
char server[] = "somewhere";
char resource[] = "something";
// Test TCP functions
modem.maintain();
@@ -71,9 +84,6 @@ void loop() {
client.init(&modem);
client.init(&modem, 1);
char server[] = "somewhere";
char resource[] = "something";
client.connect(server, 80);
// Make a HTTP GET request:
@@ -92,8 +102,19 @@ void loop() {
client.stop();
#if defined(TINY_GSM_MODEM_HAS_SSL)
// modem.addCertificate(); // not yet impemented
// modem.deleteCertificate(); // not yet impemented
// modem.addCertificate("certificateName"); // Not available for all modems
// modem.addCertificate(
// String("certificateName")); // Not available for all modems
// modem.addCertificate("certificateName", "certificate_content",
// 20); // Not available for all modems
// modem.addCertificate(String("certificateName"),
// String("certificate_content"),
// 20); // Not available for all
// modems
// modem.deleteCertificate("certificateName"); // Not available for all
// modems
modem.setCertificate("certificateName", 0);
modem.setCertificate(String("certificateName"), 0);
TinyGsmClientSecure client_secure(modem);
TinyGsmClientSecure client_secure2(modem);
TinyGsmClientSecure client_secure3(modem, 1);
@@ -149,71 +170,98 @@ void loop() {
#if defined(TINY_GSM_MODEM_HAS_GSM_LOCATION) && not defined(__AVR_ATmega32U4__)
modem.getGsmLocationRaw();
modem.getGsmLocation();
float glatitude = -9999;
float glongitude = -9999;
float gacc = 0;
int gyear = 0;
int gmonth = 0;
int gday = 0;
int ghour = 0;
int gmin = 0;
int gsec = 0;
modem.getGsmLocation(&glatitude, &glongitude);
modem.getGsmLocation(&glatitude, &glongitude, &gacc, &gyear, &gmonth, &gday,
&ghour, &gmin, &gsec);
modem.getGsmLocationTime(&gyear, &gmonth, &gday, &ghour, &gmin, &gsec);
float gsm_latitude = 0;
float gsm_longitude = 0;
float gsm_accuracy = 0;
int gsm_year = 0;
int gsm_month = 0;
int gsm_day = 0;
int gsm_hour = 0;
int gsm_minute = 0;
int gsm_second = 0;
modem.getGsmLocation(&gsm_latitude, &gsm_longitude);
modem.getGsmLocation(&gsm_latitude, &gsm_longitude, &gsm_accuracy, &gsm_year,
&gsm_month, &gsm_day, &gsm_hour, &gsm_minute,
&gsm_second);
modem.getGsmLocationTime(&gsm_year, &gsm_month, &gsm_day, &gsm_hour,
&gsm_minute, &gsm_second);
modem.getGsmLocation();
#endif
// Test the GPS functions
#if defined(TINY_GSM_MODEM_HAS_GPS) && not defined(__AVR_ATmega32U4__)
// modem.setGNSSMode(1, true); // Not available for all modems
// modem.getGNSSMode(); // Not available for all modems
#if !defined(TINY_GSM_MODEM_SARAR5) // not available for this module
modem.enableGPS();
#endif
float gps_latitude = 0;
float gps_longitude = 0;
float gps_speed = 0;
float gps_altitude = 0;
int gps_vsat = 0;
int gps_usat = 0;
float gps_accuracy = 0;
int gps_year = 0;
int gps_month = 0;
int gps_day = 0;
int gps_hour = 0;
int gps_minute = 0;
int gps_second = 0;
modem.getGPS(&gps_latitude, &gps_longitude);
modem.getGPS(&gps_latitude, &gps_longitude, &gps_speed, &gps_altitude,
&gps_vsat, &gps_usat, &gps_accuracy, &gps_year, &gps_month,
&gps_day, &gps_hour, &gps_minute, &gps_second);
modem.getGPSraw();
float latitude = -9999;
float longitude = -9999;
float speed = 0;
float alt = 0;
int vsat = 0;
int usat = 0;
float acc = 0;
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minute = 0;
int second = 0;
modem.getGPS(&latitude, &longitude);
modem.getGPS(&latitude, &longitude, &speed, &alt, &vsat, &usat, &acc, &year,
&month, &day, &hour, &minute, &second);
#if !defined(TINY_GSM_MODEM_SARAR5) // not available for this module
modem.disableGPS();
#endif
#endif
// Test the Network time function
// Test the Network time functions
#if defined(TINY_GSM_MODEM_HAS_NTP) && not defined(__AVR_ATmega32U4__)
modem.NTPServerSync("pool.ntp.org", 3);
// modem.ShowNTPError(1); // Not available for all modems
#endif
// Test the Network time function
#if defined(TINY_GSM_MODEM_HAS_TIME) && not defined(__AVR_ATmega32U4__)
modem.getGSMDateTime(DATE_FULL);
int year3 = 0;
int month3 = 0;
int day3 = 0;
int hour3 = 0;
int min3 = 0;
int sec3 = 0;
float timezone = 0;
modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3, &timezone);
int ntp_year = 0;
int ntp_month = 0;
int ntp_day = 0;
int ntp_hour = 0;
int ntp_min = 0;
int ntp_sec = 0;
float ntp_timezone = 0;
modem.getNetworkTime(&ntp_year, &ntp_month, &ntp_day, &ntp_hour, &ntp_min,
&ntp_sec, &ntp_timezone);
// modem.getNetworkUTCTime(&ntp_year, &ntp_month, &ntp_day, &ntp_hour,
// &ntp_min,
// &ntp_sec,
// &ntp_timezone); // Not available for all modems
#endif
// Test bluetooth functions
#if defined(TINY_GSM_MODEM_HAS_BLUETOOTH)
modem.enableBluetooth();
modem.disableBluetooth();
modem.setBluetoothVisibility(true);
modem.setBluetoothHostName("bluetooth");
#endif
// Test Battery functions
#if defined(TINY_GSM_MODEM_HAS_BATTERY)
uint8_t chargeState = 0;
int8_t chargePercent = 0;
uint16_t milliVolts = 0;
// modem.getBattVoltage(); // Not available for all modems
// modem.getBattPercent(); // Not available for all modems
// modem.getBattChargeState(); // Not available for all modems
int8_t chargeState = -99;
int8_t chargePercent = -99;
int16_t milliVolts = -9999;
modem.getBattStats(chargeState, chargePercent, milliVolts);
#endif
// Test the temperature function
// Test temperature functions
#if defined(TINY_GSM_MODEM_HAS_TEMPERATURE)
modem.getTemperature();
#endif