Compare commits
106 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
04dacd4ed9 | ||
|
92c0ba3721 | ||
|
318fa45bee | ||
|
c2de83b4ca | ||
|
b65f1c1e14 | ||
|
5b83997877 | ||
|
ef1a7e08a1 | ||
|
78425a5514 | ||
|
8a84350181 | ||
|
d70f005b98 | ||
|
8d60810efe | ||
|
3d384e5435 | ||
|
dcc2f9cd63 | ||
|
01dbc023b9 | ||
|
77f285bee2 | ||
|
b96d401e20 | ||
|
191b3b1209 | ||
|
a423350ff2 | ||
|
8a911b218c | ||
|
ef1337aada | ||
|
80d25de1c7 | ||
|
daf1063344 | ||
|
3356c1d5c7 | ||
|
03e647ab5b | ||
|
b381fa5c74 | ||
|
f8c8e2c432 | ||
|
47793e0ad9 | ||
|
cce063cf88 | ||
|
132844d1e1 | ||
|
feb3a22629 | ||
|
f3dd62630b | ||
|
0622616c51 | ||
|
2f0b7978be | ||
|
b3fc9eedae | ||
|
09e679e943 | ||
|
a57014d0e6 | ||
|
a092bfa636 | ||
|
4d722a34f2 | ||
|
a5a2ce3453 | ||
|
8b25d8c1d9 | ||
|
e5131eae7d | ||
|
c9ebf60e3c | ||
|
b6a86862cb | ||
|
516db057b5 | ||
|
a0d246be80 | ||
|
6e10a3a009 | ||
|
60a88ef89e | ||
|
78130df146 | ||
|
f508e78b4e | ||
|
4f9d284030 | ||
|
4dc0fa2abd | ||
|
1e4ecae77d | ||
|
07b402721d | ||
|
70af3cf488 | ||
|
cad8f7a61a | ||
|
db756813d4 | ||
|
6e64e867ec | ||
|
b5c5a62b2d | ||
|
644085b30e | ||
|
0879deab70 | ||
|
4eedb84cd3 | ||
|
243afe7245 | ||
|
93fc96d9ec | ||
|
9128baeb27 | ||
|
459106a854 | ||
|
68a03b3ba0 | ||
|
9af0acc18b | ||
|
0094193049 | ||
|
ecca37d778 | ||
|
8766eac978 | ||
|
2d603d600e | ||
|
4fc428c945 | ||
|
38a712500e | ||
|
b22aa854d6 | ||
|
a9f723130c | ||
|
772f33636e | ||
|
75104a49c3 | ||
|
51f4da58e5 | ||
|
f6d7480a69 | ||
|
d3944ecc8b | ||
|
b1f81f485e | ||
|
750108ee09 | ||
|
c1d6abaff7 | ||
|
7f19c69554 | ||
|
28f7e7b298 | ||
|
f0abeef22d | ||
|
b8a54d37e0 | ||
|
57895868f2 | ||
|
57514b7c4d | ||
|
7cf19beb44 | ||
|
0be9622e9c | ||
|
81f583a80f | ||
|
9498800b50 | ||
|
f20293905f | ||
|
1291a4407d | ||
|
98d67a4155 | ||
|
eb9c1f7786 | ||
|
7f2900b278 | ||
|
b0e363c536 | ||
|
88320025ec | ||
|
54c25cce23 | ||
|
a51cfda25d | ||
|
31bb5cbeed | ||
|
ba778adb74 | ||
|
f6d636274f | ||
|
23742b4b9c |
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.10.9) -->
|
||||
TinyGSM version: <!-- always try to use the latest (0.11.7) -->
|
||||
Code: <!-- Example name or paste in your code -->
|
||||
|
||||
### Scenario, steps to reproduce
|
||||
|
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
labels:
|
||||
- 'CI/CD'
|
||||
commit-message:
|
||||
prefix: ci
|
91
.github/workflows/build_examples_platformio.yaml
vendored
Normal file
91
.github/workflows/build_examples_platformio.yaml
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
name: Build Examples with PlatformIO
|
||||
|
||||
# Triggers the workflow on push or pull request events
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
example:
|
||||
[
|
||||
examples/BlynkClient,
|
||||
examples/FileDownload,
|
||||
examples/MqttClient,
|
||||
examples/WebClient,
|
||||
tools/test_build,
|
||||
tools/Diagnostics,
|
||||
]
|
||||
modem:
|
||||
[
|
||||
TINY_GSM_MODEM_A6,
|
||||
TINY_GSM_MODEM_BG96,
|
||||
TINY_GSM_MODEM_ESP8266,
|
||||
TINY_GSM_MODEM_M95,
|
||||
TINY_GSM_MODEM_M590,
|
||||
TINY_GSM_MODEM_MC60,
|
||||
TINY_GSM_MODEM_SIM800,
|
||||
TINY_GSM_MODEM_SIM808,
|
||||
TINY_GSM_MODEM_SIM5360,
|
||||
TINY_GSM_MODEM_SIM7600,
|
||||
TINY_GSM_MODEM_SIM7000,
|
||||
TINY_GSM_MODEM_SIM7000SSL,
|
||||
TINY_GSM_MODEM_SIM7070,
|
||||
TINY_GSM_MODEM_UBLOX,
|
||||
TINY_GSM_MODEM_SARAR4,
|
||||
TINY_GSM_MODEM_XBEE,
|
||||
TINY_GSM_MODEM_SEQUANS_MONARCH,
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set variables
|
||||
run: |
|
||||
if [[ -z "${GITHUB_HEAD_REF}" ]]; then
|
||||
echo "::debug::Push to commit ${GITHUB_SHA}"
|
||||
echo "LIBRARY_INSTALL_SOURCE=https://github.com/${GITHUB_REPOSITORY}.git#${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "::debug::Pull Request from the ${GITHUB_HEAD_REF} branch"
|
||||
echo "LIBRARY_INSTALL_SOURCE=https://github.com/${GITHUB_REPOSITORY}.git#${GITHUB_HEAD_REF}" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
# This should be pulled from cache, if there's not a new version
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
|
||||
- name: Restore or Cache Platforms and Libraries
|
||||
uses: actions/cache@v3.3.1
|
||||
id: cache_pio
|
||||
with:
|
||||
path: ~/.platformio
|
||||
# if nothing in the example_dependencies.json file has changed, then it will
|
||||
# be a "cache hit" and we can restore libraries from cache and not
|
||||
# download them. If it has changed we have to re-download.
|
||||
key: ${{ hashFiles('./examples/example_dependencies.json') }}
|
||||
|
||||
# Install cores and library dependencies for the Arduino CLI, iff no cache
|
||||
- name: Install the Arduino libraries
|
||||
if: steps.cache_pio.outputs.cache-hit != 'true'
|
||||
run: pio lib --global install 89 415 1202 1286
|
||||
|
||||
- name: Run PlatformIO
|
||||
env:
|
||||
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 }}
|
||||
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
|
95
README.md
95
README.md
@@ -1,3 +1,5 @@
|
||||
[](https://vshymanskyy.github.io/StandWithUkraine)
|
||||
|
||||

|
||||
|
||||
A small Arduino library for GSM modules, that just works.
|
||||
@@ -17,6 +19,32 @@ If you like **TinyGSM** - give it a star, or fork it and contribute!
|
||||
You can also join our chat:
|
||||
[](https://gitter.im/tinygsm)
|
||||
|
||||
- [Supported modems](#supported-modems)
|
||||
- [Supported boards/modules](#supported-boardsmodules)
|
||||
- [Features](#features)
|
||||
- [Getting Started](#getting-started)
|
||||
- [First Steps](#first-steps)
|
||||
- [Writing your own code](#writing-your-own-code)
|
||||
- [If you have any issues](#if-you-have-any-issues)
|
||||
- [How does it work?](#how-does-it-work)
|
||||
- [API Reference](#api-reference)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [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)
|
||||
- [Diagnostics sketch](#diagnostics-sketch)
|
||||
- [Web request formatting problems - "but it works with PostMan"](#web-request-formatting-problems---but-it-works-with-postman)
|
||||
- [SoftwareSerial problems](#softwareserial-problems)
|
||||
- [ESP32 Notes](#esp32-notes)
|
||||
- [HardwareSerial](#hardwareserial)
|
||||
- [HttpClient](#httpclient)
|
||||
- [SAMD21](#samd21)
|
||||
- [Goouuu Tech IOT-GA6 vs AI-Thinker A6 confusion](#goouuu-tech-iot-ga6-vs-ai-thinker-a6-confusion)
|
||||
- [SIM800 and SSL](#sim800-and-ssl)
|
||||
- [Which version of the SIM7000 code to use](#which-version-of-the-sim7000-code-to-use)
|
||||
- [License](#license)
|
||||
|
||||
### Arduino Client interface support
|
||||
This library is easy to integrate with lots of sketches which use Ethernet or WiFi.
|
||||
**PubSubClient ([MQTT](http://mqtt.org/))**, **[Blynk](http://blynk.cc)**, **HTTP Client** and **File Download** examples are provided.
|
||||
@@ -41,8 +69,9 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
|
||||
- SIMCom WCDMA/HSPA/HSPA+ Modules (SIM5360, SIM5320, SIM5300E, SIM5300E/A)
|
||||
- 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
|
||||
- AI-Thinker A6, A6C, A7, A20
|
||||
- ESP8266 (AT commands interface, similar to GSM modems)
|
||||
- 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)
|
||||
@@ -86,7 +115,8 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
||||
- Sequans Monarch - 6
|
||||
- SIM 800/900 - 5
|
||||
- SIM 5360/5320/5300/7100 - 10
|
||||
- SIM7000 - 8
|
||||
- SIM7000 - 8 possible without SSL, only 2 with
|
||||
- SIM 7070/7080/7090 - 12
|
||||
- SIM 7500/7600/7800 - 10
|
||||
- u-blox 2G/3G - 7
|
||||
- u-blox SARA R4/N4 - 7
|
||||
@@ -95,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, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
|
||||
- Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
|
||||
- SIM800, SIM7000, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
|
||||
- Note: **only some device models or firmware revisions have this feature** (SIM8xx R14.18, A7, etc.)
|
||||
- Not yet supported on:
|
||||
- Quectel modems, SIM7000, SIM 5360/5320/7100, SIM 7500/7600/7800
|
||||
- Quectel modems, 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
|
||||
@@ -117,9 +147,9 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
||||
|
||||
**Voice Calls**
|
||||
- Supported on:
|
||||
- SIM800/SIM900, A6/A7, Quectel modems, u-blox
|
||||
- SIM800/SIM900, SIM7600, A6/A7, Quectel modems, u-blox
|
||||
- Not yet supported on:
|
||||
- SIM7000, SIM5360/5320/7100, SIM7500/7600/7800, VZM20Q (Monarch)
|
||||
- SIM7000, SIM5360/5320/7100, SIM7500/7800, VZM20Q (Monarch)
|
||||
- Not possible on:
|
||||
- XBee (any type), u-blox SARA R4/N4, Neoway M590, ESP8266 (obviously)
|
||||
- Functions:
|
||||
@@ -129,7 +159,7 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
||||
**Location**
|
||||
- GPS/GNSS
|
||||
- SIM808, SIM7000, SIM7500/7600/7800, BG96, u-blox
|
||||
- NOTE: u-blox chips do _NOT_ have embedded GPS - this function only works if a secondary GPS is connected to primary cellular chip over I2C
|
||||
- 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
|
||||
|
||||
@@ -139,6 +169,7 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
||||
- [SRGDamia1](https://github.com/SRGDamia1/)
|
||||
- SIM7000:
|
||||
- [captFuture](https://github.com/captFuture/)
|
||||
- [FStefanni](https://github.com/FStefanni/)
|
||||
- Sequans Monarch:
|
||||
- [nootropicdesign](https://github.com/nootropicdesign/)
|
||||
- Quectel M9C60
|
||||
@@ -205,8 +236,7 @@ The general flow of your code should be:
|
||||
- Send out your data.
|
||||
|
||||
|
||||
|
||||
#### If you have any issues:
|
||||
#### If you have any issues
|
||||
|
||||
1. Read the whole README (you're looking at it!), particularly the troubleshooting section below.
|
||||
2. Some boards require [**special configuration**](https://github.com/vshymanskyy/TinyGSM/wiki/Board-configuration).
|
||||
@@ -219,6 +249,15 @@ The general flow of your code should be:
|
||||
Many GSM modems, WiFi and radio modules can be controlled by sending AT commands over Serial.
|
||||
TinyGSM knows which commands to send, and how to handle AT responses, and wraps that into standard Arduino Client interface.
|
||||
|
||||
This library is "blocking" in all of its communication.
|
||||
Depending on the function, your code may be blocked for a long time waiting for the module responses.
|
||||
Apart from the obvious (ie, `waitForNetwork()`) several other functions may block your code for up to several *minutes*.
|
||||
The `gprsConnect()` and `client.connect()` functions commonly block the longest, especially in poorer service regions.
|
||||
The module shutdown and restart may also be quite slow.
|
||||
|
||||
This libary *does not* support any sort of "hardware" or pin level controls for the modules.
|
||||
If you need to turn your module on or reset it using some sort of High/Low/High pin sequence, you must write those functions yourself.
|
||||
|
||||
## API Reference
|
||||
|
||||
For GPRS data streams, this library provides the standard [Arduino Client](https://www.arduino.cc/en/Reference/ClientConstructor) interface.
|
||||
@@ -237,6 +276,13 @@ Improving the power supply actually solves stability problems in **many** cases!
|
||||
- Do not put your wires next to noisy signal sources (buck converters, antennas, oscillators etc.)
|
||||
- If everything else seems to be working but you are unable to connect to the network, check your power supply!
|
||||
|
||||
### Baud rates
|
||||
|
||||
Most modules support some sort of "auto-bauding" feature where the module will attempt to adjust it's baud rate to match what it is receiving.
|
||||
TinyGSM also implements its own auto bauding function (`TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);`).
|
||||
While very useful when initially connecting to a module and doing tests, these should **NOT** be used in any sort of production code.
|
||||
Once you've established communication with the module, set the baud rate using the `setBaud(#)` function and stick with that rate.
|
||||
|
||||
### Broken initial configuration
|
||||
|
||||
Sometimes (especially if you played with AT commands), your module configuration may become invalid.
|
||||
@@ -255,6 +301,15 @@ Try using the ```gprsConnect(APN)``` function to set an initial APN if you are u
|
||||
You may need set the APN again after registering.
|
||||
(In most cases, you should set the APN after registration.)
|
||||
|
||||
### Failed connection or no data received
|
||||
|
||||
The first connection with a new SIM card, a new module, or at a new location/tower may take a *LONG* time - up to 15 minutes or even more, especially if the signal quality isn't excellent.
|
||||
If it is your first connection, you may need to adjust your wait times and possibly go to lunch while you're waiting.
|
||||
|
||||
If you are able to open a TCP connection but have the connection close before receiving data, try adding a keep-alive header to your request.
|
||||
Some modules (ie, the SIM7000 in SSL mode) will immediately throw away any un-read data when the remote server closes the connection - sometimes without even giving a notification that data arrived in the first place.
|
||||
When using MQTT, to keep a continuous connection you may need to reduce your keep-alive interval (PINGREQ/PINGRESP).
|
||||
|
||||
### Diagnostics sketch
|
||||
|
||||
Use this sketch to help diagnose SIM card and GPRS connection issues:
|
||||
@@ -337,8 +392,26 @@ Please [refer to this comment](https://github.com/vshymanskyy/TinyGSM/issues/102
|
||||
|
||||
It turns out that **Goouuu Tech IOT-GA6** is not the same as **AI-Thinker A6**. Unfortunately IOT-GA6 is not supported out of the box yet. There are some hints that IOT-GA6 firmware may be updated to match A6... See [this topic](https://github.com/vshymanskyy/TinyGSM/issues/164).
|
||||
|
||||
### SIM800 and SSL
|
||||
|
||||
Some, but not all, versions of the SIM800 support SSL.
|
||||
Having SSL support depends on the firmware version and the individual module.
|
||||
Users have had varying levels of success in using SSL on the SIM800 even with apparently identical firmware.
|
||||
If you need SSL and it does not appear to be working on your SIM800, try a different module or try using a secondary SSL library.
|
||||
|
||||
### Which version of the SIM7000 code to use
|
||||
|
||||
There are two versions of the SIM7000 code, one using `TINY_GSM_MODEM_SIM7000` and another with `TINY_GSM_MODEM_SIM7000SSL`.
|
||||
The `TINY_GSM_MODEM_SIM7000` version *does not support SSL* but supports up to 8 simultaneous connections.
|
||||
The `TINY_GSM_MODEM_SIM7000SSL` version supports both SSL *and unsecured connections* with up to 2 simultaneous connections.
|
||||
So why are there two versions?
|
||||
The "SSL" version uses the SIM7000's "application" commands while the other uses the "TCP-IP toolkit".
|
||||
Depending on your region/firmware, one or the other may not work for you.
|
||||
Try both and use whichever is more stable.
|
||||
If you do not need SSL, I recommend starting with `TINY_GSM_MODEM_SIM7000`.
|
||||
|
||||
__________
|
||||
|
||||
### License
|
||||
## License
|
||||
This project is released under
|
||||
The GNU Lesser General Public License (LGPL-3.0)
|
||||
|
@@ -15,6 +15,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -35,11 +37,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
// #include <SoftwareSerial.h>
|
||||
// SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
// #define DUMP_AT_COMMANDS
|
||||
@@ -48,9 +53,15 @@
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
|
||||
// Range to attempt to autobaud
|
||||
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
|
||||
// communication, set a fixed baud rate using modem.setBaud(#).
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 57600
|
||||
|
||||
// Add a reception delay, if needed.
|
||||
// This may be needed for a fast processor at a slow baud rate.
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
/*
|
||||
* Tests enabled
|
||||
*/
|
||||
@@ -58,16 +69,17 @@
|
||||
#define TINY_GSM_TEST_WIFI false
|
||||
#define TINY_GSM_TEST_TCP true
|
||||
#define TINY_GSM_TEST_SSL true
|
||||
// #define TINY_GSM_TEST_CALL true
|
||||
// #define TINY_GSM_TEST_SMS true
|
||||
// #define TINY_GSM_TEST_USSD true
|
||||
#define TINY_GSM_TEST_CALL false
|
||||
#define TINY_GSM_TEST_SMS false
|
||||
#define TINY_GSM_TEST_USSD false
|
||||
#define TINY_GSM_TEST_BATTERY true
|
||||
#define TINY_GSM_TEST_TEMPERATURE true
|
||||
#define TINY_GSM_TEST_GSM_LOCATION true
|
||||
#define TINY_GSM_TEST_TIME 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
|
||||
// powerdown modem after tests
|
||||
#define TINY_GSM_POWERDOWN true
|
||||
// disconnect and power down modem after tests
|
||||
#define TINY_GSM_POWERDOWN false
|
||||
|
||||
// set GSM PIN, if any
|
||||
#define GSM_PIN ""
|
||||
@@ -87,7 +99,7 @@ const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details to test TCP/SSL
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char resource[] = "/TinyGSM/logo.txt";
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
@@ -106,11 +118,11 @@ const char resource[] = "/TinyGSM/logo.txt";
|
||||
#endif
|
||||
|
||||
#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() {
|
||||
@@ -120,17 +132,6 @@ void setup() {
|
||||
|
||||
// !!!!!!!!!!!
|
||||
// Set your reset, enable, power pins here
|
||||
pinMode(A5, OUTPUT);
|
||||
DBG("Pin HIGH");
|
||||
digitalWrite(A5, HIGH);
|
||||
delay(5000);
|
||||
DBG("Pin LOW");
|
||||
digitalWrite(A5, LOW);
|
||||
delay(1300);
|
||||
digitalWrite(A5, HIGH);
|
||||
DBG("Pin HIGH");
|
||||
// pinMode(20, OUTPUT);
|
||||
// digitalWrite(20, HIGH);
|
||||
// !!!!!!!!!!!
|
||||
|
||||
DBG("Wait...");
|
||||
@@ -161,9 +162,7 @@ void loop() {
|
||||
|
||||
#if TINY_GSM_TEST_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_WIFI
|
||||
@@ -182,14 +181,12 @@ void loop() {
|
||||
#endif
|
||||
|
||||
DBG("Waiting for network...");
|
||||
if (!modem.waitForNetwork(600000L)) {
|
||||
if (!modem.waitForNetwork(600000L, true)) {
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (modem.isNetworkConnected()) {
|
||||
DBG("Network connected");
|
||||
}
|
||||
if (modem.isNetworkConnected()) { DBG("Network connected"); }
|
||||
|
||||
#if TINY_GSM_TEST_GPRS
|
||||
DBG("Connecting to", apn);
|
||||
@@ -230,8 +227,8 @@ void loop() {
|
||||
|
||||
#if TINY_GSM_TEST_TCP && defined TINY_GSM_MODEM_HAS_TCP
|
||||
TinyGsmClient client(modem, 0);
|
||||
const int port = 80;
|
||||
DBG("Connecting to ", server);
|
||||
const int port = 80;
|
||||
DBG("Connecting to", server);
|
||||
if (!client.connect(server, port)) {
|
||||
DBG("... failed");
|
||||
} else {
|
||||
@@ -248,21 +245,29 @@ void loop() {
|
||||
};
|
||||
|
||||
// Read data
|
||||
start = millis();
|
||||
while (client.connected() && millis() - start < 5000L) {
|
||||
start = millis();
|
||||
char logo[640] = {
|
||||
'\0',
|
||||
};
|
||||
int read_chars = 0;
|
||||
while (client.connected() && millis() - start < 10000L) {
|
||||
while (client.available()) {
|
||||
SerialMon.write(client.read());
|
||||
logo[read_chars] = client.read();
|
||||
logo[read_chars + 1] = '\0';
|
||||
read_chars++;
|
||||
start = millis();
|
||||
}
|
||||
}
|
||||
SerialMon.println(logo);
|
||||
DBG("##### RECEIVED:", strlen(logo), "CHARACTERS");
|
||||
client.stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL
|
||||
TinyGsmClientSecure secureClient(modem, 1);
|
||||
const int securePort = 443;
|
||||
DBG("Connecting to ", server);
|
||||
const int securePort = 443;
|
||||
DBG("Connecting securely to", server);
|
||||
if (!secureClient.connect(server, securePort)) {
|
||||
DBG("... failed");
|
||||
} else {
|
||||
@@ -279,19 +284,27 @@ void loop() {
|
||||
};
|
||||
|
||||
// Read data
|
||||
startS = millis();
|
||||
while (secureClient.connected() && millis() - startS < 5000L) {
|
||||
startS = millis();
|
||||
char logoS[640] = {
|
||||
'\0',
|
||||
};
|
||||
int read_charsS = 0;
|
||||
while (secureClient.connected() && millis() - startS < 10000L) {
|
||||
while (secureClient.available()) {
|
||||
SerialMon.write(secureClient.read());
|
||||
logoS[read_charsS] = secureClient.read();
|
||||
logoS[read_charsS + 1] = '\0';
|
||||
read_charsS++;
|
||||
startS = millis();
|
||||
}
|
||||
}
|
||||
SerialMon.println(logoS);
|
||||
DBG("##### RECEIVED:", strlen(logoS), "CHARACTERS");
|
||||
secureClient.stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \
|
||||
defined CALL_TARGET
|
||||
defined CALL_TARGET
|
||||
DBG("Calling:", CALL_TARGET);
|
||||
|
||||
// This is NOT supported on M590
|
||||
@@ -305,9 +318,7 @@ void loop() {
|
||||
modem.dtmfSend('A', 1000);
|
||||
|
||||
// Play DTMF 0..4, default duration (100ms)
|
||||
for (char tone = '0'; tone <= '4'; tone++) {
|
||||
modem.dtmfSend(tone);
|
||||
}
|
||||
for (char tone = '0'; tone <= '4'; tone++) { modem.dtmfSend(tone); }
|
||||
|
||||
delay(5000);
|
||||
|
||||
@@ -341,7 +352,7 @@ void loop() {
|
||||
int day = 0;
|
||||
int hour = 0;
|
||||
int min = 0;
|
||||
int sec = 0;
|
||||
int sec = 0;
|
||||
for (int8_t i = 15; i; i--) {
|
||||
DBG("Requesting current GSM location");
|
||||
if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
|
||||
@@ -381,7 +392,7 @@ void loop() {
|
||||
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)) {
|
||||
&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);
|
||||
@@ -401,18 +412,23 @@ void loop() {
|
||||
modem.disableGPS();
|
||||
#endif
|
||||
|
||||
#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);
|
||||
#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;
|
||||
int year3 = 0;
|
||||
int month3 = 0;
|
||||
int day3 = 0;
|
||||
int hour3 = 0;
|
||||
int min3 = 0;
|
||||
int sec3 = 0;
|
||||
float timezone = 0;
|
||||
for (int8_t i = 5; i; i--) {
|
||||
DBG("Requesting current network time");
|
||||
if (modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3,
|
||||
&timezone)) {
|
||||
&timezone)) {
|
||||
DBG("Year:", year3, "\tMonth:", month3, "\tDay:", day3);
|
||||
DBG("Hour:", hour3, "\tMinute:", min3, "\tSecond:", sec3);
|
||||
DBG("Timezone:", timezone);
|
||||
@@ -427,21 +443,6 @@ void loop() {
|
||||
DBG("Current Network Time:", time);
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_GPRS
|
||||
modem.gprsDisconnect();
|
||||
delay(5000L);
|
||||
if (!modem.isGprsConnected()) {
|
||||
DBG("GPRS disconnected");
|
||||
} else {
|
||||
DBG("GPRS disconnect: Failed.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_WIFI
|
||||
modem.networkDisconnect();
|
||||
DBG("WiFi disconnected");
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_BATTERY && defined TINY_GSM_MODEM_HAS_BATTERY
|
||||
uint8_t chargeState = -99;
|
||||
int8_t percent = -99;
|
||||
@@ -458,6 +459,22 @@ void loop() {
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_POWERDOWN
|
||||
|
||||
#if TINY_GSM_TEST_GPRS
|
||||
modem.gprsDisconnect();
|
||||
delay(5000L);
|
||||
if (!modem.isGprsConnected()) {
|
||||
DBG("GPRS disconnected");
|
||||
} else {
|
||||
DBG("GPRS disconnect: Failed.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_WIFI
|
||||
modem.networkDisconnect();
|
||||
DBG("WiFi disconnected");
|
||||
#endif
|
||||
|
||||
// Try to power-off (modem may decide to restart automatically)
|
||||
// To turn off modem completely, please use Reset/Enable pins
|
||||
modem.poweroff();
|
||||
@@ -467,7 +484,5 @@ void loop() {
|
||||
DBG("End of tests.");
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
modem.maintain();
|
||||
}
|
||||
while (true) { modem.maintain(); }
|
||||
}
|
||||
|
@@ -22,6 +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_PRINT Serial // Comment this out to disable prints and save space
|
||||
|
||||
// Default heartbeat interval for GSM is 60
|
||||
@@ -34,6 +39,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -56,11 +63,14 @@
|
||||
#define SerialMon Serial
|
||||
|
||||
// Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
|
@@ -19,6 +19,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -39,11 +41,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// Increase RX buffer to capture the entire response
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
@@ -60,10 +65,12 @@
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
// #define LOGGING // <- Logging is for the HTTP library
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
// Add a reception delay, if needed.
|
||||
// This may be needed for a fast processor at a slow baud rate.
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
// Define how you're planning to connect to the internet.
|
||||
// This is only needed for this example, not in other code.
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
|
||||
@@ -71,17 +78,17 @@
|
||||
#define GSM_PIN ""
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
// Your WiFi connection credentials, if applicable
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const int port = 80;
|
||||
const int port = 80;
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
#include <CRC32.h>
|
||||
@@ -100,16 +107,16 @@ const int port = 80;
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
#endif
|
||||
|
||||
const char resource[] = "/TinyGSM/test_1k.bin";
|
||||
uint32_t knownCRC32 = 0x6f50d767;
|
||||
uint32_t knownFileSize = 1024; // In case server does not send it
|
||||
const char resource[] = "/TinyGSM/test_1k.bin";
|
||||
uint32_t knownCRC32 = 0x6f50d767;
|
||||
uint32_t knownFileSize = 1024; // In case server does not send it
|
||||
|
||||
#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
|
||||
|
||||
TinyGsmClient client(modem);
|
||||
@@ -141,9 +148,7 @@ void setup() {
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -159,7 +164,6 @@ void printPercent(uint32_t readLength, uint32_t contentLength) {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
// Wifi connection parameters must be set before waiting for the network
|
||||
SerialMon.print(F("Setting SSID/password..."));
|
||||
@@ -184,9 +188,7 @@ void loop() {
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network connected");
|
||||
}
|
||||
if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// GPRS connection parameters are usually set after network registration
|
||||
@@ -199,9 +201,7 @@ void loop() {
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) {
|
||||
SerialMon.println("GPRS connected");
|
||||
}
|
||||
if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
|
||||
#endif
|
||||
|
||||
SerialMon.print(F("Connecting to "));
|
||||
@@ -223,15 +223,16 @@ void loop() {
|
||||
|
||||
SerialMon.println(F("Waiting for response header"));
|
||||
|
||||
// While we are still looking for the end of the header (i.e. empty line FOLLOWED by a newline),
|
||||
// continue to read data into the buffer, parsing each line (data FOLLOWED by a newline).
|
||||
// If it takes too long to get data from the client, we need to exit.
|
||||
// While we are still looking for the end of the header (i.e. empty line
|
||||
// FOLLOWED by a newline), continue to read data into the buffer, parsing each
|
||||
// line (data FOLLOWED by a newline). If it takes too long to get data from
|
||||
// the client, we need to exit.
|
||||
|
||||
const uint32_t clientReadTimeout = 5000;
|
||||
uint32_t clientReadStartTime = millis();
|
||||
String headerBuffer;
|
||||
bool finishedHeader = false;
|
||||
uint32_t contentLength = 0;
|
||||
const uint32_t clientReadTimeout = 5000;
|
||||
uint32_t clientReadStartTime = millis();
|
||||
String headerBuffer;
|
||||
bool finishedHeader = false;
|
||||
uint32_t contentLength = 0;
|
||||
|
||||
while (!finishedHeader) {
|
||||
int nlPos;
|
||||
@@ -254,11 +255,9 @@ void loop() {
|
||||
// SerialMon.print(' ');
|
||||
|
||||
// Let's exit and process if we find a new line
|
||||
if (headerBuffer.indexOf(F("\r\n")) >= 0)
|
||||
break;
|
||||
if (headerBuffer.indexOf(F("\r\n")) >= 0) break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (millis() - clientReadStartTime > clientReadTimeout) {
|
||||
// Time-out waiting for data from client
|
||||
SerialMon.println(F(">>> Client Timeout !"));
|
||||
@@ -273,37 +272,42 @@ void loop() {
|
||||
headerBuffer.toLowerCase();
|
||||
// Check if line contains content-length
|
||||
if (headerBuffer.startsWith(F("content-length:"))) {
|
||||
contentLength = headerBuffer.substring(headerBuffer.indexOf(':') + 1).toInt();
|
||||
contentLength =
|
||||
headerBuffer.substring(headerBuffer.indexOf(':') + 1).toInt();
|
||||
// SerialMon.print(F("Got Content Length: ")); // uncomment for
|
||||
// SerialMon.println(contentLength); // confirmation
|
||||
}
|
||||
|
||||
headerBuffer.remove(0, nlPos + 2); // remove the line
|
||||
}
|
||||
else if (nlPos == 0) {
|
||||
// if the new line is empty (i.e. "\r\n" is at the beginning of the line), we are done with the header.
|
||||
} else if (nlPos == 0) {
|
||||
// if the new line is empty (i.e. "\r\n" is at the beginning of the line),
|
||||
// we are done with the header.
|
||||
finishedHeader = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The two cases which are not managed properly are as follows:
|
||||
// 1. The client doesn't provide data quickly enough to keep up with this loop.
|
||||
// 2. If the client data is segmented in the middle of the 'Content-Length: ' header,
|
||||
// 1. The client doesn't provide data quickly enough to keep up with this
|
||||
// loop.
|
||||
// 2. If the client data is segmented in the middle of the 'Content-Length: '
|
||||
// header,
|
||||
// then that header may be missed/damaged.
|
||||
//
|
||||
|
||||
uint32_t readLength = 0;
|
||||
CRC32 crc;
|
||||
CRC32 crc;
|
||||
|
||||
if (finishedHeader && contentLength == knownFileSize) {
|
||||
SerialMon.println(F("Reading response data"));
|
||||
clientReadStartTime = millis();
|
||||
|
||||
printPercent(readLength, contentLength);
|
||||
while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) {
|
||||
while (readLength < contentLength && client.connected() &&
|
||||
millis() - clientReadStartTime < clientReadTimeout) {
|
||||
while (client.available()) {
|
||||
uint8_t c = client.read();
|
||||
//SerialMon.print(reinterpret_cast<char>c); // Uncomment this to show data
|
||||
// SerialMon.print(reinterpret_cast<char>c); // Uncomment this to show
|
||||
// data
|
||||
crc.update(c);
|
||||
readLength++;
|
||||
if (readLength % (contentLength / 13) == 0) {
|
||||
@@ -335,14 +339,18 @@ void loop() {
|
||||
float duration = float(timeElapsed) / 1000;
|
||||
|
||||
SerialMon.println();
|
||||
SerialMon.print("Content-Length: "); SerialMon.println(contentLength);
|
||||
SerialMon.print("Actually read: "); SerialMon.println(readLength);
|
||||
SerialMon.print("Calc. CRC32: 0x"); SerialMon.println(crc.finalize(), HEX);
|
||||
SerialMon.print("Known CRC32: 0x"); SerialMon.println(knownCRC32, HEX);
|
||||
SerialMon.print("Duration: "); SerialMon.print(duration); SerialMon.println("s");
|
||||
SerialMon.print("Content-Length: ");
|
||||
SerialMon.println(contentLength);
|
||||
SerialMon.print("Actually read: ");
|
||||
SerialMon.println(readLength);
|
||||
SerialMon.print("Calc. CRC32: 0x");
|
||||
SerialMon.println(crc.finalize(), HEX);
|
||||
SerialMon.print("Known CRC32: 0x");
|
||||
SerialMon.println(knownCRC32, HEX);
|
||||
SerialMon.print("Duration: ");
|
||||
SerialMon.print(duration);
|
||||
SerialMon.println("s");
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
while (true) { delay(1000); }
|
||||
}
|
||||
|
@@ -24,6 +24,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -44,11 +46,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// Increase RX buffer to capture the entire response
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
@@ -66,13 +71,17 @@
|
||||
// #define LOGGING // <- Logging is for the HTTP library
|
||||
|
||||
// Range to attempt to autobaud
|
||||
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
|
||||
// communication, set a fixed baud rate using modem.setBaud(#).
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
// Add a reception delay, if needed.
|
||||
// This may be needed for a fast processor at a slow baud rate.
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
// These defines are only for this example; they are not needed in other code.
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
|
||||
@@ -80,18 +89,18 @@
|
||||
#define GSM_PIN ""
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
// Your WiFi connection credentials, if applicable
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char resource[] = "/TinyGSM/logo.txt";
|
||||
const int port = 80;
|
||||
const int port = 80;
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
#include <ArduinoHttpClient.h>
|
||||
@@ -111,15 +120,15 @@ const int port = 80;
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
TinyGsmClient client(modem);
|
||||
HttpClient http(client, server, port);
|
||||
HttpClient http(client, server, port);
|
||||
|
||||
void setup() {
|
||||
// Set console baud rate
|
||||
@@ -149,14 +158,11 @@ void setup() {
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
// Wifi connection parameters must be set before waiting for the network
|
||||
SerialMon.print(F("Setting SSID/password..."));
|
||||
@@ -181,24 +187,20 @@ void loop() {
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network connected");
|
||||
}
|
||||
if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// GPRS connection parameters are usually set after network registration
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) {
|
||||
SerialMon.println("GPRS connected");
|
||||
}
|
||||
if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
|
||||
#endif
|
||||
|
||||
SerialMon.print(F("Performing HTTP GET request... "));
|
||||
@@ -219,7 +221,7 @@ void loop() {
|
||||
|
||||
SerialMon.println(F("Response Headers:"));
|
||||
while (http.headerAvailable()) {
|
||||
String headerName = http.readHeaderName();
|
||||
String headerName = http.readHeaderName();
|
||||
String headerValue = http.readHeaderValue();
|
||||
SerialMon.println(" " + headerName + " : " + headerValue);
|
||||
}
|
||||
@@ -246,16 +248,14 @@ void loop() {
|
||||
SerialMon.println(F("Server disconnected"));
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
modem.networkDisconnect();
|
||||
SerialMon.println(F("WiFi disconnected"));
|
||||
modem.networkDisconnect();
|
||||
SerialMon.println(F("WiFi disconnected"));
|
||||
#endif
|
||||
#if TINY_GSM_USE_GPRS
|
||||
modem.gprsDisconnect();
|
||||
SerialMon.println(F("GPRS disconnected"));
|
||||
modem.gprsDisconnect();
|
||||
SerialMon.println(F("GPRS disconnected"));
|
||||
#endif
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
while (true) { delay(1000); }
|
||||
}
|
||||
|
@@ -25,6 +25,8 @@
|
||||
#define TINY_GSM_MODEM_SIM800
|
||||
// #define TINY_GSM_MODEM_SIM808
|
||||
// #define TINY_GSM_MODEM_SIM868
|
||||
// #define TINY_GSM_MODEM_SIM7000SSL
|
||||
// #define TINY_GSM_MODEM_SIM7080
|
||||
// #define TINY_GSM_MODEM_UBLOX
|
||||
// #define TINY_GSM_MODEM_SARAR4
|
||||
// #define TINY_GSM_MODEM_ESP8266
|
||||
@@ -36,11 +38,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// Increase RX buffer to capture the entire response
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
@@ -58,13 +63,17 @@
|
||||
// #define LOGGING // <- Logging is for the HTTP library
|
||||
|
||||
// Range to attempt to autobaud
|
||||
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
|
||||
// communication, set a fixed baud rate using modem.setBaud(#).
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
// Add a reception delay, if needed.
|
||||
// This may be needed for a fast processor at a slow baud rate.
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
// Define how you're planning to connect to the internet.
|
||||
// This is only needed for this example, not in other code.
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
|
||||
@@ -75,12 +84,12 @@
|
||||
// #define TINY_GSM_SSL_CLIENT_AUTHENTICATION
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
// Your WiFi connection credentials, if applicable
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details
|
||||
@@ -110,7 +119,7 @@ const int port = 443;
|
||||
StreamDebugger debugger(SerialAT, SerialMon);
|
||||
TinyGsm modem(debugger);
|
||||
#else
|
||||
TinyGsm modem(SerialAT);
|
||||
TinyGsm modem(SerialAT);
|
||||
#endif
|
||||
|
||||
TinyGsmClientSecure client(modem);
|
||||
@@ -144,14 +153,11 @@ void setup() {
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
// Wifi connection parameters must be set before waiting for the network
|
||||
SerialMon.print(F("Setting SSID/password..."));
|
||||
@@ -176,28 +182,24 @@ void loop() {
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network connected");
|
||||
}
|
||||
if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// GPRS connection parameters are usually set after network registration
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) {
|
||||
SerialMon.println("GPRS connected");
|
||||
}
|
||||
if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
|
||||
#endif
|
||||
|
||||
SerialMon.print(F("Performing HTTPS GET request... "));
|
||||
http.connectionKeepAlive(); // Currently, this is needed for HTTPS
|
||||
http.connectionKeepAlive(); // Currently, this is needed for HTTPS
|
||||
int err = http.get(resource);
|
||||
if (err != 0) {
|
||||
SerialMon.println(F("failed to connect"));
|
||||
@@ -215,7 +217,7 @@ void loop() {
|
||||
|
||||
SerialMon.println(F("Response Headers:"));
|
||||
while (http.headerAvailable()) {
|
||||
String headerName = http.readHeaderName();
|
||||
String headerName = http.readHeaderName();
|
||||
String headerValue = http.readHeaderValue();
|
||||
SerialMon.println(" " + headerName + " : " + headerValue);
|
||||
}
|
||||
@@ -242,16 +244,14 @@ void loop() {
|
||||
SerialMon.println(F("Server disconnected"));
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
modem.networkDisconnect();
|
||||
SerialMon.println(F("WiFi disconnected"));
|
||||
modem.networkDisconnect();
|
||||
SerialMon.println(F("WiFi disconnected"));
|
||||
#endif
|
||||
#if TINY_GSM_USE_GPRS
|
||||
modem.gprsDisconnect();
|
||||
SerialMon.println(F("GPRS disconnected"));
|
||||
modem.gprsDisconnect();
|
||||
SerialMon.println(F("GPRS disconnected"));
|
||||
#endif
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
while (true) { delay(1000); }
|
||||
}
|
||||
|
@@ -10,20 +10,15 @@
|
||||
* For more MQTT examples, see PubSubClient library
|
||||
*
|
||||
**************************************************************
|
||||
* Use Mosquitto client tools to work with MQTT
|
||||
* Ubuntu/Linux: sudo apt-get install mosquitto-clients
|
||||
* Windows: https://mosquitto.org/download/
|
||||
* This example connects to HiveMQ's showcase broker.
|
||||
*
|
||||
* Subscribe for messages:
|
||||
* mosquitto_sub -h test.mosquitto.org -t GsmClientTest/init -t GsmClientTest/ledStatus -q 1
|
||||
* Toggle led:
|
||||
* mosquitto_pub -h test.mosquitto.org -t GsmClientTest/led -q 1 -m "toggle"
|
||||
* You can quickly test sending and receiving messages from the HiveMQ webclient
|
||||
* available at http://www.hivemq.com/demos/websocket-client/.
|
||||
*
|
||||
* You can use Node-RED for wiring together MQTT-enabled devices
|
||||
* https://nodered.org/
|
||||
* Also, take a look at these additional Node-RED modules:
|
||||
* node-red-contrib-blynk-ws
|
||||
* node-red-dashboard
|
||||
* Subscribe to the topic GsmClientTest/ledStatus
|
||||
* Publish "toggle" to the topic GsmClientTest/led and the LED on your board
|
||||
* should toggle and you should see a new message published to
|
||||
* GsmClientTest/ledStatus with the newest LED status.
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
@@ -33,6 +28,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -53,11 +50,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
// #define DUMP_AT_COMMANDS
|
||||
@@ -66,13 +66,17 @@
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
|
||||
// Range to attempt to autobaud
|
||||
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
|
||||
// communication, set a fixed baud rate using modem.setBaud(#).
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
// Add a reception delay, if needed.
|
||||
// This may be needed for a fast processor at a slow baud rate.
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
// Define how you're planning to connect to the internet.
|
||||
// This is only needed for this example, not in other code.
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
|
||||
@@ -80,7 +84,7 @@
|
||||
#define GSM_PIN ""
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
@@ -91,8 +95,8 @@ const char wifiPass[] = "YourWiFiPass";
|
||||
// MQTT details
|
||||
const char* broker = "broker.hivemq.com";
|
||||
|
||||
const char* topicLed = "GsmClientTest/led";
|
||||
const char* topicInit = "GsmClientTest/init";
|
||||
const char* topicLed = "GsmClientTest/led";
|
||||
const char* topicInit = "GsmClientTest/init";
|
||||
const char* topicLedStatus = "GsmClientTest/ledStatus";
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
@@ -113,14 +117,14 @@ const char* topicLedStatus = "GsmClientTest/ledStatus";
|
||||
#endif
|
||||
|
||||
#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
|
||||
TinyGsmClient client(modem);
|
||||
PubSubClient mqtt(client);
|
||||
PubSubClient mqtt(client);
|
||||
|
||||
#define LED_PIN 13
|
||||
int ledStatus = LOW;
|
||||
@@ -150,7 +154,7 @@ boolean mqttConnect() {
|
||||
boolean status = mqtt.connect("GsmClientTest");
|
||||
|
||||
// Or, if you want to authenticate MQTT:
|
||||
//boolean status = mqtt.connect("GsmClientName", "mqtt_user", "mqtt_pass");
|
||||
// boolean status = mqtt.connect("GsmClientName", "mqtt_user", "mqtt_pass");
|
||||
|
||||
if (status == false) {
|
||||
SerialMon.println(" fail");
|
||||
@@ -193,13 +197,11 @@ void setup() {
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
// Wifi connection parameters must be set before waiting for the network
|
||||
// Wifi connection parameters must be set before waiting for the network
|
||||
SerialMon.print(F("Setting SSID/password..."));
|
||||
if (!modem.networkConnect(wifiSSID, wifiPass)) {
|
||||
SerialMon.println(" fail");
|
||||
@@ -222,24 +224,20 @@ void setup() {
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network connected");
|
||||
}
|
||||
if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// GPRS connection parameters are usually set after network registration
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) {
|
||||
SerialMon.println("GPRS connected");
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
|
||||
#endif
|
||||
|
||||
// MQTT Broker setup
|
||||
@@ -248,6 +246,33 @@ void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Make sure we're still registered on the network
|
||||
if (!modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network disconnected");
|
||||
if (!modem.waitForNetwork(180000L, true)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
if (modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network re-connected");
|
||||
}
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// and make sure GPRS/EPS is still connected
|
||||
if (!modem.isGprsConnected()) {
|
||||
SerialMon.println("GPRS disconnected!");
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
if (modem.isGprsConnected()) { SerialMon.println("GPRS reconnected"); }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!mqtt.connected()) {
|
||||
SerialMon.println("=== MQTT NOT CONNECTED ===");
|
||||
@@ -255,9 +280,7 @@ void loop() {
|
||||
uint32_t t = millis();
|
||||
if (t - lastReconnectAttempt > 10000L) {
|
||||
lastReconnectAttempt = t;
|
||||
if (mqttConnect()) {
|
||||
lastReconnectAttempt = 0;
|
||||
}
|
||||
if (mqttConnect()) { lastReconnectAttempt = 0; }
|
||||
}
|
||||
delay(100);
|
||||
return;
|
||||
|
@@ -14,6 +14,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -34,11 +36,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// Increase RX buffer to capture the entire response
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
@@ -55,16 +60,20 @@
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
|
||||
// Range to attempt to autobaud
|
||||
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
|
||||
// communication, set a fixed baud rate using modem.setBaud(#).
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
// Add a reception delay, if needed.
|
||||
// This may be needed for a fast processor at a slow baud rate.
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Uncomment this if you want to use SSL
|
||||
// #define USE_SSL
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
// Define how you're planning to connect to the internet.
|
||||
// This is only needed for this example, not in other code.
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
|
||||
@@ -72,16 +81,16 @@
|
||||
#define GSM_PIN ""
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
// Your WiFi connection credentials, if applicable
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char resource[] = "/TinyGSM/logo.txt";
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
@@ -101,19 +110,19 @@ const char resource[] = "/TinyGSM/logo.txt";
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifdef USE_SSL
|
||||
TinyGsmClientSecure client(modem);
|
||||
const int port = 443;
|
||||
TinyGsmClientSecure client(modem);
|
||||
const int port = 443;
|
||||
#else
|
||||
TinyGsmClient client(modem);
|
||||
const int port = 80;
|
||||
TinyGsmClient client(modem);
|
||||
const int port = 80;
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
@@ -144,14 +153,11 @@ void setup() {
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
// Wifi connection parameters must be set before waiting for the network
|
||||
SerialMon.print(F("Setting SSID/password..."));
|
||||
@@ -176,24 +182,20 @@ void loop() {
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isNetworkConnected()) {
|
||||
SerialMon.println("Network connected");
|
||||
}
|
||||
if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// GPRS connection parameters are usually set after network registration
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) {
|
||||
SerialMon.println("GPRS connected");
|
||||
SerialMon.print(F("Connecting to "));
|
||||
SerialMon.print(apn);
|
||||
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
|
||||
SerialMon.println(" fail");
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
SerialMon.println(" success");
|
||||
|
||||
if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
|
||||
#endif
|
||||
|
||||
SerialMon.print("Connecting to ");
|
||||
@@ -229,16 +231,14 @@ void loop() {
|
||||
SerialMon.println(F("Server disconnected"));
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
modem.networkDisconnect();
|
||||
SerialMon.println(F("WiFi disconnected"));
|
||||
modem.networkDisconnect();
|
||||
SerialMon.println(F("WiFi disconnected"));
|
||||
#endif
|
||||
#if TINY_GSM_USE_GPRS
|
||||
modem.gprsDisconnect();
|
||||
SerialMon.println(F("GPRS disconnected"));
|
||||
modem.gprsDisconnect();
|
||||
SerialMon.println(F("GPRS disconnected"));
|
||||
#endif
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
while (true) { delay(1000); }
|
||||
}
|
||||
|
41
examples/example_dependencies.json
Normal file
41
examples/example_dependencies.json
Normal file
@@ -0,0 +1,41 @@
|
||||
[
|
||||
{
|
||||
"name": "PubSubClient",
|
||||
"owner": "knolleary",
|
||||
"library id": "89",
|
||||
"url": "https://github.com/knolleary/pubsubclient.git",
|
||||
"version": "~2.8",
|
||||
"note": "A client library for MQTT messaging.",
|
||||
"authors": ["Nick O'Leary"]
|
||||
},
|
||||
{
|
||||
"name": "Blynk",
|
||||
"owner": "blynkkk",
|
||||
"library id": "415",
|
||||
"url": "https://github.com/blynkkk/blynk-library.git",
|
||||
"version": "~0.6.7",
|
||||
"authors": ["Volodymyr Shymanskyy"],
|
||||
"frameworks": "*",
|
||||
"platforms": "*"
|
||||
},
|
||||
{
|
||||
"name": "AceCRC",
|
||||
"owner": "bxparks",
|
||||
"library id": "1202",
|
||||
"url": "https://github.com/bxparks/AceCRC.git",
|
||||
"version": "~1.0.1",
|
||||
"authors": ["Brian T. Park"],
|
||||
"frameworks": "*",
|
||||
"platforms": "*"
|
||||
},
|
||||
{
|
||||
"name": "StreamDebugger",
|
||||
"owner": "vshymanskyy",
|
||||
"library id": "1286",
|
||||
"url": "https://github.com/vshymanskyy/StreamDebugger.git",
|
||||
"version": "~1.0.1",
|
||||
"authors": ["Volodymyr Shymanskyy"],
|
||||
"frameworks": "*",
|
||||
"platforms": "*"
|
||||
}
|
||||
]
|
@@ -5,8 +5,8 @@
|
||||
width="500" height="80"
|
||||
>
|
||||
<text x="0" y="0" font-size="18px" font-family="'Ubuntu Mono',monospace" white-space="pre" xml:space="preserve" >
|
||||
<tspan x="0" dy="18px"> _____ _____ _____ _____ </tspan>
|
||||
<tspan x="0" dy="18px"> | | |\ | \_/ | ___ |_____ | | |</tspan>
|
||||
<tspan x="0" dy="18px"> | | | \| | |_____| _____|| | |</tspan>
|
||||
<tspan x="0" dy="1em"> _____ _____ _____ _____ </tspan>
|
||||
<tspan x="0" dy="1em"> | | |\ | \_/ | ___ |_____ | | |</tspan>
|
||||
<tspan x="0" dy="1em"> | | | \| | |_____| _____|| | |</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 536 B After Width: | Height: | Size: 533 B |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TinyGSM",
|
||||
"version": "0.10.9",
|
||||
"version": "0.11.7",
|
||||
"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",
|
||||
"authors": [
|
||||
@@ -28,5 +28,5 @@
|
||||
},
|
||||
"frameworks": ["arduino", "energia", "wiringpi"],
|
||||
"platforms": "*",
|
||||
"examples": "examples/*/*.ino"
|
||||
"headers": "TinyGsmClient.h"
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
name=TinyGSM
|
||||
version=0.10.9
|
||||
version=0.11.7
|
||||
author=Volodymyr Shymanskyy
|
||||
maintainer=Volodymyr Shymanskyy
|
||||
sentence=A small Arduino library for GPRS modules, that just works.
|
||||
|
@@ -24,22 +24,24 @@
|
||||
#include "ArduinoCompat/IPAddress.h"
|
||||
|
||||
class Client : public Stream {
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) = 0;
|
||||
virtual int connect(const char* host, uint16_t port) = 0;
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
virtual size_t write(const uint8_t* buf, size_t size) = 0;
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int read(uint8_t* buf, size_t size) = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual uint8_t connected() = 0;
|
||||
virtual operator bool() = 0;
|
||||
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) =0;
|
||||
virtual int connect(const char *host, uint16_t port) =0;
|
||||
virtual size_t write(uint8_t) =0;
|
||||
virtual size_t write(const uint8_t *buf, size_t size) =0;
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int read(uint8_t *buf, size_t size) = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual uint8_t connected() = 0;
|
||||
virtual operator bool() = 0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr) {
|
||||
return addr.raw_address();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
6
src/TinyGSM.h
Normal file
6
src/TinyGSM.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef TINYGSM_H
|
||||
#define TINYGSM_H
|
||||
|
||||
#include "TinyGsmClient.h"
|
||||
|
||||
#endif
|
57
src/TinyGsmBluetooth.tpp
Normal file
57
src/TinyGsmBluetooth.tpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file TinyGsmGPS.tpp
|
||||
* @author Adrian Cervera Andes
|
||||
* @license LGPL-3.0
|
||||
* @copyright Copyright (c) 2021 Adrian Cervera Andes
|
||||
* @date Jan 2021
|
||||
*/
|
||||
|
||||
#ifndef SRC_TINYGSMBLUETOOTH_H_
|
||||
#define SRC_TINYGSMBLUETOOTH_H_
|
||||
|
||||
#include "TinyGsmCommon.h"
|
||||
|
||||
#define TINY_GSM_MODEM_HAS_BLUETOOTH
|
||||
|
||||
template <class modemType>
|
||||
class TinyGsmBluetooth {
|
||||
public:
|
||||
/*
|
||||
* Bluetooth functions
|
||||
*/
|
||||
bool enableBluetooth() {
|
||||
return thisModem().enableBluetoothImpl();
|
||||
}
|
||||
bool disableBluetooth() {
|
||||
return thisModem().disableBluetoothImpl();
|
||||
}
|
||||
bool setBluetoothVisibility(bool visible) {
|
||||
return thisModem().setBluetoothVisibilityImpl(visible);
|
||||
}
|
||||
bool setBluetoothHostName(const char* name) {
|
||||
return thisModem().setBluetoothHostNameImpl(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* CRTP Helper
|
||||
*/
|
||||
protected:
|
||||
inline const modemType& thisModem() const {
|
||||
return static_cast<const modemType&>(*this);
|
||||
}
|
||||
inline modemType& thisModem() {
|
||||
return static_cast<modemType&>(*this);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
||||
#endif // SRC_TINYGSMBLUETOOTH_H_
|
@@ -30,7 +30,19 @@ typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
|
||||
#include "TinyGsmClientSIM7000.h"
|
||||
typedef TinyGsmSim7000 TinyGsm;
|
||||
typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient;
|
||||
// typedef TinyGsmSim7000::GsmClientSecureSim7000 TinyGsmClientSecure; TODO!
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM7000SSL)
|
||||
#include "TinyGsmClientSIM7000SSL.h"
|
||||
typedef TinyGsmSim7000SSL TinyGsm;
|
||||
typedef TinyGsmSim7000SSL::GsmClientSim7000SSL TinyGsmClient;
|
||||
typedef TinyGsmSim7000SSL::GsmClientSecureSIM7000SSL TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM7070) || defined(TINY_GSM_MODEM_SIM7080) || \
|
||||
defined(TINY_GSM_MODEM_SIM7090)
|
||||
#include "TinyGsmClientSIM7080.h"
|
||||
typedef TinyGsmSim7080 TinyGsm;
|
||||
typedef TinyGsmSim7080::GsmClientSim7080 TinyGsmClient;
|
||||
typedef TinyGsmSim7080::GsmClientSecureSIM7080 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \
|
||||
defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
|
||||
|
@@ -79,7 +79,7 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
|
||||
}
|
||||
|
||||
public:
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -176,11 +176,11 @@ class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+RST=1"));
|
||||
delay(3000);
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "TinyGsmTCP.tpp"
|
||||
#include "TinyGsmTemperature.tpp"
|
||||
#include "TinyGsmTime.tpp"
|
||||
#include "TinyGsmNTP.tpp"
|
||||
|
||||
#define GSM_NL "\r\n"
|
||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||
@@ -49,6 +50,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
|
||||
public TinyGsmCalling<TinyGsmBG96>,
|
||||
public TinyGsmSMS<TinyGsmBG96>,
|
||||
public TinyGsmTime<TinyGsmBG96>,
|
||||
public TinyGsmNTP<TinyGsmBG96>,
|
||||
public TinyGsmGPS<TinyGsmBG96>,
|
||||
public TinyGsmBattery<TinyGsmBG96>,
|
||||
public TinyGsmTemperature<TinyGsmBG96> {
|
||||
@@ -58,6 +60,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
|
||||
friend class TinyGsmCalling<TinyGsmBG96>;
|
||||
friend class TinyGsmSMS<TinyGsmBG96>;
|
||||
friend class TinyGsmTime<TinyGsmBG96>;
|
||||
friend class TinyGsmNTP<TinyGsmBG96>;
|
||||
friend class TinyGsmGPS<TinyGsmBG96>;
|
||||
friend class TinyGsmBattery<TinyGsmBG96>;
|
||||
friend class TinyGsmTemperature<TinyGsmBG96>;
|
||||
@@ -202,11 +205,11 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
if (!setPhoneFunctionality(1, true)) { return false; }
|
||||
waitResponse(10000L, GF("APP RDY"));
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -235,7 +238,16 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
|
||||
*/
|
||||
public:
|
||||
RegStatus getRegistrationStatus() {
|
||||
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||
// Check first for EPS registration
|
||||
RegStatus epsStatus = (RegStatus)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");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -468,6 +480,27 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
|
||||
byte NTPServerSyncImpl(String server = "pool.ntp.org", byte = -5) {
|
||||
// Request network synchronization
|
||||
// AT+QNTP=<contextID>,<server>[,<port>][,<autosettime>]
|
||||
sendAT(GF("+QNTP=1,\""), server, '"');
|
||||
if (waitResponse(10000L, GF("+QNTP:"))) {
|
||||
String result = stream.readStringUntil(',');
|
||||
streamSkipUntil('\n');
|
||||
result.trim();
|
||||
if (TinyGsmIsValidNumber(result)) { return result.toInt(); }
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
String ShowNTPErrorImpl(byte error) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* Battery functions
|
||||
*/
|
||||
|
@@ -149,8 +149,12 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+CWMODE=1")); // Put into "station" mode
|
||||
if (waitResponse() != 1) {
|
||||
sendAT(GF("+CWMODE_CUR=1")); // Attempt "current" station mode command
|
||||
// for some firmware variants if needed
|
||||
if (waitResponse() != 1) { return false; }
|
||||
}
|
||||
DBG(GF("### Modem:"), getModemName());
|
||||
return true;
|
||||
}
|
||||
@@ -161,6 +165,15 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||
|
||||
void setBaudImpl(uint32_t baud) {
|
||||
sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
|
||||
if (waitResponse() != 1) {
|
||||
sendAT(GF("+UART="), baud,
|
||||
"8,1,0,0"); // Really old firmwares might need this
|
||||
// if (waitResponse() != 1) {
|
||||
// sendAT(GF("+IPR="), baud); // First release firmwares might need
|
||||
// this
|
||||
waitResponse();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
bool factoryDefaultImpl() {
|
||||
@@ -182,13 +195,13 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
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; }
|
||||
delay(500);
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -218,11 +231,17 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||
|
||||
protected:
|
||||
int8_t getSignalQualityImpl() {
|
||||
sendAT(GF("+CWJAP_CUR?"));
|
||||
int8_t res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
||||
sendAT(GF("+CWJAP?"));
|
||||
int8_t res1 = waitResponse(GF("No AP"), GF("+CWJAP:"));
|
||||
if (res1 != 2) {
|
||||
waitResponse();
|
||||
return 0;
|
||||
sendAT(GF("+CWJAP_CUR?")); // attempt "current" as used by some firmware
|
||||
// versions
|
||||
int8_t res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
||||
if (res1 != 2) {
|
||||
waitResponse();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
streamSkipUntil(','); // Skip SSID
|
||||
streamSkipUntil(','); // Skip BSSID/MAC address
|
||||
@@ -250,10 +269,18 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||
}
|
||||
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+CIPSTA_CUR?"));
|
||||
int8_t res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
||||
if (res1 != 2) { return ""; }
|
||||
String res2 = stream.readStringUntil('"');
|
||||
// attempt with and without 'current' flag
|
||||
sendAT(GF("+CIPSTA?"));
|
||||
int8_t res1 = waitResponse(GF("ERROR"), GF("+CIPSTA:"));
|
||||
if (res1 != 2) {
|
||||
sendAT(GF("+CIPSTA_CUR?"));
|
||||
res1 = waitResponse(GF("ERROR"), GF("+CIPSTA_CUR:"));
|
||||
if (res1 != 2) { return ""; }
|
||||
}
|
||||
String res2 = stream.readStringUntil('\n');
|
||||
res2.replace("ip:", ""); // newer firmwares have this
|
||||
res2.replace("\"", "");
|
||||
res2.trim();
|
||||
waitResponse();
|
||||
return res2;
|
||||
}
|
||||
@@ -263,9 +290,14 @@ class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||
*/
|
||||
protected:
|
||||
bool networkConnectImpl(const char* ssid, const char* pwd) {
|
||||
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
|
||||
// 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) {
|
||||
return false;
|
||||
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
|
||||
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -79,7 +79,7 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
|
||||
}
|
||||
|
||||
public:
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -171,12 +171,12 @@ class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
if (!setPhoneFunctionality(15)) { return false; }
|
||||
// MODEM:STARTUP
|
||||
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
|
@@ -198,7 +198,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+CFUN=0"));
|
||||
if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) ==
|
||||
@@ -209,7 +209,7 @@ class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
|
||||
if (waitResponse(10000L, GF("Call Ready"), GF("OK"), GF("FAIL")) == 3) {
|
||||
return false;
|
||||
}
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
|
@@ -197,12 +197,12 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
if (!setPhoneFunctionality(0)) { return false; }
|
||||
if (!setPhoneFunctionality(1, true)) { return false; }
|
||||
delay(3000);
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -381,7 +381,8 @@ class TinyGsmMC60 : public TinyGsmModem<TinyGsmMC60>,
|
||||
// If it is a domain name, "AT+QIDNSIP=1" should be executed.
|
||||
// "AT+QIDNSIP=0" is for dotted decimal IP address.
|
||||
IPAddress addr;
|
||||
sendAT(GF("+QIDNSIP="), (addr.fromString(host) ? 0 : 1));
|
||||
sendAT(GF("+QIDNSIP="),
|
||||
(TinyGsmIpFromString(host) == IPAddress(0, 0, 0, 0) ? 0 : 1));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "TinyGsmTCP.tpp"
|
||||
#include "TinyGsmTemperature.tpp"
|
||||
#include "TinyGsmTime.tpp"
|
||||
#include "TinyGsmNTP.tpp"
|
||||
|
||||
#define GSM_NL "\r\n"
|
||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||
@@ -47,6 +48,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
|
||||
public TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>,
|
||||
public TinyGsmSMS<TinyGsmSim5360>,
|
||||
public TinyGsmTime<TinyGsmSim5360>,
|
||||
public TinyGsmNTP<TinyGsmSim5360>,
|
||||
public TinyGsmGSMLocation<TinyGsmSim5360>,
|
||||
public TinyGsmBattery<TinyGsmSim5360>,
|
||||
public TinyGsmTemperature<TinyGsmSim5360> {
|
||||
@@ -55,6 +57,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
|
||||
friend class TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>;
|
||||
friend class TinyGsmSMS<TinyGsmSim5360>;
|
||||
friend class TinyGsmTime<TinyGsmSim5360>;
|
||||
friend class TinyGsmNTP<TinyGsmSim5360>;
|
||||
friend class TinyGsmGSMLocation<TinyGsmSim5360>;
|
||||
friend class TinyGsmBattery<TinyGsmSim5360>;
|
||||
friend class TinyGsmTemperature<TinyGsmSim5360>;
|
||||
@@ -215,7 +218,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+REBOOT"));
|
||||
// Should return an 'OK' after reboot command is sent
|
||||
@@ -223,7 +226,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
|
||||
// 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; }
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -270,12 +273,17 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
|
||||
return res;
|
||||
}
|
||||
|
||||
String setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
int16_t getNetworkMode() {
|
||||
sendAT(GF("+CNMP?"));
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
|
||||
int16_t mode = streamGetIntBefore('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
String getLocalIPImpl() {
|
||||
@@ -435,6 +443,11 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
// Can sync with server using CNTP as per template
|
||||
|
||||
/*
|
||||
* Battery functions
|
||||
*/
|
||||
|
@@ -15,46 +15,14 @@
|
||||
#define TINY_GSM_MUX_COUNT 8
|
||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||
|
||||
#include "TinyGsmBattery.tpp"
|
||||
#include "TinyGsmGPRS.tpp"
|
||||
#include "TinyGsmGPS.tpp"
|
||||
#include "TinyGsmModem.tpp"
|
||||
#include "TinyGsmSMS.tpp"
|
||||
#include "TinyGsmClientSIM70xx.h"
|
||||
#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:";
|
||||
#endif
|
||||
|
||||
enum RegStatus {
|
||||
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 TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
public TinyGsmGPRS<TinyGsmSim7000>,
|
||||
public TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT>,
|
||||
public TinyGsmSMS<TinyGsmSim7000>,
|
||||
public TinyGsmGPS<TinyGsmSim7000>,
|
||||
public TinyGsmTime<TinyGsmSim7000>,
|
||||
public TinyGsmBattery<TinyGsmSim7000> {
|
||||
friend class TinyGsmModem<TinyGsmSim7000>;
|
||||
friend class TinyGsmGPRS<TinyGsmSim7000>;
|
||||
class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
|
||||
public TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmSim70xx<TinyGsmSim7000>;
|
||||
friend class TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT>;
|
||||
friend class TinyGsmSMS<TinyGsmSim7000>;
|
||||
friend class TinyGsmGPS<TinyGsmSim7000>;
|
||||
friend class TinyGsmTime<TinyGsmSim7000>;
|
||||
friend class TinyGsmBattery<TinyGsmSim7000>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
@@ -101,7 +69,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse();
|
||||
at->waitResponse(3000);
|
||||
}
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
@@ -117,34 +85,14 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
/*TODO(?))
|
||||
class GsmClientSecureSIM7000 : public GsmClientSim7000
|
||||
{
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
|
||||
GsmClientSecure(TinyGsmSim7000& 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
|
||||
};
|
||||
*/
|
||||
// NOTE: Use modem TINYGSMSIM7000SSL for a secure client!
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmSim7000(Stream& stream) : stream(stream) {
|
||||
explicit TinyGsmSim7000(Stream& stream)
|
||||
: TinyGsmSim70xx<TinyGsmSim7000>(stream) {
|
||||
memset(sockets, 0, sizeof(sockets));
|
||||
}
|
||||
|
||||
@@ -190,109 +138,16 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
}
|
||||
}
|
||||
|
||||
String getModemNameImpl() {
|
||||
String name = "SIMCom SIM7000";
|
||||
|
||||
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;
|
||||
return name;
|
||||
}
|
||||
|
||||
bool factoryDefaultImpl() { // these commands aren't supported
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
if (!setPhoneFunctionality(0)) { return false; }
|
||||
if (!setPhoneFunctionality(1, true)) { return false; }
|
||||
waitResponse(10000L, GF("SMS Ready"), GF("RDY"));
|
||||
return init();
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
sendAT(GF("+CPOWD=1"));
|
||||
return waitResponse(GF("NORMAL POWER DOWN")) == 1;
|
||||
}
|
||||
|
||||
// During sleep, the SIM7000 module has its serial communication disabled.
|
||||
// In order to reestablish communication pull the DRT-pin of the SIM7000
|
||||
// module LOW for at least 50ms. Then use this function to disable sleep mode.
|
||||
// The DTR-pin can then be released again.
|
||||
bool sleepEnableImpl(bool enable = true) {
|
||||
sendAT(GF("+CSCLK="), enable);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
|
||||
sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
|
||||
return waitResponse(10000L) == 1;
|
||||
}
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
public:
|
||||
RegStatus getRegistrationStatus() {
|
||||
RegStatus epsStatus = (RegStatus)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)getRegistrationStatusXREG("CGREG");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isNetworkConnectedImpl() {
|
||||
RegStatus 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 ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
String setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
String getPreferredModes() {
|
||||
sendAT(GF("+CMNB=?"));
|
||||
if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
String setPreferredMode(uint8_t mode) {
|
||||
sendAT(GF("+CMNB="), mode);
|
||||
if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return "OK"; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+CIFSR;E0"));
|
||||
String res;
|
||||
@@ -311,20 +166,23 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
// Set the Bearer for the IP
|
||||
sendAT(GF(
|
||||
"+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS
|
||||
// Bearer settings for applications based on IP
|
||||
// Set the connection type to GPRS
|
||||
sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\""));
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN
|
||||
// Set the APN
|
||||
sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
// Set the user name
|
||||
if (user && strlen(user) > 0) {
|
||||
sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name
|
||||
sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');
|
||||
waitResponse();
|
||||
}
|
||||
// Set the password
|
||||
if (pwd && strlen(pwd) > 0) {
|
||||
sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password
|
||||
sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');
|
||||
waitResponse();
|
||||
}
|
||||
|
||||
@@ -332,6 +190,10 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
// Attach to GPRS
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// Activate the PDP context
|
||||
sendAT(GF("+CGACT=1,1"));
|
||||
waitResponse(60000L);
|
||||
@@ -343,33 +205,29 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
sendAT(GF("+SAPBR=2,1"));
|
||||
if (waitResponse(30000L) != 1) { return false; }
|
||||
|
||||
// Attach to GPRS
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// TODO(?): wait AT+CGATT?
|
||||
|
||||
// Set to multi-IP
|
||||
// Set the TCP application toolkit to multi-IP
|
||||
sendAT(GF("+CIPMUX=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Put in "quick send" mode (thus no extra "Send OK")
|
||||
// Put the TCP application toolkit in "quick send" mode
|
||||
// (thus no extra "Send OK")
|
||||
sendAT(GF("+CIPQSEND=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Set to get data manually
|
||||
// Set the TCP application toolkit to get data manually
|
||||
sendAT(GF("+CIPRXGET=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Start Task and Set APN, USER NAME, PASSWORD
|
||||
// Start the TCP application toolkit task and set APN, USER NAME, PASSWORD
|
||||
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// Bring Up Wireless Connection with GPRS or CSD
|
||||
// Bring up the TCP application toolkit wireless connection with GPRS or CSD
|
||||
sendAT(GF("+CIICR"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// Get Local IP Address, only assigned after connection
|
||||
// Get local IP address for the TCP application toolkit
|
||||
// only assigned after connection
|
||||
sendAT(GF("+CIFSR;E0"));
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
|
||||
@@ -377,8 +235,8 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
}
|
||||
|
||||
bool gprsDisconnectImpl() {
|
||||
// Shut the TCP/IP connection
|
||||
// CIPSHUT will close *all* open connections
|
||||
// Shut the TCP application toolkit connection
|
||||
// CIPSHUT will close *all* open TCP application toolkit connections
|
||||
sendAT(GF("+CIPSHUT"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
@@ -392,15 +250,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
* SIM card functions
|
||||
*/
|
||||
protected:
|
||||
// Doesn't return the "+CCID" before the number
|
||||
String getSimCCIDImpl() {
|
||||
sendAT(GF("+CCID"));
|
||||
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
res.trim();
|
||||
return res;
|
||||
}
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
@@ -412,113 +262,18 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
* GPS/GNSS/GLONASS location functions
|
||||
*/
|
||||
protected:
|
||||
// enable GPS
|
||||
bool enableGPSImpl() {
|
||||
sendAT(GF("+CGNSPWR=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disableGPSImpl() {
|
||||
sendAT(GF("+CGNSPWR=0"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the RAW GPS output
|
||||
String getGPSrawImpl() {
|
||||
sendAT(GF("+CGNSINF"));
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 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("+CGNSINF"));
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
|
||||
|
||||
streamSkipUntil(','); // GNSS run status
|
||||
if (streamGetIntBefore(',') == 1) { // fix status
|
||||
// init variables
|
||||
float ilat = 0;
|
||||
float ilon = 0;
|
||||
float ispeed = 0;
|
||||
float ialt = 0;
|
||||
int ivsat = 0;
|
||||
int iusat = 0;
|
||||
float iaccuracy = 0;
|
||||
int iyear = 0;
|
||||
int imonth = 0;
|
||||
int iday = 0;
|
||||
int ihour = 0;
|
||||
int imin = 0;
|
||||
float secondWithSS = 0;
|
||||
|
||||
// UTC date & Time
|
||||
iyear = streamGetIntLength(4); // Four digit year
|
||||
imonth = streamGetIntLength(2); // Two digit month
|
||||
iday = streamGetIntLength(2); // Two digit day
|
||||
ihour = streamGetIntLength(2); // Two digit hour
|
||||
imin = streamGetIntLength(2); // Two digit minute
|
||||
secondWithSS =
|
||||
streamGetFloatBefore(','); // 6 digit second with subseconds
|
||||
|
||||
ilat = streamGetFloatBefore(','); // Latitude
|
||||
ilon = streamGetFloatBefore(','); // Longitude
|
||||
ialt = streamGetFloatBefore(','); // MSL Altitude. Unit is meters
|
||||
ispeed = streamGetFloatBefore(','); // Speed Over Ground. Unit is knots.
|
||||
streamSkipUntil(','); // Course Over Ground. Degrees.
|
||||
streamSkipUntil(','); // Fix Mode
|
||||
streamSkipUntil(','); // Reserved1
|
||||
iaccuracy =
|
||||
streamGetFloatBefore(','); // Horizontal Dilution Of Precision
|
||||
streamSkipUntil(','); // Position Dilution Of Precision
|
||||
streamSkipUntil(','); // Vertical Dilution Of Precision
|
||||
streamSkipUntil(','); // Reserved2
|
||||
ivsat = streamGetIntBefore(','); // GNSS Satellites in View
|
||||
iusat = streamGetIntBefore(','); // GNSS Satellites Used
|
||||
streamSkipUntil(','); // GLONASS Satellites Used
|
||||
streamSkipUntil(','); // Reserved3
|
||||
streamSkipUntil(','); // C/N0 max
|
||||
streamSkipUntil(','); // HPA
|
||||
streamSkipUntil('\n'); // VPA
|
||||
|
||||
// Set pointers
|
||||
if (lat != NULL) *lat = ilat;
|
||||
if (lon != NULL) *lon = ilon;
|
||||
if (speed != NULL) *speed = ispeed;
|
||||
if (alt != NULL) *alt = ialt;
|
||||
if (vsat != NULL) *vsat = ivsat;
|
||||
if (usat != NULL) *usat = iusat;
|
||||
if (accuracy != NULL) *accuracy = iaccuracy;
|
||||
if (iyear < 2000) iyear += 2000;
|
||||
if (year != NULL) *year = iyear;
|
||||
if (month != NULL) *month = imonth;
|
||||
if (day != NULL) *day = iday;
|
||||
if (hour != NULL) *hour = ihour;
|
||||
if (minute != NULL) *minute = imin;
|
||||
if (second != NULL) *second = static_cast<int>(secondWithSS);
|
||||
|
||||
waitResponse();
|
||||
return true;
|
||||
}
|
||||
|
||||
streamSkipUntil('\n'); // toss the row of commas
|
||||
waitResponse();
|
||||
return false;
|
||||
}
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
// Can follow CCLK as per template
|
||||
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
// Can sync with server using CNTP as per template
|
||||
|
||||
/*
|
||||
* Battery functions
|
||||
*/
|
||||
@@ -531,9 +286,10 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||
bool ssl = false, int timeout_s = 75) {
|
||||
if (ssl) { DBG("SSL not yet supported on this module!"); }
|
||||
|
||||
if (ssl) { DBG("SSL only supported using application on SIM7000!"); }
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
|
||||
// when not using SSL, the TCP application toolkit is more stable
|
||||
sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host,
|
||||
GF("\","), port);
|
||||
return (1 ==
|
||||
@@ -546,8 +302,10 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||
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(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; }
|
||||
streamSkipUntil(','); // Skip mux
|
||||
return streamGetIntBefore('\n');
|
||||
@@ -555,6 +313,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
|
||||
size_t modemRead(size_t size, uint8_t mux) {
|
||||
if (!sockets[mux]) return 0;
|
||||
|
||||
#ifdef TINY_GSM_USE_HEX
|
||||
sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
|
||||
@@ -603,6 +362,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
|
||||
size_t modemGetAvailable(uint8_t mux) {
|
||||
if (!sockets[mux]) return 0;
|
||||
|
||||
sendAT(GF("+CIPRXGET=4,"), mux);
|
||||
size_t result = 0;
|
||||
if (waitResponse(GF("+CIPRXGET:")) == 1) {
|
||||
@@ -724,6 +484,10 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
'\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();
|
||||
}
|
||||
}
|
||||
} while (millis() - startMillis < timeout_ms);
|
||||
@@ -763,12 +527,8 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
|
||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||
}
|
||||
|
||||
public:
|
||||
Stream& stream;
|
||||
|
||||
protected:
|
||||
GsmClientSim7000* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMCLIENTSIM7000_H_
|
||||
|
730
src/TinyGsmClientSIM7000SSL.h
Normal file
730
src/TinyGsmClientSIM7000SSL.h
Normal file
@@ -0,0 +1,730 @@
|
||||
/**
|
||||
* @file TinyGsmClientSim7000SSL.h
|
||||
* @author Volodymyr Shymanskyy
|
||||
* @license LGPL-3.0
|
||||
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef SRC_TINYGSMCLIENTSIM7000SSL_H_
|
||||
#define SRC_TINYGSMCLIENTSIM7000SSL_H_
|
||||
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
// #define TINY_GSM_USE_HEX
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 2
|
||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||
|
||||
#include "TinyGsmClientSIM70xx.h"
|
||||
#include "TinyGsmTCP.tpp"
|
||||
#include "TinyGsmSSL.tpp"
|
||||
|
||||
class TinyGsmSim7000SSL
|
||||
: public TinyGsmSim70xx<TinyGsmSim7000SSL>,
|
||||
public TinyGsmTCP<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>,
|
||||
public TinyGsmSSL<TinyGsmSim7000SSL> {
|
||||
friend class TinyGsmSim70xx<TinyGsmSim7000SSL>;
|
||||
friend class TinyGsmTCP<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>;
|
||||
friend class TinyGsmSSL<TinyGsmSim7000SSL>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
class GsmClientSim7000SSL : public GsmClient {
|
||||
friend class TinyGsmSim7000SSL;
|
||||
|
||||
public:
|
||||
GsmClientSim7000SSL() {}
|
||||
|
||||
explicit GsmClientSim7000SSL(TinyGsmSim7000SSL& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
bool init(TinyGsmSim7000SSL* 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("+CACLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(3000);
|
||||
}
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
class GsmClientSecureSIM7000SSL : public GsmClientSim7000SSL {
|
||||
public:
|
||||
GsmClientSecureSIM7000SSL() {}
|
||||
|
||||
explicit GsmClientSecureSIM7000SSL(TinyGsmSim7000SSL& modem,
|
||||
uint8_t mux = 0)
|
||||
: GsmClientSim7000SSL(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 {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||
};
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmSim7000SSL(Stream& stream)
|
||||
: TinyGsmSim70xx<TinyGsmSim7000SSL>(stream),
|
||||
certificates() {
|
||||
memset(sockets, 0, sizeof(sockets));
|
||||
}
|
||||
|
||||
/*
|
||||
* Basic functions
|
||||
*/
|
||||
protected:
|
||||
bool initImpl(const char* pin = NULL) {
|
||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||
DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7000SSL"));
|
||||
|
||||
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 Local Time Stamp for getting network time
|
||||
sendAT(GF("+CLTS=1"));
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
|
||||
// Enable battery checks
|
||||
sendAT(GF("+CBATCHK=1"));
|
||||
if (waitResponse() != 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 != NULL && 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);
|
||||
}
|
||||
}
|
||||
|
||||
void maintainImpl() {
|
||||
// Keep listening for modem URC's and proactively iterate through
|
||||
// sockets asking if any data is avaiable
|
||||
bool check_socks = false;
|
||||
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
|
||||
GsmClientSim7000SSL* sock = sockets[mux];
|
||||
if (sock && sock->got_data) {
|
||||
sock->got_data = false;
|
||||
check_socks = true;
|
||||
}
|
||||
}
|
||||
// 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); }
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
protected:
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+CNACT?"));
|
||||
if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
|
||||
streamSkipUntil('\"');
|
||||
String res = stream.readStringUntil('\"');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Secure socket layer 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPRS functions
|
||||
*/
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
// Define the PDP context
|
||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
// Attach to GPRS
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// NOTE: **DO NOT** activate the PDP context
|
||||
// For who only knows what reason, doing so screws up the rest of the
|
||||
// process
|
||||
|
||||
// Bearer settings for applications based on IP
|
||||
// Set the user name and password
|
||||
// AT+CNCFG=<ip_type>[,<APN>[,<usename>,<password>[,<authentication>]]]
|
||||
//<ip_type> 0: Dual PDN Stack
|
||||
// 1: Internet Protocol Version 4
|
||||
// 2: Internet Protocol Version 6
|
||||
//<authentication> 0: NONE
|
||||
// 1: PAP
|
||||
// 2: CHAP
|
||||
// 3: PAP or CHAP
|
||||
if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) {
|
||||
sendAT(GF("+CNCFG=1,\""), apn, "\",\"", "\",\"", user, pwd, '"');
|
||||
waitResponse();
|
||||
} else if (user && strlen(user) > 0) {
|
||||
// Set the user name only
|
||||
sendAT(GF("+CNCFG=1,\""), apn, "\",\"", user, '"');
|
||||
waitResponse();
|
||||
} else {
|
||||
// Set the APN only
|
||||
sendAT(GF("+CNCFG=1,\""), apn, '"');
|
||||
waitResponse();
|
||||
}
|
||||
|
||||
// Activate application network connection
|
||||
// This is for most other supported applications outside of the
|
||||
// TCP application toolkit (ie, SSL)
|
||||
// AT+CNACT=<mode>,<action>
|
||||
// <mode> 0: Deactive
|
||||
// 1: Active
|
||||
// 2: Auto Active
|
||||
bool res = false;
|
||||
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;
|
||||
waitResponse();
|
||||
ntries++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool gprsDisconnectImpl() {
|
||||
// Shut down the general application TCP/IP connection
|
||||
// CNACT will close *all* open application connections
|
||||
sendAT(GF("+CNACT=0"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
sendAT(GF("+CGATT=0")); // Deactivate the bearer context
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
protected:
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
protected:
|
||||
// Follows all messaging functions per template
|
||||
|
||||
/*
|
||||
* GPS/GNSS/GLONASS location functions
|
||||
*/
|
||||
protected:
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||
bool ssl = false, int timeout_s = 75) {
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
|
||||
// set the connection (mux) identifier to use
|
||||
sendAT(GF("+CACID="), mux);
|
||||
if (waitResponse(timeout_ms) != 1) return false;
|
||||
|
||||
|
||||
if (ssl) {
|
||||
// set the ssl version
|
||||
// AT+CSSLCFG="SSLVERSION",<ctxindex>,<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;
|
||||
}
|
||||
|
||||
// enable or disable ssl
|
||||
// AT+CASSLCFG=<cid>,"SSL",<sslFlag>
|
||||
// <cid> Application connection ID (set with AT+CACID above)
|
||||
// <sslFlag> 0: Not support SSL
|
||||
// 1: Support SSL
|
||||
sendAT(GF("+CASSLCFG="), mux, ',', GF("ssl,"), ssl);
|
||||
waitResponse();
|
||||
|
||||
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
|
||||
sendAT(GF("+CSSLCFG=\"ctxindex\",0"));
|
||||
if (waitResponse(5000L, GF("+CSSLCFG:")) != 1) return false;
|
||||
streamSkipUntil('\n'); // read out the certificate information
|
||||
waitResponse();
|
||||
|
||||
if (certificates[mux] != "") {
|
||||
// apply the correct certificate to the connection
|
||||
// AT+CASSLCFG=<cid>,"CACERT",<caname>
|
||||
// <cid> Application connection ID (set with AT+CACID above)
|
||||
// <certname> certificate name
|
||||
sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"", certificates[mux].c_str(),
|
||||
"\"");
|
||||
if (waitResponse(5000L) != 1) return false;
|
||||
}
|
||||
|
||||
// set the protocol
|
||||
// 0: TCP; 1: UDP
|
||||
sendAT(GF("+CASSLCFG="), mux, ',', GF("protocol,0"));
|
||||
waitResponse();
|
||||
|
||||
// set the SSL SNI (server name indication)
|
||||
// NOTE: despite docs using caps, "sni" must be in lower case
|
||||
sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\""));
|
||||
waitResponse();
|
||||
}
|
||||
|
||||
// actually open the connection
|
||||
// AT+CAOPEN=<cid>[,<conn_type>],<server>,<port>
|
||||
// <cid> TCP/UDP identifier
|
||||
// <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; }
|
||||
// returns OK/r/n/r/n+CAOPEN: <cid>,<result>
|
||||
// <result> 0: Success
|
||||
// 1: Socket error
|
||||
// 2: No memory
|
||||
// 3: Connection limit
|
||||
// 4: Parameter invalid
|
||||
// 6: Invalid IP address
|
||||
// 7: Not support the function
|
||||
// 12: Can’t bind the port
|
||||
// 13: Can’t listen the port
|
||||
// 20: Can’t resolve the host
|
||||
// 21: Network not active
|
||||
// 23: Remote refuse
|
||||
// 24: Certificate’s time expired
|
||||
// 25: Certificate’s common name does not match
|
||||
// 26: Certificate’s common name does not match and time expired
|
||||
// 27: Connect failed
|
||||
streamSkipUntil(','); // Skip mux
|
||||
|
||||
// make sure the connection really opened
|
||||
int8_t res = streamGetIntBefore('\n');
|
||||
waitResponse();
|
||||
|
||||
return 0 == res;
|
||||
}
|
||||
|
||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||
// send data on prompt
|
||||
sendAT(GF("+CASEND="), mux, ',', (uint16_t)len);
|
||||
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||
|
||||
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||
stream.flush();
|
||||
|
||||
// after posting data, module responds with:
|
||||
//+CASEND: <cid>,<result>,<sendlen>
|
||||
if (waitResponse(GF(GSM_NL "+CASEND:")) != 1) { return 0; }
|
||||
streamSkipUntil(','); // Skip mux
|
||||
if (streamGetIntBefore(',') != 0) { return 0; } // If result != success
|
||||
return streamGetIntBefore('\n');
|
||||
}
|
||||
|
||||
size_t modemRead(size_t size, uint8_t mux) {
|
||||
if (!sockets[mux]) { return 0; }
|
||||
|
||||
sendAT(GF("+CARECV="), mux, ',', (uint16_t)size);
|
||||
|
||||
if (waitResponse(GF("+CARECV:")) != 1) { return 0; }
|
||||
|
||||
// uint8_t ret_mux = stream.parseInt();
|
||||
// streamSkipUntil(',');
|
||||
// const int16_t len_confirmed = streamGetIntBefore('\n');
|
||||
// DBG("### READING:", len_confirmed, "from", ret_mux);
|
||||
|
||||
// if (ret_mux != mux) {
|
||||
// DBG("### Data from wrong mux! Got", ret_mux, "expected", mux);
|
||||
// waitResponse();
|
||||
// sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// NOTE: manual says the mux number is returned before the number of
|
||||
// characters available, but in tests only the number is returned
|
||||
|
||||
int16_t len_confirmed = stream.parseInt();
|
||||
streamSkipUntil(','); // skip the comma
|
||||
if (len_confirmed <= 0) {
|
||||
waitResponse();
|
||||
sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len_confirmed; 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);
|
||||
}
|
||||
waitResponse();
|
||||
// DBG("### READ:", len_confirmed, "from", mux);
|
||||
// make sure the sock available number is accurate again
|
||||
// the module is **EXTREMELY** testy about being asked to read more from
|
||||
// the buffer than exits; it will freeze until a hard reset or power cycle!
|
||||
sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||
return len_confirmed;
|
||||
}
|
||||
|
||||
size_t modemGetAvailable(uint8_t mux) {
|
||||
// If the socket doesn't exist, just return
|
||||
if (!sockets[mux]) { return 0; }
|
||||
// We need to check if there are any connections open *before* checking for
|
||||
// available characters. The SIM7000 *will crash* if you ask about data
|
||||
// when there are no open connections.
|
||||
if (!modemGetConnected(mux)) { return 0; }
|
||||
// NOTE: This gets how many characters are available on all connections that
|
||||
// have data. It does not return all the connections, just those with data.
|
||||
sendAT(GF("+CARECV?"));
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
// after the last connection, there's an ok, so we catch it right away
|
||||
int res = waitResponse(3000, GF("+CARECV:"), GFP(GSM_OK), GFP(GSM_ERROR));
|
||||
// if we get the +CARECV: response, read the mux number and the number of
|
||||
// characters available
|
||||
if (res == 1) {
|
||||
int ret_mux = streamGetIntBefore(',');
|
||||
size_t result = streamGetIntBefore('\n');
|
||||
GsmClientSim7000SSL* sock = sockets[ret_mux];
|
||||
if (sock) { sock->sock_available = result; }
|
||||
// if the first returned mux isn't 0 (or is higher than expected)
|
||||
// we need to fill in the missing muxes
|
||||
if (ret_mux > muxNo) {
|
||||
for (int extra_mux = muxNo; extra_mux < ret_mux; extra_mux++) {
|
||||
GsmClientSim7000SSL* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_available = 0; }
|
||||
}
|
||||
muxNo = ret_mux;
|
||||
}
|
||||
} else if (res == 2) {
|
||||
// if we get an OK, we've reached the last socket with available data
|
||||
// so we set any we haven't gotten to yet to 0
|
||||
for (int extra_mux = muxNo; extra_mux < TINY_GSM_MUX_COUNT;
|
||||
extra_mux++) {
|
||||
GsmClientSim7000SSL* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_available = 0; }
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// if we got an error, give up
|
||||
break;
|
||||
}
|
||||
// Should be a final OK at the end.
|
||||
// If every connection was returned, catch the OK here.
|
||||
// If only a portion were returned, catch it above.
|
||||
if (muxNo == TINY_GSM_MUX_COUNT - 1) { waitResponse(); }
|
||||
}
|
||||
modemGetConnected(mux); // check the state of all connections
|
||||
if (!sockets[mux]) { return 0; }
|
||||
return sockets[mux]->sock_available;
|
||||
}
|
||||
|
||||
bool modemGetConnected(uint8_t mux) {
|
||||
// NOTE: This gets the state of all connections that have been opened
|
||||
// since the last connection
|
||||
sendAT(GF("+CASTATE?"));
|
||||
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
// after the last connection, there's an ok, so we catch it right away
|
||||
int res = waitResponse(3000, GF("+CASTATE:"), GFP(GSM_OK),
|
||||
GFP(GSM_ERROR));
|
||||
// if we get the +CASTATE: response, read the mux number and the status
|
||||
if (res == 1) {
|
||||
int ret_mux = streamGetIntBefore(',');
|
||||
size_t status = streamGetIntBefore('\n');
|
||||
// 0: Closed by remote server or internal error
|
||||
// 1: Connected to remote server
|
||||
// 2: Listening (server mode)
|
||||
GsmClientSim7000SSL* sock = sockets[ret_mux];
|
||||
if (sock) { sock->sock_connected = (status == 1); }
|
||||
// if the first returned mux isn't 0 (or is higher than expected)
|
||||
// we need to fill in the missing muxes
|
||||
if (ret_mux > muxNo) {
|
||||
for (int extra_mux = muxNo; extra_mux < ret_mux; extra_mux++) {
|
||||
GsmClientSim7000SSL* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_connected = false; }
|
||||
}
|
||||
muxNo = ret_mux;
|
||||
}
|
||||
} else if (res == 2) {
|
||||
// if we get an OK, we've reached the last socket with available data
|
||||
// so we set any we haven't gotten to yet to 0
|
||||
for (int extra_mux = muxNo; extra_mux < TINY_GSM_MUX_COUNT;
|
||||
extra_mux++) {
|
||||
GsmClientSim7000SSL* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_connected = false; }
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// if we got an error, give up
|
||||
break;
|
||||
}
|
||||
// Should be a final OK at the end.
|
||||
// If every connection was returned, catch the OK here.
|
||||
// If only a portion were returned, catch it above.
|
||||
if (muxNo == TINY_GSM_MUX_COUNT - 1) { waitResponse(); }
|
||||
}
|
||||
return sockets[mux]->sock_connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = "";
|
||||
}
|
||||
}
|
||||
} while (millis() - startMillis < timeout_ms);
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
protected:
|
||||
GsmClientSim7000SSL* sockets[TINY_GSM_MUX_COUNT];
|
||||
String certificates[TINY_GSM_MUX_COUNT];
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMCLIENTSIM7000SSL_H_
|
729
src/TinyGsmClientSIM7080.h
Normal file
729
src/TinyGsmClientSIM7080.h
Normal file
@@ -0,0 +1,729 @@
|
||||
/**
|
||||
* @file TinyGsmClientSim7080.h
|
||||
* @author Volodymyr Shymanskyy
|
||||
* @license LGPL-3.0
|
||||
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef SRC_TINYGSMCLIENTSIM7080_H_
|
||||
#define SRC_TINYGSMCLIENTSIM7080_H_
|
||||
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
// #define TINY_GSM_USE_HEX
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 12
|
||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||
|
||||
#include "TinyGsmClientSIM70xx.h"
|
||||
#include "TinyGsmTCP.tpp"
|
||||
#include "TinyGsmSSL.tpp"
|
||||
|
||||
class TinyGsmSim7080 : public TinyGsmSim70xx<TinyGsmSim7080>,
|
||||
public TinyGsmTCP<TinyGsmSim7080, TINY_GSM_MUX_COUNT>,
|
||||
public TinyGsmSSL<TinyGsmSim7080> {
|
||||
friend class TinyGsmSim70xx<TinyGsmSim7080>;
|
||||
friend class TinyGsmTCP<TinyGsmSim7080, TINY_GSM_MUX_COUNT>;
|
||||
friend class TinyGsmSSL<TinyGsmSim7080>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
class GsmClientSim7080 : public GsmClient {
|
||||
friend class TinyGsmSim7080;
|
||||
|
||||
public:
|
||||
GsmClientSim7080() {}
|
||||
|
||||
explicit GsmClientSim7080(TinyGsmSim7080& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
bool init(TinyGsmSim7080* 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("+CACLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(3000);
|
||||
}
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
class GsmClientSecureSIM7080 : public GsmClientSim7080 {
|
||||
public:
|
||||
GsmClientSecureSIM7080() {}
|
||||
|
||||
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 {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||
};
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmSim7080(Stream& stream)
|
||||
: TinyGsmSim70xx<TinyGsmSim7080>(stream),
|
||||
certificates() {
|
||||
memset(sockets, 0, sizeof(sockets));
|
||||
}
|
||||
|
||||
/*
|
||||
* Basic functions
|
||||
*/
|
||||
protected:
|
||||
bool initImpl(const char* pin = NULL) {
|
||||
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; }
|
||||
|
||||
#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 Local Time Stamp for getting network time
|
||||
sendAT(GF("+CLTS=1"));
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
|
||||
// Enable battery checks
|
||||
sendAT(GF("+CBATCHK=1"));
|
||||
if (waitResponse() != 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 != NULL && 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);
|
||||
}
|
||||
}
|
||||
|
||||
void maintainImpl() {
|
||||
// Keep listening for modem URC's and proactively iterate through
|
||||
// sockets asking if any data is avaiable
|
||||
bool check_socks = false;
|
||||
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
|
||||
GsmClientSim7080* sock = sockets[mux];
|
||||
if (sock && sock->got_data) {
|
||||
sock->got_data = false;
|
||||
check_socks = true;
|
||||
}
|
||||
}
|
||||
// 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); }
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
protected:
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+CNACT?"));
|
||||
if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
|
||||
streamSkipUntil('\"');
|
||||
String res = stream.readStringUntil('\"');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Secure socket layer 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPRS functions
|
||||
*/
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
// Define the PDP context
|
||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
// Attach to GPRS
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// NOTE: **DO NOT** activate the PDP context
|
||||
// For who only knows what reason, doing so screws up the rest of the
|
||||
// process
|
||||
|
||||
// Check the APN returned by the server
|
||||
// not sure why, but the connection is more consistent with this
|
||||
sendAT(GF("+CGNAPN"));
|
||||
waitResponse();
|
||||
|
||||
// Bearer settings for applications based on IP
|
||||
// Set the user name and password
|
||||
// AT+CNCFG=<pdpidx>,<ip_type>,[<APN>,[<usename>,<password>,[<authentication>]]]
|
||||
// <pdpidx> PDP Context Identifier - for reasons not understood by me,
|
||||
// use PDP context identifier of 0 for what we defined as 1 above
|
||||
// <ip_type> 0: Dual PDN Stack
|
||||
// 1: Internet Protocol Version 4
|
||||
// 2: Internet Protocol Version 6
|
||||
// <authentication> 0: NONE
|
||||
// 1: PAP
|
||||
// 2: CHAP
|
||||
// 3: PAP or CHAP
|
||||
if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) {
|
||||
sendAT(GF("+CNCFG=0,1,\""), apn, "\",\"", user, "\",\"", pwd, '"');
|
||||
waitResponse();
|
||||
} else if (user && strlen(user) > 0) {
|
||||
// Set the user name only
|
||||
sendAT(GF("+CNCFG=0,1,\""), apn, "\",\"", user, '"');
|
||||
waitResponse();
|
||||
} else {
|
||||
// Set the APN only
|
||||
sendAT(GF("+CNCFG=0,1,\""), apn, '"');
|
||||
waitResponse();
|
||||
}
|
||||
|
||||
// Activate application network connection
|
||||
// AT+CNACT=<pdpidx>,<action>
|
||||
// <pdpidx> PDP Context Identifier - for reasons not understood by me,
|
||||
// use PDP context identifier of 0 for what we defined as 1 above
|
||||
// <action> 0: Deactive
|
||||
// 1: Active
|
||||
// 2: Auto Active
|
||||
bool res = false;
|
||||
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"));
|
||||
waitResponse();
|
||||
ntries++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool gprsDisconnectImpl() {
|
||||
// Shut down the general application TCP/IP connection
|
||||
// CNACT will close *all* open application connections
|
||||
sendAT(GF("+CNACT=0,0"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
sendAT(GF("+CGATT=0")); // Deactivate the bearer context
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
protected:
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
protected:
|
||||
// Follows all messaging functions per template
|
||||
|
||||
/*
|
||||
* GPS/GNSS/GLONASS location functions
|
||||
*/
|
||||
protected:
|
||||
// Follows the SIM70xx template
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||
bool ssl = false, int timeout_s = 75) {
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
|
||||
// set the connection (mux) identifier to use
|
||||
sendAT(GF("+CACID="), mux);
|
||||
if (waitResponse(timeout_ms) != 1) return false;
|
||||
|
||||
|
||||
if (ssl) {
|
||||
// set the ssl version
|
||||
// AT+CSSLCFG="SSLVERSION",<ctxindex>,<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;
|
||||
}
|
||||
|
||||
// enable or disable ssl
|
||||
// AT+CASSLCFG=<cid>,"SSL",<sslFlag>
|
||||
// <cid> Application connection ID (set with AT+CACID above)
|
||||
// <sslFlag> 0: Not support SSL
|
||||
// 1: Support SSL
|
||||
sendAT(GF("+CASSLCFG="), mux, ',', GF("SSL,"), ssl);
|
||||
waitResponse();
|
||||
|
||||
if (ssl) {
|
||||
// set the PDP context to apply SSL to
|
||||
// AT+CSSLCFG="CTXINDEX",<ctxindex>
|
||||
// <ctxindex> PDP context identifier
|
||||
// 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
|
||||
waitResponse();
|
||||
|
||||
if (certificates[mux] != "") {
|
||||
// apply the correct certificate to the connection
|
||||
// AT+CASSLCFG=<cid>,"CACERT",<caname>
|
||||
// <cid> Application connection ID (set with AT+CACID above)
|
||||
// <certname> certificate name
|
||||
sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"", certificates[mux].c_str(),
|
||||
"\"");
|
||||
if (waitResponse(5000L) != 1) return false;
|
||||
}
|
||||
|
||||
// set the SSL SNI (server name indication)
|
||||
// NOTE: despite docs using caps, "sni" must be in lower case
|
||||
sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\""));
|
||||
waitResponse();
|
||||
}
|
||||
|
||||
// actually open the connection
|
||||
// AT+CAOPEN=<cid>,<pdp_index>,<conn_type>,<server>,<port>[,<recv_mode>]
|
||||
// <cid> TCP/UDP identifier
|
||||
// <pdp_index> Index of PDP connection; we set up PCP context 1 above
|
||||
// <conn_type> "TCP" or "UDP"
|
||||
// <recv_mode> 0: The received data can only be read manually using
|
||||
// AT+CARECV=<cid>
|
||||
// 1: After receiving the data, it will automatically report
|
||||
// URC:
|
||||
// +CAURC:
|
||||
// "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; }
|
||||
// returns OK/r/n/r/n+CAOPEN: <cid>,<result>
|
||||
// <result> 0: Success
|
||||
// 1: Socket error
|
||||
// 2: No memory
|
||||
// 3: Connection limit
|
||||
// 4: Parameter invalid
|
||||
// 6: Invalid IP address
|
||||
// 7: Not support the function
|
||||
// 12: Can’t bind the port
|
||||
// 13: Can’t listen the port
|
||||
// 20: Can’t resolve the host
|
||||
// 21: Network not active
|
||||
// 23: Remote refuse
|
||||
// 24: Certificate’s time expired
|
||||
// 25: Certificate’s common name does not match
|
||||
// 26: Certificate’s common name does not match and time expired
|
||||
// 27: Connect failed
|
||||
streamSkipUntil(','); // Skip mux
|
||||
|
||||
// make sure the connection really opened
|
||||
int8_t res = streamGetIntBefore('\n');
|
||||
waitResponse();
|
||||
|
||||
return 0 == res;
|
||||
}
|
||||
|
||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||
// send data on prompt
|
||||
sendAT(GF("+CASEND="), mux, ',', (uint16_t)len);
|
||||
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||
|
||||
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||
stream.flush();
|
||||
|
||||
// OK after posting data
|
||||
if (waitResponse() != 1) { return 0; }
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t modemRead(size_t size, uint8_t mux) {
|
||||
if (!sockets[mux]) { return 0; }
|
||||
|
||||
sendAT(GF("+CARECV="), mux, ',', (uint16_t)size);
|
||||
|
||||
if (waitResponse(GF("+CARECV:")) != 1) { return 0; }
|
||||
|
||||
// uint8_t ret_mux = stream.parseInt();
|
||||
// streamSkipUntil(',');
|
||||
// const int16_t len_confirmed = streamGetIntBefore('\n');
|
||||
// DBG("### READING:", len_confirmed, "from", ret_mux);
|
||||
|
||||
// if (ret_mux != mux) {
|
||||
// DBG("### Data from wrong mux! Got", ret_mux, "expected", mux);
|
||||
// waitResponse();
|
||||
// sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// NOTE: manual says the mux number is returned before the number of
|
||||
// characters available, but in tests only the number is returned
|
||||
|
||||
int16_t len_confirmed = stream.parseInt();
|
||||
streamSkipUntil(','); // skip the comma
|
||||
if (len_confirmed <= 0) {
|
||||
waitResponse();
|
||||
sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len_confirmed; 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);
|
||||
}
|
||||
waitResponse();
|
||||
// make sure the sock available number is accurate again
|
||||
sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||
return len_confirmed;
|
||||
}
|
||||
|
||||
size_t modemGetAvailable(uint8_t mux) {
|
||||
// If the socket doesn't exist, just return
|
||||
if (!sockets[mux]) { return 0; }
|
||||
// NOTE: This gets how many characters are available on all connections that
|
||||
// have data. It does not return all the connections, just those with data.
|
||||
sendAT(GF("+CARECV?"));
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
// after the last connection, there's an ok, so we catch it right away
|
||||
int res = waitResponse(3000, GF("+CARECV:"), GFP(GSM_OK), GFP(GSM_ERROR));
|
||||
// if we get the +CARECV: response, read the mux number and the number of
|
||||
// characters available
|
||||
if (res == 1) {
|
||||
int ret_mux = streamGetIntBefore(',');
|
||||
size_t result = streamGetIntBefore('\n');
|
||||
GsmClientSim7080* sock = sockets[ret_mux];
|
||||
if (sock) { sock->sock_available = result; }
|
||||
// if the first returned mux isn't 0 (or is higher than expected)
|
||||
// we need to fill in the missing muxes
|
||||
if (ret_mux > muxNo) {
|
||||
for (int extra_mux = muxNo; extra_mux < ret_mux; extra_mux++) {
|
||||
GsmClientSim7080* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_available = 0; }
|
||||
}
|
||||
muxNo = ret_mux;
|
||||
}
|
||||
} else if (res == 2) {
|
||||
// if we get an OK, we've reached the last socket with available data
|
||||
// so we set any we haven't gotten to yet to 0
|
||||
for (int extra_mux = muxNo; extra_mux < TINY_GSM_MUX_COUNT;
|
||||
extra_mux++) {
|
||||
GsmClientSim7080* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_available = 0; }
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// if we got an error, give up
|
||||
break;
|
||||
}
|
||||
// Should be a final OK at the end.
|
||||
// If every connection was returned, catch the OK here.
|
||||
// If only a portion were returned, catch it above.
|
||||
if (muxNo == TINY_GSM_MUX_COUNT - 1) { waitResponse(); }
|
||||
}
|
||||
modemGetConnected(mux); // check the state of all connections
|
||||
if (!sockets[mux]) { return 0; }
|
||||
return sockets[mux]->sock_available;
|
||||
}
|
||||
|
||||
bool modemGetConnected(uint8_t mux) {
|
||||
// NOTE: This gets the state of all connections that have been opened
|
||||
// since the last connection
|
||||
sendAT(GF("+CASTATE?"));
|
||||
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
// after the last connection, there's an ok, so we catch it right away
|
||||
int res = waitResponse(3000, GF("+CASTATE:"), GFP(GSM_OK),
|
||||
GFP(GSM_ERROR));
|
||||
// if we get the +CASTATE: response, read the mux number and the status
|
||||
if (res == 1) {
|
||||
int ret_mux = streamGetIntBefore(',');
|
||||
size_t status = streamGetIntBefore('\n');
|
||||
// 0: Closed by remote server or internal error
|
||||
// 1: Connected to remote server
|
||||
// 2: Listening (server mode)
|
||||
GsmClientSim7080* sock = sockets[ret_mux];
|
||||
if (sock) { sock->sock_connected = (status == 1); }
|
||||
// if the first returned mux isn't 0 (or is higher than expected)
|
||||
// we need to fill in the missing muxes
|
||||
if (ret_mux > muxNo) {
|
||||
for (int extra_mux = muxNo; extra_mux < ret_mux; extra_mux++) {
|
||||
GsmClientSim7080* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_connected = false; }
|
||||
}
|
||||
muxNo = ret_mux;
|
||||
}
|
||||
} else if (res == 2) {
|
||||
// if we get an OK, we've reached the last socket with available data
|
||||
// so we set any we haven't gotten to yet to 0
|
||||
for (int extra_mux = muxNo; extra_mux < TINY_GSM_MUX_COUNT;
|
||||
extra_mux++) {
|
||||
GsmClientSim7080* isock = sockets[extra_mux];
|
||||
if (isock) { isock->sock_connected = false; }
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// if we got an error, give up
|
||||
break;
|
||||
}
|
||||
// Should be a final OK at the end.
|
||||
// If every connection was returned, catch the OK here.
|
||||
// If only a portion were returned, catch it above.
|
||||
if (muxNo == TINY_GSM_MUX_COUNT - 1) { waitResponse(); }
|
||||
}
|
||||
return sockets[mux]->sock_connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = "";
|
||||
}
|
||||
}
|
||||
} while (millis() - startMillis < timeout_ms);
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
protected:
|
||||
GsmClientSim7080* sockets[TINY_GSM_MUX_COUNT];
|
||||
String certificates[TINY_GSM_MUX_COUNT];
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMCLIENTSIM7080_H_
|
459
src/TinyGsmClientSIM70xx.h
Normal file
459
src/TinyGsmClientSIM70xx.h
Normal file
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* @file TinyGsmClientSIM70xx.h
|
||||
* @author Volodymyr Shymanskyy
|
||||
* @license LGPL-3.0
|
||||
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef SRC_TINYGSMCLIENTSIM70XX_H_
|
||||
#define SRC_TINYGSMCLIENTSIM70XX_H_
|
||||
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
// #define TINY_GSM_USE_HEX
|
||||
|
||||
#include "TinyGsmBattery.tpp"
|
||||
#include "TinyGsmGPRS.tpp"
|
||||
#include "TinyGsmGPS.tpp"
|
||||
#include "TinyGsmModem.tpp"
|
||||
#include "TinyGsmSMS.tpp"
|
||||
#include "TinyGsmTime.tpp"
|
||||
#include "TinyGsmNTP.tpp"
|
||||
#include "TinyGsmGSMLocation.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 {
|
||||
REG_NO_RESULT = -1,
|
||||
REG_UNREGISTERED = 0,
|
||||
REG_SEARCHING = 2,
|
||||
REG_DENIED = 3,
|
||||
REG_OK_HOME = 1,
|
||||
REG_OK_ROAMING = 5,
|
||||
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>>;
|
||||
|
||||
/*
|
||||
* CRTP Helper
|
||||
*/
|
||||
protected:
|
||||
inline const modemType& thisModem() const {
|
||||
return static_cast<const modemType&>(*this);
|
||||
}
|
||||
inline modemType& thisModem() {
|
||||
return static_cast<modemType&>(*this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmSim70xx(Stream& stream) : stream(stream) {}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
thisModem().sendAT(GF("E0")); // Echo Off
|
||||
thisModem().waitResponse();
|
||||
if (!thisModem().setPhoneFunctionality(0)) { return false; }
|
||||
if (!thisModem().setPhoneFunctionality(1, true)) { return false; }
|
||||
thisModem().waitResponse(30000L, GF("SMS Ready"));
|
||||
return thisModem().initImpl(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
thisModem().sendAT(GF("+CPOWD=1"));
|
||||
return thisModem().waitResponse(GF("NORMAL POWER DOWN")) == 1;
|
||||
}
|
||||
|
||||
// During sleep, the SIM70xx module has its serial communication disabled.
|
||||
// In order to reestablish communication pull the DRT-pin of the SIM70xx
|
||||
// module LOW for at least 50ms. Then use this function to disable sleep
|
||||
// mode. The DTR-pin can then be released again.
|
||||
bool sleepEnableImpl(bool enable = true) {
|
||||
thisModem().sendAT(GF("+CSCLK="), enable);
|
||||
return thisModem().waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
|
||||
thisModem().sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
|
||||
return thisModem().waitResponse(10000L) == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
public:
|
||||
RegStatus getRegistrationStatus() {
|
||||
RegStatus epsStatus =
|
||||
(RegStatus)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");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isNetworkConnectedImpl() {
|
||||
RegStatus s = getRegistrationStatus();
|
||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||
}
|
||||
|
||||
public:
|
||||
String getNetworkModes() {
|
||||
// Get the help string, not the setting value
|
||||
thisModem().sendAT(GF("+CNMP=?"));
|
||||
if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
thisModem().waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
int16_t getNetworkMode() {
|
||||
thisModem().sendAT(GF("+CNMP?"));
|
||||
if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
|
||||
int16_t mode = thisModem().streamGetIntBefore('\n');
|
||||
thisModem().waitResponse();
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool setNetworkMode(uint8_t mode) {
|
||||
// 2 Automatic
|
||||
// 13 GSM only
|
||||
// 38 LTE only
|
||||
// 51 GSM and LTE only
|
||||
thisModem().sendAT(GF("+CNMP="), mode);
|
||||
return thisModem().waitResponse() == 1;
|
||||
}
|
||||
|
||||
String getPreferredModes() {
|
||||
// Get the help string, not the setting value
|
||||
thisModem().sendAT(GF("+CMNB=?"));
|
||||
if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
thisModem().waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
int16_t getPreferredMode() {
|
||||
thisModem().sendAT(GF("+CMNB?"));
|
||||
if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return false; }
|
||||
int16_t mode = thisModem().streamGetIntBefore('\n');
|
||||
thisModem().waitResponse();
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool setPreferredMode(uint8_t mode) {
|
||||
// 1 CAT-M
|
||||
// 2 NB-IoT
|
||||
// 3 CAT-M and NB-IoT
|
||||
thisModem().sendAT(GF("+CMNB="), mode);
|
||||
return thisModem().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
|
||||
thisModem().sendAT(GF("+CNSMOD?"));
|
||||
if (thisModem().waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { return false; }
|
||||
n = thisModem().streamGetIntBefore(',') != 0;
|
||||
stat = thisModem().streamGetIntBefore('\n');
|
||||
thisModem().waitResponse();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setNetworkSystemMode(bool n) {
|
||||
// n: whether to automatically report the system mode info
|
||||
thisModem().sendAT(GF("+CNSMOD="), int8_t(n));
|
||||
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
|
||||
*/
|
||||
protected:
|
||||
// Doesn't return the "+CCID" before the number
|
||||
String getSimCCIDImpl() {
|
||||
thisModem().sendAT(GF("+CCID"));
|
||||
if (thisModem().waitResponse(GF(GSM_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
|
||||
*/
|
||||
protected:
|
||||
// enable GPS
|
||||
bool enableGPSImpl() {
|
||||
thisModem().sendAT(GF("+CGNSPWR=1"));
|
||||
if (thisModem().waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disableGPSImpl() {
|
||||
thisModem().sendAT(GF("+CGNSPWR=0"));
|
||||
if (thisModem().waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the RAW GPS output
|
||||
String getGPSrawImpl() {
|
||||
thisModem().sendAT(GF("+CGNSINF"));
|
||||
if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
String res = stream.readStringUntil('\n');
|
||||
thisModem().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) {
|
||||
thisModem().sendAT(GF("+CGNSINF"));
|
||||
if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
thisModem().streamSkipUntil(','); // GNSS run status
|
||||
if (thisModem().streamGetIntBefore(',') == 1) { // fix status
|
||||
// init variables
|
||||
float ilat = 0;
|
||||
float ilon = 0;
|
||||
float ispeed = 0;
|
||||
float ialt = 0;
|
||||
int ivsat = 0;
|
||||
int iusat = 0;
|
||||
float iaccuracy = 0;
|
||||
int iyear = 0;
|
||||
int imonth = 0;
|
||||
int iday = 0;
|
||||
int ihour = 0;
|
||||
int imin = 0;
|
||||
float secondWithSS = 0;
|
||||
|
||||
// UTC date & Time
|
||||
iyear = thisModem().streamGetIntLength(4); // Four digit year
|
||||
imonth = thisModem().streamGetIntLength(2); // Two digit month
|
||||
iday = thisModem().streamGetIntLength(2); // Two digit day
|
||||
ihour = thisModem().streamGetIntLength(2); // Two digit hour
|
||||
imin = thisModem().streamGetIntLength(2); // Two digit minute
|
||||
secondWithSS = thisModem().streamGetFloatBefore(
|
||||
','); // 6 digit second with subseconds
|
||||
|
||||
ilat = thisModem().streamGetFloatBefore(','); // Latitude
|
||||
ilon = thisModem().streamGetFloatBefore(','); // Longitude
|
||||
ialt = thisModem().streamGetFloatBefore(
|
||||
','); // MSL Altitude. Unit is meters
|
||||
ispeed = thisModem().streamGetFloatBefore(
|
||||
','); // Speed Over Ground. Unit is knots.
|
||||
thisModem().streamSkipUntil(','); // Course Over Ground. Degrees.
|
||||
thisModem().streamSkipUntil(','); // Fix Mode
|
||||
thisModem().streamSkipUntil(','); // Reserved1
|
||||
iaccuracy = thisModem().streamGetFloatBefore(
|
||||
','); // Horizontal Dilution Of Precision
|
||||
thisModem().streamSkipUntil(','); // Position Dilution Of Precision
|
||||
thisModem().streamSkipUntil(','); // Vertical Dilution Of Precision
|
||||
thisModem().streamSkipUntil(','); // Reserved2
|
||||
ivsat = thisModem().streamGetIntBefore(','); // GNSS Satellites in View
|
||||
iusat = thisModem().streamGetIntBefore(','); // GNSS Satellites Used
|
||||
thisModem().streamSkipUntil(','); // GLONASS Satellites Used
|
||||
thisModem().streamSkipUntil(','); // Reserved3
|
||||
thisModem().streamSkipUntil(','); // C/N0 max
|
||||
thisModem().streamSkipUntil(','); // HPA
|
||||
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 (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);
|
||||
|
||||
thisModem().waitResponse();
|
||||
return true;
|
||||
}
|
||||
|
||||
thisModem().streamSkipUntil('\n'); // toss the row of commas
|
||||
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);
|
||||
}
|
||||
|
||||
public:
|
||||
Stream& stream;
|
||||
|
||||
protected:
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMCLIENTSIM70XX_H_
|
@@ -16,6 +16,7 @@
|
||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||
|
||||
#include "TinyGsmBattery.tpp"
|
||||
#include "TinyGsmCalling.tpp"
|
||||
#include "TinyGsmGPRS.tpp"
|
||||
#include "TinyGsmGPS.tpp"
|
||||
#include "TinyGsmGSMLocation.tpp"
|
||||
@@ -24,6 +25,8 @@
|
||||
#include "TinyGsmTCP.tpp"
|
||||
#include "TinyGsmTemperature.tpp"
|
||||
#include "TinyGsmTime.tpp"
|
||||
#include "TinyGsmNTP.tpp"
|
||||
|
||||
|
||||
#define GSM_NL "\r\n"
|
||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||
@@ -50,8 +53,10 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
public TinyGsmGSMLocation<TinyGsmSim7600>,
|
||||
public TinyGsmGPS<TinyGsmSim7600>,
|
||||
public TinyGsmTime<TinyGsmSim7600>,
|
||||
public TinyGsmNTP<TinyGsmSim7600>,
|
||||
public TinyGsmBattery<TinyGsmSim7600>,
|
||||
public TinyGsmTemperature<TinyGsmSim7600> {
|
||||
public TinyGsmTemperature<TinyGsmSim7600>,
|
||||
public TinyGsmCalling<TinyGsmSim7600> {
|
||||
friend class TinyGsmModem<TinyGsmSim7600>;
|
||||
friend class TinyGsmGPRS<TinyGsmSim7600>;
|
||||
friend class TinyGsmTCP<TinyGsmSim7600, TINY_GSM_MUX_COUNT>;
|
||||
@@ -59,8 +64,10 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
friend class TinyGsmGPS<TinyGsmSim7600>;
|
||||
friend class TinyGsmGSMLocation<TinyGsmSim7600>;
|
||||
friend class TinyGsmTime<TinyGsmSim7600>;
|
||||
friend class TinyGsmNTP<TinyGsmSim7600>;
|
||||
friend class TinyGsmBattery<TinyGsmSim7600>;
|
||||
friend class TinyGsmTemperature<TinyGsmSim7600>;
|
||||
friend class TinyGsmCalling<TinyGsmSim7600>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
@@ -219,12 +226,12 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+CRESET"));
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
delay(5000L); // TODO(?): Test this delay!
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -271,12 +278,17 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
return res;
|
||||
}
|
||||
|
||||
String setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
int16_t getNetworkMode() {
|
||||
sendAT(GF("+CNMP?"));
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
|
||||
int16_t mode = streamGetIntBefore('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
String getLocalIPImpl() {
|
||||
@@ -398,11 +410,10 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
* Phone Call functions
|
||||
*/
|
||||
protected:
|
||||
bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool dtmfSendImpl(char cmd,
|
||||
int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callHangupImpl() {
|
||||
sendAT(GF("+CHUP"));
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
@@ -435,7 +446,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
|
||||
// get the RAW GPS output
|
||||
String getGPSrawImpl() {
|
||||
sendAT(GF("+CGNSSINFO=32"));
|
||||
sendAT(GF("+CGNSSINFO"));
|
||||
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
@@ -558,6 +569,11 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
// Can sync with server using CNTP as per template
|
||||
|
||||
/*
|
||||
* Battery functions
|
||||
*/
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "TinyGsmSSL.tpp"
|
||||
#include "TinyGsmTCP.tpp"
|
||||
#include "TinyGsmTime.tpp"
|
||||
#include "TinyGsmNTP.tpp"
|
||||
|
||||
#define GSM_NL "\r\n"
|
||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||
@@ -51,6 +52,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
public TinyGsmSMS<TinyGsmSim800>,
|
||||
public TinyGsmGSMLocation<TinyGsmSim800>,
|
||||
public TinyGsmTime<TinyGsmSim800>,
|
||||
public TinyGsmNTP<TinyGsmSim800>,
|
||||
public TinyGsmBattery<TinyGsmSim800> {
|
||||
friend class TinyGsmModem<TinyGsmSim800>;
|
||||
friend class TinyGsmGPRS<TinyGsmSim800>;
|
||||
@@ -60,6 +62,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
friend class TinyGsmSMS<TinyGsmSim800>;
|
||||
friend class TinyGsmGSMLocation<TinyGsmSim800>;
|
||||
friend class TinyGsmTime<TinyGsmSim800>;
|
||||
friend class TinyGsmNTP<TinyGsmSim800>;
|
||||
friend class TinyGsmBattery<TinyGsmSim800>;
|
||||
|
||||
/*
|
||||
@@ -250,14 +253,14 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("&W"));
|
||||
waitResponse();
|
||||
if (!setPhoneFunctionality(0)) { return false; }
|
||||
if (!setPhoneFunctionality(1, true)) { return false; }
|
||||
delay(3000);
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -315,20 +318,23 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
// Set the Bearer for the IP
|
||||
sendAT(GF(
|
||||
"+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS
|
||||
// Bearer settings for applications based on IP
|
||||
// Set the connection type to GPRS
|
||||
sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\""));
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN
|
||||
// Set the APN
|
||||
sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
// Set the user name
|
||||
if (user && strlen(user) > 0) {
|
||||
sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name
|
||||
sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');
|
||||
waitResponse();
|
||||
}
|
||||
// Set the password
|
||||
if (pwd && strlen(pwd) > 0) {
|
||||
sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password
|
||||
sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');
|
||||
waitResponse();
|
||||
}
|
||||
|
||||
@@ -351,8 +357,6 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// TODO(?): wait AT+CGATT?
|
||||
|
||||
// Set to multi-IP
|
||||
sendAT(GF("+CIPMUX=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
@@ -441,12 +445,56 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
protected:
|
||||
// No functions of this type supported
|
||||
|
||||
/*
|
||||
* Audio functions
|
||||
*/
|
||||
public:
|
||||
bool setVolume(uint8_t volume = 50) {
|
||||
// Set speaker volume
|
||||
sendAT(GF("+CLVL="), volume);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
uint8_t getVolume() {
|
||||
// Get speaker volume
|
||||
sendAT(GF("+CLVL?"));
|
||||
if (waitResponse(GF(GSM_NL)) != 1) { return 0; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
res.replace("+CLVL:", "");
|
||||
res.trim();
|
||||
return res.toInt();
|
||||
}
|
||||
|
||||
bool setMicVolume(uint8_t channel, uint8_t level) {
|
||||
if (channel > 4) { return 0; }
|
||||
sendAT(GF("+CMIC="), level);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool setAudioChannel(uint8_t channel) {
|
||||
sendAT(GF("+CHFA="), channel);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool playToolkitTone(uint8_t tone, uint32_t duration) {
|
||||
sendAT(GF("STTONE="), 1, tone);
|
||||
delay(duration);
|
||||
sendAT(GF("STTONE="), 0);
|
||||
return waitResponse();
|
||||
}
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
// Can sync with server using CNTP as per template
|
||||
|
||||
/*
|
||||
* Battery functions
|
||||
*/
|
||||
@@ -456,50 +504,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
public:
|
||||
boolean isValidNumber(String str) {
|
||||
if (!(str.charAt(0) == '+' || str.charAt(0) == '-' ||
|
||||
isDigit(str.charAt(0))))
|
||||
return false;
|
||||
|
||||
for (byte i = 1; i < str.length(); i++) {
|
||||
if (!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String ShowNTPError(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);
|
||||
}
|
||||
}
|
||||
|
||||
byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
|
||||
// Set GPRS bearer profile to associate with NTP sync
|
||||
sendAT(GF("+CNTPCID=1"));
|
||||
if (waitResponse(10000L) != 1) { return -1; }
|
||||
|
||||
// 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(GSM_NL "+CNTP:"))) {
|
||||
String result = stream.readStringUntil('\n');
|
||||
result.trim();
|
||||
if (isValidNumber(result)) { return result.toInt(); }
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// Can sync with server using CNTP as per template
|
||||
|
||||
/*
|
||||
* Client related functions
|
||||
|
@@ -12,9 +12,11 @@
|
||||
|
||||
#include "TinyGsmClientSIM800.h"
|
||||
#include "TinyGsmGPS.tpp"
|
||||
#include "TinyGsmBluetooth.tpp"
|
||||
|
||||
class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
|
||||
class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808>, public TinyGsmBluetooth<TinyGsmSim808> {
|
||||
friend class TinyGsmGPS<TinyGsmSim808>;
|
||||
friend class TinyGsmBluetooth<TinyGsmSim808>;
|
||||
|
||||
public:
|
||||
explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {}
|
||||
@@ -127,6 +129,40 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
|
||||
waitResponse();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bluetooth functions
|
||||
*/
|
||||
|
||||
bool enableBluetoothImpl() {
|
||||
sendAT(GF("+BTPOWER=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disableBluetoothImpl() {
|
||||
sendAT(GF("+BTPOWER=0"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setBluetoothVisibilityImpl(bool visible) {
|
||||
sendAT(GF("+BTVIS="), visible);
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setBluetoothHostNameImpl(const char* name) {
|
||||
sendAT(GF("+BTHOST="), name);
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMCLIENTSIM808_H_
|
||||
|
@@ -297,11 +297,11 @@ class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4>,
|
||||
*/
|
||||
protected:
|
||||
// using +CFUN=15 instead of the more common CFUN=1,1
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
if (!setPhoneFunctionality(15)) { return false; }
|
||||
delay(3000); // TODO(?): Verify delay timing here
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
|
@@ -98,7 +98,7 @@ class TinyGsmSequansMonarch
|
||||
} else {
|
||||
this->mux = (mux % TINY_GSM_MUX_COUNT) + 1;
|
||||
}
|
||||
at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
|
||||
at->sockets[this->mux % TINY_GSM_MUX_COUNT] = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -283,7 +283,7 @@ class TinyGsmSequansMonarch
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
|
||||
sendAT(GF("+CFUN=0"));
|
||||
@@ -295,7 +295,7 @@ class TinyGsmSequansMonarch
|
||||
res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR));
|
||||
if (res != 1 && res != 3) { return false; }
|
||||
delay(1000);
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -467,8 +467,8 @@ class TinyGsmSequansMonarch
|
||||
// <recvDataMode1> = Receive data mode = 0 - data as text (1 for hex)
|
||||
// <keepalive1> = unused = 0
|
||||
// <listenAutoRsp1> = Listen auto-response mode = 0 - deactivated
|
||||
// <sendDataMode1> = Send data mode = 0 - data as text (1 for hex)
|
||||
sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0"));
|
||||
// <sendDataMode1> = Send data mode = 1 - data as hex (0 for text)
|
||||
sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,1"));
|
||||
waitResponse(5000L);
|
||||
|
||||
// Socket dial
|
||||
@@ -508,7 +508,13 @@ class TinyGsmSequansMonarch
|
||||
|
||||
sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len);
|
||||
waitResponse(10000L, GF(GSM_NL "> "));
|
||||
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||
// 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++) {
|
||||
memset(&char_command, 0, sizeof(char_command));
|
||||
sprintf(&char_command[0], "%02X", reinterpret_cast<const uint8_t*>(buff)[i]);
|
||||
stream.write(char_command, sizeof(char_command));
|
||||
}
|
||||
stream.flush();
|
||||
if (waitResponse() != 1) {
|
||||
DBG("### no OK after send");
|
||||
@@ -596,7 +602,7 @@ class TinyGsmSequansMonarch
|
||||
// SOCK_LISTENING = 4,
|
||||
// SOCK_INCOMING = 5,
|
||||
// SOCK_OPENING = 6,
|
||||
GsmClientSequansMonarch* sock = sockets[mux % TINY_GSM_MUX_COUNT];
|
||||
GsmClientSequansMonarch* sock = sockets[muxNo % TINY_GSM_MUX_COUNT];
|
||||
if (sock) {
|
||||
sock->sock_connected = ((status != SOCK_CLOSED) &&
|
||||
(status != SOCK_INCOMING) &&
|
||||
@@ -720,7 +726,8 @@ class TinyGsmSequansMonarch
|
||||
|
||||
protected:
|
||||
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
// GSM_NL (\r\n) is not accepted with SQNSSENDEXT in data mode so use \n
|
||||
const char* gsmNL = "\n";
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
|
||||
|
@@ -193,7 +193,9 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
|
||||
|
||||
// Enable automatic time zome update
|
||||
sendAT(GF("+CTZU=1"));
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
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
|
||||
@@ -222,7 +224,6 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
|
||||
res2.trim();
|
||||
|
||||
String name = res1 + String(' ') + res2;
|
||||
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!");
|
||||
@@ -243,11 +244,11 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
|
||||
* Power functions
|
||||
*/
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!testAT()) { return false; }
|
||||
if (!setPhoneFunctionality(16)) { return false; }
|
||||
delay(3000); // TODO(?): Verify delay timing here
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool powerOffImpl() {
|
||||
@@ -270,6 +271,29 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
|
||||
return (RegStatus)getRegistrationStatusXREG("CGREG");
|
||||
}
|
||||
|
||||
bool setRadioAccessTecnology(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 getCurrentRadioAccessTecnology(int&) {
|
||||
// @TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isNetworkConnectedImpl() {
|
||||
RegStatus s = getRegistrationStatus();
|
||||
@@ -772,7 +796,7 @@ class TinyGsmUBLOX : public TinyGsmModem<TinyGsmUBLOX>,
|
||||
if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
|
||||
}
|
||||
data = "";
|
||||
DBG("### URC Data Received:", len, "on", mux);
|
||||
// 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]) {
|
||||
|
@@ -108,12 +108,12 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
}
|
||||
|
||||
public:
|
||||
// NOTE: The XBee saves all connection information (ssid/pwd or apn AND
|
||||
// last used IP address) in flash (NVM). When you turn it on it immediately
|
||||
// prepares to re-connect to whatever was last set. The TCP connection
|
||||
// itself is not opened until you attempt to send data. Because all settings
|
||||
// are saved to flash, it is possible (or likely) that you could send data
|
||||
// even if you haven't "made" any connection.
|
||||
// NOTE: The XBee saves all connection information (ssid/pwd etc) except
|
||||
// IP address and port number, in flash (NVM).
|
||||
// The NVM is be updated only when it is initialized.
|
||||
// The TCP connection itself is not opened until you attempt to send data.
|
||||
// Because all settings are saved to flash, it is possible (or likely) that
|
||||
// you could send data even if you haven't "made" any connection.
|
||||
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
// NOTE: Not caling stop() or yeild() here
|
||||
at->streamClear(); // Empty anything in the buffer before starting
|
||||
@@ -242,7 +242,10 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
String remoteIP() {
|
||||
IPAddress savedIP = at->savedIP;
|
||||
return TinyGsmStringFromIp(savedIP);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -329,25 +332,43 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
digitalWrite(resetPin, HIGH);
|
||||
}
|
||||
|
||||
if (pin && strlen(pin) > 0) {
|
||||
DBG("XBee's do not support SIMs that require an unlock pin!");
|
||||
}
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(10, false)
|
||||
|
||||
sendAT(GF("AP0")); // Put in transparent mode
|
||||
bool ret_val = waitResponse() == 1;
|
||||
bool changesMade = false;
|
||||
bool ret_val = true;
|
||||
|
||||
sendAT(GF("GT64")); // shorten the guard time to 100ms
|
||||
ret_val &= waitResponse() == 1;
|
||||
if (ret_val) guardTime = 110;
|
||||
// if there's a pin, we need to re-write to flash each time
|
||||
if (pin && strlen(pin) > 0) {
|
||||
sendAT(GF("PN"), pin);
|
||||
if (waitResponse() != 1) {
|
||||
ret_val = false;
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Put in transparent mode, if it isn't already
|
||||
changesMade |= changeSettingIfNeeded(GF("AP"), 0x0);
|
||||
|
||||
// shorten the guard time to 100ms, if it was anything else
|
||||
sendAT(GF("GT"));
|
||||
if (readResponseInt() != 0x64) {
|
||||
sendAT(GF("GT"), 64);
|
||||
ret_val &= waitResponse() == 1;
|
||||
if (ret_val) {
|
||||
guardTime = 110;
|
||||
changesMade = true;
|
||||
}
|
||||
} else {
|
||||
guardTime = 110;
|
||||
}
|
||||
|
||||
// Make sure the command mode drop-out time is long enough that we won't
|
||||
// fall out of command mode without intentionally leaving it. This is the
|
||||
// default drop out time of 0x64 x 100ms (10 seconds)
|
||||
sendAT(GF("CT64"));
|
||||
ret_val &= waitResponse() == 1;
|
||||
ret_val &= writeChanges();
|
||||
changesMade |= changeSettingIfNeeded(GF("CT"), 0x64);
|
||||
|
||||
if (changesMade) { ret_val &= writeChanges(); }
|
||||
|
||||
getSeries(); // Get the "Hardware Series";
|
||||
|
||||
@@ -362,25 +383,26 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
|
||||
void setBaudImpl(uint32_t baud) {
|
||||
XBEE_COMMAND_START_DECORATOR(5, )
|
||||
bool changesMade = false;
|
||||
switch (baud) {
|
||||
case 2400: sendAT(GF("BD1")); break;
|
||||
case 4800: sendAT(GF("BD2")); break;
|
||||
case 9600: sendAT(GF("BD3")); break;
|
||||
case 19200: sendAT(GF("BD4")); break;
|
||||
case 38400: sendAT(GF("BD5")); break;
|
||||
case 57600: sendAT(GF("BD6")); break;
|
||||
case 115200: sendAT(GF("BD7")); break;
|
||||
case 230400: sendAT(GF("BD8")); break;
|
||||
case 460800: sendAT(GF("BD9")); break;
|
||||
case 921600: sendAT(GF("BDA")); break;
|
||||
case 2400: changesMade |= changeSettingIfNeeded(GF("BD"), 0x1); break;
|
||||
case 4800: changesMade |= changeSettingIfNeeded(GF("BD"), 0x2); break;
|
||||
case 9600: changesMade |= changeSettingIfNeeded(GF("BD"), 0x3); break;
|
||||
case 19200: changesMade |= changeSettingIfNeeded(GF("BD"), 0x4); break;
|
||||
case 38400: changesMade |= changeSettingIfNeeded(GF("BD"), 0x5); break;
|
||||
case 57600: changesMade |= changeSettingIfNeeded(GF("BD"), 0x6); break;
|
||||
case 115200: changesMade |= changeSettingIfNeeded(GF("BD"), 0x7); break;
|
||||
case 230400: changesMade |= changeSettingIfNeeded(GF("BD"), 0x8); break;
|
||||
case 460800: changesMade |= changeSettingIfNeeded(GF("BD"), 0x9); break;
|
||||
case 921600: changesMade |= changeSettingIfNeeded(GF("BD"), 0xA); break;
|
||||
default: {
|
||||
DBG(GF("Specified baud rate is unsupported! Setting to 9600 baud."));
|
||||
sendAT(GF("BD3")); // Set to default of 9600
|
||||
changesMade |= changeSettingIfNeeded(GF("BD"),
|
||||
0x3); // Set to default of 9600
|
||||
break;
|
||||
}
|
||||
}
|
||||
waitResponse();
|
||||
writeChanges();
|
||||
if (changesMade) { writeChanges(); }
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
}
|
||||
|
||||
@@ -468,7 +490,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
case XBEE_3G: return "Digi XBee Cellular 3G";
|
||||
case XBEE3_LTE1_ATT: return "Digi XBee3 Cellular LTE CAT 1";
|
||||
case XBEE3_LTEM_ATT: return "Digi XBee3 Cellular LTE-M";
|
||||
default: return "Digi XBee";
|
||||
default: return "Digi XBee Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,11 +506,17 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
digitalWrite(resetPin, LOW);
|
||||
delay(1);
|
||||
digitalWrite(resetPin, HIGH);
|
||||
} else {
|
||||
DBG("### Attempting a modem software restart");
|
||||
restartImpl();
|
||||
}
|
||||
}
|
||||
|
||||
bool restartImpl() {
|
||||
if (!commandMode()) { return false; } // Return immediately
|
||||
bool restartImpl(const char* pin = NULL) {
|
||||
if (!commandMode()) {
|
||||
DBG("### XBee not in command mode for restart; Exit");
|
||||
return false;
|
||||
} // Return immediately
|
||||
|
||||
if (beeType == XBEE_UNKNOWN) getSeries(); // how we restart depends on this
|
||||
|
||||
@@ -525,7 +553,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
|
||||
exitCommand();
|
||||
|
||||
return init();
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
void setupPinSleep(bool maintainAssociation = false) {
|
||||
@@ -533,20 +561,21 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
|
||||
if (beeType == XBEE_UNKNOWN) getSeries(); // Command depends on series
|
||||
|
||||
sendAT(GF("SM"), 1); // Pin sleep
|
||||
waitResponse();
|
||||
bool changesMade = false;
|
||||
|
||||
// Pin sleep
|
||||
changesMade |= changeSettingIfNeeded(GF("SM"), 0x1);
|
||||
|
||||
if (beeType == XBEE_S6B_WIFI && !maintainAssociation) {
|
||||
sendAT(GF("SO"), 200); // For lowest power, dissassociated deep sleep
|
||||
waitResponse();
|
||||
// For lowest power, dissassociated deep sleep
|
||||
changesMade |= changeSettingIfNeeded(GF("SO"), 0x200);
|
||||
} else if (!maintainAssociation) {
|
||||
sendAT(GF("SO"),
|
||||
1); // For supported cellular modules, maintain association
|
||||
// Not supported by all modules, will return "ERROR"
|
||||
waitResponse();
|
||||
// For supported cellular modules, maintain association
|
||||
// Not supported by all modules, will return "ERROR"
|
||||
changesMade |= changeSettingIfNeeded(GF("SO"), 0x1);
|
||||
}
|
||||
|
||||
writeChanges();
|
||||
if (changesMade) { writeChanges(); }
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
}
|
||||
|
||||
@@ -555,6 +584,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
sendAT(GF("SD"));
|
||||
bool ret_val = waitResponse(120000L) == 1;
|
||||
// make sure we're really shut down
|
||||
if (ret_val) { ret_val &= (sendATGetString(GF("AI")) == "2D"); }
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
return ret_val;
|
||||
@@ -562,12 +592,13 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
|
||||
// Enable airplane mode
|
||||
bool radioOffImpl() {
|
||||
bool success = true;
|
||||
bool changesMade = false;
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
sendAT(GF("AM1"));
|
||||
int8_t res = (1 == waitResponse(5000));
|
||||
writeChanges();
|
||||
changesMade = changeSettingIfNeeded(GF("AM"), 0x1, 5000L);
|
||||
if (changesMade) { success = writeChanges(); }
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
return res;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
@@ -698,23 +729,33 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
}
|
||||
|
||||
bool isNetworkConnectedImpl() {
|
||||
// first check for association indicator
|
||||
RegStatus s = getRegistrationStatus();
|
||||
if (s == REG_OK) {
|
||||
IPAddress ip = localIP();
|
||||
if (ip != IPAddress(0, 0, 0, 0)) {
|
||||
return true;
|
||||
if (beeType == XBEE_S6B_WIFI) {
|
||||
// For wifi bees, if the association indicator is ok, check that a both
|
||||
// a local IP and DNS have been allocated
|
||||
IPAddress ip = localIP();
|
||||
IPAddress dns = getDNSAddress();
|
||||
if (ip != IPAddress(0, 0, 0, 0) && dns != IPAddress(0, 0, 0, 0)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) {
|
||||
bool waitForNetworkImpl(uint32_t timeout_ms = 60000L,
|
||||
bool check_signal = false) {
|
||||
bool retVal = false;
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||
if (check_signal) { getSignalQuality(); }
|
||||
if (isNetworkConnected()) {
|
||||
retVal = true;
|
||||
break;
|
||||
@@ -737,30 +778,63 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
return IPaddr;
|
||||
}
|
||||
|
||||
String getDNS() {
|
||||
XBEE_COMMAND_START_DECORATOR(5, "")
|
||||
switch (beeType) {
|
||||
case XBEE_S6B_WIFI: {
|
||||
sendAT(GF("NS"));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sendAT(GF("N1"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
String DNSaddr;
|
||||
DNSaddr.reserve(16);
|
||||
// wait for the response - this response can be very slow
|
||||
DNSaddr = readResponseString(30000);
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
DNSaddr.trim();
|
||||
return DNSaddr;
|
||||
}
|
||||
|
||||
IPAddress getDNSAddress() {
|
||||
return TinyGsmIpFromString(getDNS());
|
||||
}
|
||||
|
||||
/*
|
||||
* WiFi functions
|
||||
*/
|
||||
protected:
|
||||
bool networkConnectImpl(const char* ssid, const char* pwd) {
|
||||
bool retVal = true;
|
||||
bool changesMade = false;
|
||||
bool retVal = true;
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
|
||||
// nh For no pwd don't set set security or pwd
|
||||
if (ssid == NULL) retVal = false;
|
||||
|
||||
changesMade |= changeSettingIfNeeded(GF("ID"), ssid);
|
||||
|
||||
if (pwd && strlen(pwd) > 0) {
|
||||
sendAT(GF("EE"), 2); // Set security to WPA2
|
||||
if (waitResponse() != 1) retVal = false;
|
||||
// Set security to WPA2
|
||||
changesMade |= changeSettingIfNeeded(GF("EE"), 0x2);
|
||||
// set the password
|
||||
// the wifi bee will NOT return the previously set password,
|
||||
// so we have no way of knowing if the passwords has changed
|
||||
// and must re-write to flash each time
|
||||
sendAT(GF("PK"), pwd);
|
||||
if (waitResponse() != 1) {
|
||||
retVal = false;
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
} else {
|
||||
sendAT(GF("EE"), 0); // Set No security
|
||||
changesMade |= changeSettingIfNeeded(GF("EE"), 0x0); // Set No security
|
||||
}
|
||||
if (waitResponse() != 1) retVal = false;
|
||||
|
||||
sendAT(GF("ID"), ssid);
|
||||
if (waitResponse() != 1) retVal = false;
|
||||
|
||||
if (!writeChanges()) retVal = false;
|
||||
if (changesMade) { retVal &= writeChanges(); }
|
||||
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
|
||||
@@ -784,36 +858,48 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
bool success = true;
|
||||
bool success = true;
|
||||
bool changesMade = false;
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
|
||||
// the cellular bees will NOT return the previously set username or
|
||||
// password, so we have no way of knowing if they have changed
|
||||
// and must re-write to flash each time
|
||||
if (user && strlen(user) > 0) {
|
||||
sendAT(GF("CU"), user); // Set the user for the APN
|
||||
success &= waitResponse() == 1;
|
||||
if (waitResponse() != 1) {
|
||||
success = false;
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
if (pwd && strlen(pwd) > 0) {
|
||||
sendAT(GF("CW"), pwd); // Set the password for the APN
|
||||
success &= waitResponse() == 1;
|
||||
if (waitResponse() != 1) {
|
||||
success = false;
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
sendAT(GF("AN"), apn); // Set the APN
|
||||
success &= waitResponse() == 1;
|
||||
sendAT(GF("AM0")); // Airplane mode off
|
||||
waitResponse(5000);
|
||||
writeChanges();
|
||||
changesMade |= changeSettingIfNeeded(GF("AN"), String(apn)); // Set the APN
|
||||
|
||||
changesMade |= changeSettingIfNeeded(GF("AM"), 0x0,
|
||||
5000L); // Airplane mode off
|
||||
|
||||
if (changesMade) { success = writeChanges(); }
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
return success;
|
||||
}
|
||||
|
||||
bool gprsDisconnectImpl() {
|
||||
bool success = true;
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
sendAT(
|
||||
GF("AM1")); // Cheating and disconnecting by turning on airplane mode
|
||||
int8_t res = (1 == waitResponse(5000));
|
||||
writeChanges();
|
||||
// sendAT(GF("AM0")); // Airplane mode off
|
||||
// waitResponse(5000);
|
||||
// writeChanges();
|
||||
// Cheating and disconnecting by turning on airplane mode
|
||||
bool changesMade = changeSettingIfNeeded(GF("AM"), 0x1, 5000L);
|
||||
|
||||
if (changesMade) { success = writeChanges(); }
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
return res;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool isGprsConnectedImpl() {
|
||||
@@ -828,7 +914,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
* SIM card functions
|
||||
*/
|
||||
protected:
|
||||
bool simUnlockImpl(const char* pin) { // Not supported
|
||||
bool simUnlockImpl(const char* pin) {
|
||||
if (pin && strlen(pin) > 0) {
|
||||
sendAT(GF("PN"), pin);
|
||||
return waitResponse() == 1;
|
||||
@@ -859,17 +945,43 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
bool sendSMSImpl(const String& number, const String& text) {
|
||||
bool changesMade = false;
|
||||
if (!commandMode()) { return false; } // Return immediately
|
||||
|
||||
sendAT(GF("IP"), 2); // Put in text messaging mode
|
||||
if (waitResponse() != 1) return exitAndFail();
|
||||
sendAT(GF("PH"), number); // Set the phone number
|
||||
if (waitResponse() != 1) return exitAndFail();
|
||||
sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriage
|
||||
// return)
|
||||
if (waitResponse() != 1) return exitAndFail();
|
||||
sendAT(GF("IP")); // check mode
|
||||
if (readResponseInt() != 2) {
|
||||
sendAT(GF("IP"), 2); // Put in text messaging mode
|
||||
if (waitResponse() != 1) {
|
||||
return exitAndFail();
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeChanges()) return exitAndFail();
|
||||
sendAT(GF("PH")); // check last number
|
||||
if (readResponseString() != String(number)) {
|
||||
sendAT(GF("PH"), number); // Set the phone number
|
||||
if (waitResponse() != 1) {
|
||||
return exitAndFail();
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
sendAT(GF("TD")); // check the text delimiter
|
||||
if (readResponseString() != String("D")) {
|
||||
sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D
|
||||
//(carriage return)
|
||||
if (waitResponse() != 1) {
|
||||
return exitAndFail();
|
||||
} else {
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changesMade) {
|
||||
if (!writeChanges()) return exitAndFail();
|
||||
}
|
||||
// Get out of command mode to actually send the text
|
||||
exitCommand();
|
||||
|
||||
@@ -1021,13 +1133,14 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
|
||||
bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0,
|
||||
bool ssl = false) {
|
||||
bool success = true;
|
||||
bool success = true;
|
||||
bool changesMade = false;
|
||||
|
||||
if (mux != 0) {
|
||||
DBG("XBee only supports 1 IP channel in transparent mode!");
|
||||
}
|
||||
|
||||
// empty the saved currelty-in-use destination address
|
||||
// empty the saved currenty-in-use destination address
|
||||
savedOperatingIP = IPAddress(0, 0, 0, 0);
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
@@ -1046,21 +1159,27 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
host += ip[3];
|
||||
|
||||
if (ssl) {
|
||||
sendAT(GF("IP"), 4); // Put in SSL over TCP communication mode
|
||||
success &= (1 == waitResponse());
|
||||
// Put in SSL over TCP communication mode
|
||||
changesMade |= changeSettingIfNeeded(GF("IP"), 0x4);
|
||||
} else {
|
||||
sendAT(GF("IP"), 1); // Put in TCP mode
|
||||
success &= (1 == waitResponse());
|
||||
// Put in unsecured TCP mode
|
||||
changesMade |= changeSettingIfNeeded(GF("IP"), 0x1);
|
||||
}
|
||||
bool changesMadeSSL = changesMade;
|
||||
|
||||
sendAT(GF("DL"), host); // Set the "Destination Address Low"
|
||||
success &= (1 == waitResponse());
|
||||
sendAT(GF("DE"), String(port, HEX)); // Set the destination port
|
||||
success &= (1 == waitResponse());
|
||||
changesMade |= changeSettingIfNeeded(
|
||||
GF("DL"), String(host)); // Set the "Destination Address Low"
|
||||
changesMade |= changeSettingIfNeeded(
|
||||
GF("DE"), String(port, HEX)); // Set the destination port
|
||||
|
||||
success &= writeChanges();
|
||||
// WiFi Bee is different
|
||||
if (beeType == XBEE_S6B_WIFI) { changesMade = changesMadeSSL; }
|
||||
|
||||
if (changesMade) { success &= writeChanges(); }
|
||||
}
|
||||
|
||||
// confirm the XBee type if needed so we know if we can know if connected
|
||||
if (beeType == XBEE_UNKNOWN) { getSeries(); }
|
||||
// we'll accept either unknown or connected
|
||||
if (beeType != XBEE_S6B_WIFI) {
|
||||
uint16_t ci = getConnectionIndicator();
|
||||
@@ -1081,25 +1200,21 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
|
||||
// Get the current socket timeout
|
||||
sendAT(GF("TM"));
|
||||
String timeoutUsed = readResponseString(5000L);
|
||||
// For WiFi models, there's no direct way to close the socket;
|
||||
// use DigiXBeeWifi::disconnectInternet(void)
|
||||
|
||||
// For WiFi models, there's no direct way to close the socket. This is a
|
||||
// hack to shut the socket by setting the timeout to zero.
|
||||
if (beeType == XBEE_S6B_WIFI) {
|
||||
sendAT(GF("TM0")); // Set socket timeout to 0
|
||||
waitResponse(maxWaitMs); // This response can be slow
|
||||
writeChanges();
|
||||
if (beeType != XBEE_S6B_WIFI) {
|
||||
// Get the current socket timeout
|
||||
sendAT(GF("TM"));
|
||||
String timeoutUsed = readResponseString(5000L);
|
||||
|
||||
// For cellular models, per documentation: If you write the TM (socket
|
||||
// timeout) value while in Transparent Mode, the current connection is
|
||||
// immediately closed - this works even if the TM values is unchanged
|
||||
sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout
|
||||
waitResponse(maxWaitMs); // This response can be slow
|
||||
}
|
||||
|
||||
// For cellular models, per documentation: If you write the TM (socket
|
||||
// timeout) value while in Transparent Mode, the current connection is
|
||||
// immediately closed - this works even if the TM values is unchanged
|
||||
sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout
|
||||
waitResponse(maxWaitMs); // This response can be slow
|
||||
writeChanges();
|
||||
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
return true;
|
||||
}
|
||||
@@ -1114,11 +1229,11 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
if (beeType != XBEE_S6B_WIFI) {
|
||||
// After a send, verify the outgoing ip if it isn't set
|
||||
if (savedOperatingIP == IPAddress(0, 0, 0, 0)) {
|
||||
modemGetConnected();
|
||||
modemGetConnected(0);
|
||||
} else if (len > 5) {
|
||||
// After sending several characters, also re-check
|
||||
// NOTE: I'm intentionally not checking after every single character!
|
||||
modemGetConnected();
|
||||
modemGetConnected(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1129,7 +1244,7 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
// after data has been sent on the socket. If it returns 0xFF the socket may
|
||||
// really be open, but no data has yet been sent. We return this unknown
|
||||
// value as true so there's a possibility it's wrong.
|
||||
bool modemGetConnected() {
|
||||
bool modemGetConnected(uint8_t) {
|
||||
// If the IP address is 0, it's not valid so we can't be connected
|
||||
if (savedIP == IPAddress(0, 0, 0, 0)) { return false; }
|
||||
|
||||
@@ -1347,9 +1462,11 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
if (inCommandMode && (millis() - lastCommandModeMillis) < 10000L)
|
||||
return true;
|
||||
|
||||
uint8_t triesMade = 0;
|
||||
uint8_t triesUntilReset = 4; // only reset after 4 failures
|
||||
uint8_t triesMade = 0;
|
||||
int8_t res;
|
||||
bool success = false;
|
||||
uint8_t triesUntilReset = 4; // reset after number of tries
|
||||
if (beeType == XBEE_S6B_WIFI) { triesUntilReset = 9; }
|
||||
streamClear(); // Empty everything in the buffer before starting
|
||||
|
||||
while (!success && triesMade < retries) {
|
||||
@@ -1357,8 +1474,15 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
// Default guard time is 1s, but the init fxn decreases it to 100 ms
|
||||
delay(guardTime + 10);
|
||||
streamWrite(GF("+++")); // enter command mode
|
||||
int8_t res = waitResponse(guardTime * 2);
|
||||
success = (1 == res);
|
||||
|
||||
if (beeType != XBEE_S6B_WIFI) {
|
||||
res = waitResponse(guardTime * 2);
|
||||
} else {
|
||||
// S6B wait a full second for OK
|
||||
res = waitResponse();
|
||||
}
|
||||
|
||||
success = (1 == res);
|
||||
if (0 == res) {
|
||||
triesUntilReset--;
|
||||
if (triesUntilReset == 0) {
|
||||
@@ -1367,6 +1491,9 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
delay(250); // a short delay to allow it to come back up
|
||||
// TODO(SRGDamia1) optimize this
|
||||
}
|
||||
if (beeType == XBEE_S6B_WIFI) {
|
||||
delay(5000); // WiFi module frozen, wait longer
|
||||
}
|
||||
}
|
||||
triesMade++;
|
||||
}
|
||||
@@ -1402,8 +1529,17 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
void getSeries(void) {
|
||||
sendAT(GF("HS")); // Get the "Hardware Series";
|
||||
int16_t intRes = readResponseInt();
|
||||
beeType = (XBeeType)intRes;
|
||||
DBG(GF("### Modem: "), getModemName());
|
||||
// if no response from module, then try again
|
||||
if (0xff == intRes) {
|
||||
sendAT(GF("HS")); // Get the "Hardware Series";
|
||||
intRes = readResponseInt();
|
||||
if (0xff == intRes) {
|
||||
// Still no response, leave a known value - should reset
|
||||
intRes = XBEE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
beeType = (XBeeType)intRes;
|
||||
DBG(GF("### Modem: "), getModemName(), beeType);
|
||||
}
|
||||
|
||||
String readResponseString(uint32_t timeout_ms = 1000) {
|
||||
@@ -1436,6 +1572,45 @@ class TinyGsmXBee : public TinyGsmModem<TinyGsmXBee>,
|
||||
return res;
|
||||
}
|
||||
|
||||
bool changeSettingIfNeeded(GsmConstStr cmd, int16_t newValue,
|
||||
uint32_t timeout_ms = 1000L) {
|
||||
sendAT(cmd);
|
||||
if (readResponseInt() != newValue) {
|
||||
sendAT(cmd, newValue);
|
||||
// return false if we attempted to change but failed
|
||||
if (waitResponse(timeout_ms) != 1) { return false; }
|
||||
// check if we succeeded in staging a change and retry once
|
||||
sendAT(cmd);
|
||||
if (readResponseInt() != newValue) {
|
||||
sendAT(cmd, newValue);
|
||||
if (waitResponse(timeout_ms) != 1) { return false; }
|
||||
}
|
||||
// return true if we succeeded in staging a change
|
||||
return true;
|
||||
}
|
||||
// return false if no change is needed
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changeSettingIfNeeded(GsmConstStr cmd, String newValue,
|
||||
uint32_t timeout_ms = 1000L) {
|
||||
sendAT(cmd);
|
||||
if (readResponseString() != newValue) {
|
||||
sendAT(cmd, newValue);
|
||||
// return false if we attempted to change but failed
|
||||
if (waitResponse(timeout_ms) != 1) { return false; }
|
||||
// check if we succeeded in staging a change and retry once
|
||||
sendAT(cmd);
|
||||
if (readResponseString() != newValue) {
|
||||
sendAT(cmd, newValue);
|
||||
if (waitResponse(timeout_ms) != 1) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// return false if no change is needed
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gotIPforSavedHost() {
|
||||
if (savedHost != "" && savedHostIP != IPAddress(0, 0, 0, 0))
|
||||
return true;
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#define SRC_TINYGSMCOMMON_H_
|
||||
|
||||
// The current library version number
|
||||
#define TINYGSM_VERSION "0.10.9"
|
||||
#define TINYGSM_VERSION "0.11.7"
|
||||
|
||||
#if defined(SPARK) || defined(PARTICLE)
|
||||
#include "Particle.h"
|
||||
@@ -41,7 +41,7 @@
|
||||
__attribute__((error("Not available on this modem type")))
|
||||
#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
|
||||
|
||||
#if defined(__AVR__)
|
||||
#if defined(__AVR__) && !defined(__AVR_ATmega4809__)
|
||||
#define TINY_GSM_PROGMEM PROGMEM
|
||||
typedef const __FlashStringHelper* GsmConstStr;
|
||||
#define GFP(x) (reinterpret_cast<GsmConstStr>(x))
|
||||
|
@@ -122,6 +122,11 @@ public:
|
||||
return n - c;
|
||||
}
|
||||
|
||||
uint8_t peek()
|
||||
{
|
||||
return _b[_r];
|
||||
}
|
||||
|
||||
private:
|
||||
int _inc(int i, int n = 1)
|
||||
{
|
||||
|
@@ -53,8 +53,8 @@ class TinyGsmModem {
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
bool restart() {
|
||||
return thisModem().restartImpl();
|
||||
bool restart(const char* pin = NULL) {
|
||||
return thisModem().restartImpl(pin);
|
||||
}
|
||||
bool poweroff() {
|
||||
return thisModem().powerOffImpl();
|
||||
@@ -77,8 +77,8 @@ class TinyGsmModem {
|
||||
return thisModem().isNetworkConnectedImpl();
|
||||
}
|
||||
// Waits for network attachment
|
||||
bool waitForNetwork(uint32_t timeout_ms = 60000L) {
|
||||
return thisModem().waitForNetworkImpl(timeout_ms);
|
||||
bool waitForNetwork(uint32_t timeout_ms = 60000L, bool check_signal = false) {
|
||||
return thisModem().waitForNetworkImpl(timeout_ms, check_signal);
|
||||
}
|
||||
// Gets signal quality report
|
||||
int16_t getSignalQuality() {
|
||||
@@ -192,15 +192,18 @@ class TinyGsmModem {
|
||||
GF("+CEREG:"));
|
||||
if (resp != 1 && resp != 2 && resp != 3) { return -1; }
|
||||
thisModem().streamSkipUntil(','); /* Skip format (0) */
|
||||
int status = thisModem().streamGetIntBefore('\n');
|
||||
int status = thisModem().stream.parseInt();
|
||||
thisModem().waitResponse();
|
||||
return status;
|
||||
}
|
||||
|
||||
bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) {
|
||||
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);
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
92
src/TinyGsmNTP.tpp
Normal file
92
src/TinyGsmNTP.tpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file TinyGsmNTP.tpp
|
||||
* @author Volodymyr Shymanskyy
|
||||
* @license LGPL-3.0
|
||||
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef SRC_TINYGSMNTP_H_
|
||||
#define SRC_TINYGSMNTP_H_
|
||||
|
||||
#include "TinyGsmCommon.h"
|
||||
|
||||
#define TINY_GSM_MODEM_HAS_NTP
|
||||
|
||||
template <class modemType>
|
||||
class TinyGsmNTP {
|
||||
public:
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
|
||||
public:
|
||||
bool TinyGsmIsValidNumber(String str) {
|
||||
if (!(str.charAt(0) == '+' || str.charAt(0) == '-' ||
|
||||
isDigit(str.charAt(0))))
|
||||
return false;
|
||||
|
||||
for (byte i = 1; i < str.length(); i++) {
|
||||
if (!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) { return false; }
|
||||
}
|
||||
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
|
||||
*/
|
||||
protected:
|
||||
inline const modemType& thisModem() const {
|
||||
return static_cast<const modemType&>(*this);
|
||||
}
|
||||
inline modemType& thisModem() {
|
||||
return static_cast<modemType&>(*this);
|
||||
}
|
||||
|
||||
/*
|
||||
* NTP server functions
|
||||
*/
|
||||
protected:
|
||||
byte NTPServerSyncImpl(String server = "pool.ntp.org", byte TimeZone = 3) {
|
||||
// Set GPRS bearer profile to associate with NTP sync
|
||||
// this may fail, it's not supported by all modules
|
||||
thisModem().sendAT(GF("+CNTPCID=1"));
|
||||
thisModem().waitResponse(10000L);
|
||||
|
||||
// Set NTP server and timezone
|
||||
thisModem().sendAT(GF("+CNTP=\""), server, "\",", String(TimeZone));
|
||||
if (thisModem().waitResponse(10000L) != 1) { return -1; }
|
||||
|
||||
// Request network synchronization
|
||||
thisModem().sendAT(GF("+CNTP"));
|
||||
if (thisModem().waitResponse(10000L, GF("+CNTP:"))) {
|
||||
String result = thisModem().stream.readStringUntil('\n');
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SRC_TINYGSMNTP_H_
|
@@ -73,7 +73,7 @@ class TinyGsmSMS {
|
||||
|
||||
static inline String TinyGsmDecodeHex8bit(String& instr) {
|
||||
String result;
|
||||
for (uint8_t i = 0; i < instr.length(); i += 2) {
|
||||
for (uint16_t i = 0; i < instr.length(); i += 2) {
|
||||
char buf[4] = {
|
||||
0,
|
||||
};
|
||||
@@ -87,7 +87,7 @@ class TinyGsmSMS {
|
||||
|
||||
static inline String TinyGsmDecodeHex16bit(String& instr) {
|
||||
String result;
|
||||
for (uint8_t i = 0; i < instr.length(); i += 4) {
|
||||
for (uint16_t i = 0; i < instr.length(); i += 4) {
|
||||
char buf[4] = {
|
||||
0,
|
||||
};
|
||||
|
@@ -141,6 +141,8 @@ class TinyGsmTCP {
|
||||
// with the modem to see if anything has arrived without a UURC.
|
||||
if (!rx.size()) {
|
||||
if (millis() - prev_check > 500) {
|
||||
// setting got_data to true will tell maintain to run
|
||||
// modemGetAvailable(mux)
|
||||
got_data = true;
|
||||
prev_check = millis();
|
||||
}
|
||||
@@ -211,6 +213,8 @@ class TinyGsmTCP {
|
||||
}
|
||||
// Workaround: Some modules "forget" to notify about data arrival
|
||||
if (millis() - prev_check > 500) {
|
||||
// setting got_data to true will tell maintain to run
|
||||
// modemGetAvailable()
|
||||
got_data = true;
|
||||
prev_check = millis();
|
||||
}
|
||||
@@ -237,10 +241,9 @@ class TinyGsmTCP {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO(SRGDamia1): Implement peek
|
||||
int peek() override {
|
||||
return -1;
|
||||
}
|
||||
int peek() override {
|
||||
return (uint8_t)rx.peek();
|
||||
}
|
||||
|
||||
void flush() override {
|
||||
at->stream.flush();
|
||||
@@ -248,7 +251,22 @@ class TinyGsmTCP {
|
||||
|
||||
uint8_t connected() override {
|
||||
if (available()) { return true; }
|
||||
#if defined TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||
// If the modem is one where we can read and check the size of the buffer,
|
||||
// then the 'available()' function will call a check of the current size
|
||||
// of the buffer and state of the connection. [available calls maintain,
|
||||
// maintain calls modemGetAvailable, modemGetAvailable calls
|
||||
// modemGetConnected] This cascade means that the sock_connected value
|
||||
// should be correct and all we need
|
||||
return sock_connected;
|
||||
#elif defined TINY_GSM_NO_MODEM_BUFFER || defined TINY_GSM_BUFFER_READ_NO_CHECK
|
||||
// If the modem doesn't have an internal buffer, or if we can't check how
|
||||
// many characters are in the buffer then the cascade won't happen.
|
||||
// We need to call modemGetConnected to check the sock state.
|
||||
return at->modemGetConnected(mux);
|
||||
#else
|
||||
#error Modem client has been incorrectly created
|
||||
#endif
|
||||
}
|
||||
operator bool() override {
|
||||
return connected();
|
||||
|
@@ -29,11 +29,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
|
||||
|
@@ -15,6 +15,8 @@
|
||||
// #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_UBLOX
|
||||
@@ -35,11 +37,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
// Increase RX buffer to capture the entire response
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
@@ -56,11 +61,13 @@
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
|
||||
// Range to attempt to autobaud
|
||||
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
|
||||
// communication, set a fixed baud rate using modem.setBaud(#).
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud
|
||||
// rate #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Uncomment this if you want to use SSL
|
||||
// #define USE_SSL
|
||||
@@ -72,16 +79,16 @@
|
||||
#define GSM_PIN ""
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
// Your WiFi connection credentials, if applicable
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char resource[] = "/TinyGSM/logo.txt";
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
@@ -101,19 +108,19 @@ const char resource[] = "/TinyGSM/logo.txt";
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifdef USE_SSL && defined TINY_GSM_MODEM_HAS_SSL
|
||||
TinyGsmClientSecure client(modem);
|
||||
const int port = 443;
|
||||
#ifdef USE_SSL&& defined TINY_GSM_MODEM_HAS_SSL
|
||||
TinyGsmClientSecure client(modem);
|
||||
const int port = 443;
|
||||
#else
|
||||
TinyGsmClient client(modem);
|
||||
const int port = 80;
|
||||
TinyGsmClient client(modem);
|
||||
const int port = 80;
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
@@ -138,14 +145,14 @@ void loop() {
|
||||
// To skip it, call init() instead of restart()
|
||||
SerialMon.print("Initializing modem...");
|
||||
if (!modem.restart()) {
|
||||
// if (!modem.init()) {
|
||||
// if (!modem.init()) {
|
||||
SerialMon.println(F(" [fail]"));
|
||||
SerialMon.println(F("************************"));
|
||||
SerialMon.println(F(" Is your modem connected properly?"));
|
||||
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 useing 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;
|
||||
@@ -158,9 +165,7 @@ void loop() {
|
||||
|
||||
#if TINY_GSM_USE_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_USE_WIFI
|
||||
@@ -180,7 +185,8 @@ void loop() {
|
||||
#endif
|
||||
|
||||
SerialMon.print("Waiting for network...");
|
||||
if (!modem.waitForNetwork(600000L)) { // You may need lengthen this in poor service areas
|
||||
if (!modem.waitForNetwork(
|
||||
600000L)) { // You may need lengthen this in poor service areas
|
||||
SerialMon.println(F(" [fail]"));
|
||||
SerialMon.println(F("************************"));
|
||||
SerialMon.println(F(" Is your sim card locked?"));
|
||||
@@ -238,12 +244,12 @@ void loop() {
|
||||
client.find("\r\n\r\n");
|
||||
|
||||
// Read data
|
||||
uint32_t timeout = millis();
|
||||
uint32_t timeout = millis();
|
||||
uint32_t bytesReceived = 0;
|
||||
while (client.connected() && millis() - timeout < 10000L) {
|
||||
while (client.available()) {
|
||||
char c = client.read();
|
||||
//SerialMon.print(c);
|
||||
// SerialMon.print(c);
|
||||
bytesReceived += 1;
|
||||
timeout = millis();
|
||||
}
|
||||
@@ -263,15 +269,13 @@ void loop() {
|
||||
|
||||
SerialMon.println();
|
||||
SerialMon.println(F("************************"));
|
||||
SerialMon.print (F(" Received: "));
|
||||
SerialMon.print(F(" Received: "));
|
||||
SerialMon.print(bytesReceived);
|
||||
SerialMon.println(F(" bytes"));
|
||||
SerialMon.print (F(" Test: "));
|
||||
SerialMon.print(F(" Test: "));
|
||||
SerialMon.println((bytesReceived == 121) ? "PASSED" : "FAILED");
|
||||
SerialMon.println(F("************************"));
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
while (true) { delay(1000); }
|
||||
}
|
||||
|
@@ -32,11 +32,14 @@
|
||||
|
||||
// Set serial for AT commands (to the module)
|
||||
// Use Hardware Serial on Mega, Leonardo, Micro
|
||||
#ifndef __AVR_ATmega328P__
|
||||
#define SerialAT Serial1
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
#endif
|
||||
|
||||
#include <StreamDebugger.h>
|
||||
StreamDebugger debugger(SerialAT, SerialMon);
|
||||
|
@@ -37,6 +37,7 @@ void loop() {
|
||||
modem.isNetworkConnected();
|
||||
modem.waitForNetwork();
|
||||
modem.waitForNetwork(15000L);
|
||||
modem.waitForNetwork(15000L, true);
|
||||
modem.getSignalQuality();
|
||||
modem.getLocalIP();
|
||||
modem.localIP();
|
||||
@@ -118,7 +119,7 @@ void loop() {
|
||||
#endif
|
||||
|
||||
// Test the calling functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_CALLING)
|
||||
#if defined(TINY_GSM_MODEM_HAS_CALLING) && not defined(__AVR_ATmega32U4__)
|
||||
modem.callNumber(String("+380000000000"));
|
||||
modem.callHangup();
|
||||
|
||||
@@ -130,7 +131,7 @@ void loop() {
|
||||
#endif
|
||||
|
||||
// Test the SMS functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_SMS)
|
||||
#if defined(TINY_GSM_MODEM_HAS_SMS) && not defined(__AVR_ATmega32U4__)
|
||||
modem.sendSMS(String("+380000000000"), String("Hello from "));
|
||||
|
||||
#if not defined(TINY_GSM_MODEM_XBEE) && not defined(TINY_GSM_MODEM_SARAR4)
|
||||
@@ -145,7 +146,7 @@ void loop() {
|
||||
#endif
|
||||
|
||||
// Test the GSM location functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_GSM_LOCATION)
|
||||
#if defined(TINY_GSM_MODEM_HAS_GSM_LOCATION) && not defined(__AVR_ATmega32U4__)
|
||||
modem.getGsmLocationRaw();
|
||||
modem.getGsmLocation();
|
||||
float glatitude = -9999;
|
||||
@@ -164,7 +165,7 @@ void loop() {
|
||||
#endif
|
||||
|
||||
// Test the GPS functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_GPS)
|
||||
#if defined(TINY_GSM_MODEM_HAS_GPS) && not defined(__AVR_ATmega32U4__)
|
||||
modem.enableGPS();
|
||||
modem.getGPSraw();
|
||||
float latitude = -9999;
|
||||
@@ -187,7 +188,12 @@ void loop() {
|
||||
#endif
|
||||
|
||||
// Test the Network time function
|
||||
#if defined(TINY_GSM_MODEM_HAS_TIME)
|
||||
#if defined(TINY_GSM_MODEM_HAS_NTP) && not defined(__AVR_ATmega32U4__)
|
||||
modem.NTPServerSync("pool.ntp.org", 3);
|
||||
#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;
|
||||
|
Reference in New Issue
Block a user