mirror of
https://github.com/vshymanskyy/TinyGSM.git
synced 2026-05-15 04:06:10 +00:00
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -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
|
||||
|
||||
75
.github/workflows/build_examples_platformio.yaml
vendored
75
.github/workflows/build_examples_platformio.yaml
vendored
@@ -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
3
.gitignore
vendored
@@ -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
60
ChangeLog.md
Normal 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
|
||||
|
||||
***
|
||||
38
README.md
38
README.md
@@ -17,7 +17,7 @@ If you like **TinyGSM** - give it a star, or fork it and contribute!
|
||||
[](https://github.com/vshymanskyy/TinyGSM/network)
|
||||
|
||||
You can also join our chat:
|
||||
[](https://gitter.im/tinygsm)
|
||||
[](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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(',');
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
775
src/TinyGsmClientA7672x.h
Normal 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_
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
823
src/TinyGsmClientSaraR5.h
Normal 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_
|
||||
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user