106 Commits

Author SHA1 Message Date
JDSenseright
04dacd4ed9 added watchdog feed 2024-02-10 22:15:42 +11:00
Volodymyr Shymanskyy
92c0ba3721 Update BlynkClient.ino 2023-07-04 12:22:48 +03:00
Sara Damiano
318fa45bee Version bump
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2023-06-27 12:04:58 -04:00
Sara Damiano
c2de83b4ca Fix fall through
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2023-06-27 11:37:26 -04:00
Sara Damiano
b65f1c1e14 Check for XBee wifi dns
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2023-06-27 11:27:14 -04:00
Sara Damiano
5b83997877 Add one retry to XBee
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2023-06-23 11:49:59 -04:00
Sara Damiano
ef1a7e08a1 Merge branch 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2023-06-23 11:04:26 -04:00
Sara Damiano
78425a5514 Bump version
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2023-06-23 11:04:10 -04:00
Sara Damiano
8a84350181 Merge pull request #732 from vshymanskyy/dependabot/github_actions/actions/checkout-3
ci: bump actions/checkout from 2 to 3
2023-06-23 10:33:36 -04:00
Sara Damiano
d70f005b98 Merge pull request #733 from vshymanskyy/dependabot/github_actions/actions/cache-3.3.1
ci: bump actions/cache from 2.1.5 to 3.3.1
2023-06-23 10:33:25 -04:00
dependabot[bot]
8d60810efe ci: bump actions/cache from 2.1.5 to 3.3.1
Bumps [actions/cache](https://github.com/actions/cache) from 2.1.5 to 3.3.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v2.1.5...v3.3.1)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 14:36:03 +00:00
dependabot[bot]
3d384e5435 ci: bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 14:36:00 +00:00
Sara Damiano
dcc2f9cd63 minor clean up, removed some debugging
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2023-06-22 10:35:27 -04:00
Sara Damiano
01dbc023b9 Merge branch 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2023-06-22 10:05:18 -04:00
Sara Damiano
77f285bee2 Merge pull request #731 from neilh10/iss347_digi_wifi_s6b_becomes_unstable
ModularSensors/Iss347 digi wifi s6b becomes unstable
2023-06-22 10:04:36 -04:00
Sara Damiano
b96d401e20 Merge branches 'master' and 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2023-06-22 10:02:49 -04:00
neilh20
191b3b1209 update for Digi WiFi s6b https://github.com/EnviroDIY/ModularSensors/issues/347 2023-06-20 16:24:26 -07:00
neilh20
a423350ff2 Merge branch 'master' of github.com:vshymanskyy/TinyGSM 2023-06-20 16:00:20 -07:00
Volodymyr Shymanskyy
8a911b218c Update logo.svg 2023-02-22 14:38:25 +02:00
Volodymyr Shymanskyy
ef1337aada Update logo.svg 2023-02-22 14:30:32 +02:00
Sara Damiano
80d25de1c7 Dependabot, update actions
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2022-06-28 15:41:34 -04:00
Sara Damiano
daf1063344 fix annoying sequans warning
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2022-05-02 13:28:13 -04:00
Volodymyr Shymanskyy
3356c1d5c7 Update README.md 2022-03-14 17:22:47 +02:00
Volodymyr Shymanskyy
03e647ab5b Update README.md 2022-03-04 11:19:26 +02:00
Sara Damiano
b381fa5c74 Version Bump
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-11-24 17:21:52 -05:00
Sara Damiano
f8c8e2c432 Added support for commands without _CUR for ESP
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-11-24 14:02:11 -05:00
Sara Damiano
47793e0ad9 Fix #578
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-11-24 10:34:53 -05:00
Sara Damiano
cce063cf88 Format after PR
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-11-24 10:34:29 -05:00
Sara Damiano
132844d1e1 Merge pull request #614 from ivankravets/patch-1
Declare header files for PlatformIO
2021-11-24 10:32:30 -05:00
Sara Damiano
feb3a22629 Merge pull request #597 from wifixcort/master
Update TinyGsmClientSIM800.h
2021-11-24 10:30:52 -05:00
Sara Damiano
f3dd62630b Merge pull request #594 from beaware-team/master
Add phone call implementation for SIM7600
2021-11-24 10:30:22 -05:00
Ivan Kravets
0622616c51 Declare header files for PlatformIO 2021-11-18 23:37:10 +02:00
fco.rivas
2f0b7978be Update TinyGsmClientSIM800.h
implementation of audio capabilities
2021-10-14 16:23:50 -06:00
Lukas_Skywalker
b3fc9eedae Add phone call implementation for SIM7600 2021-10-09 21:02:16 +02:00
Sara Damiano
09e679e943 Merge pull request #554 from IoTThinks/IoTThinks-patch-implement-peek
To implement peek()
2021-07-06 11:39:12 -04:00
Sara Damiano
a57014d0e6 Merge pull request #555 from UCIS/patch-1
Fix incorrect memory access in Sequans Monarch code
2021-07-06 11:32:49 -04:00
Ivo Smits
a092bfa636 Fix incorrect memory access in Sequans Monarch code
The mux value is corrected if it is out of the supported range, but the uncorrected value was used to store the connection object. This caused subsequent dereferences of the corrected mux index to access incorrect data or dereference a null pointer.
2021-06-17 22:40:22 +02:00
IoTThinks.com
4d722a34f2 To implement peek()
To implement peek() as in https://github.com/vshymanskyy/TinyGSM/issues/396
2021-06-15 09:53:01 +07:00
Sara Damiano
a5a2ce3453 Correctly bump version, modify workflow
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-24 14:51:17 -04:00
Sara Damiano
8b25d8c1d9 Merge pull request #530 from Orange-OpenSource/fix-monarch
TinyGsmClientSequansMonarch.h: use data mode
2021-05-24 14:18:29 -04:00
Sara Damiano
e5131eae7d Version bump
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-19 11:34:41 -04:00
Sara Damiano
c9ebf60e3c Fix compiler warnings
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-19 11:31:43 -04:00
Sara Damiano
b6a86862cb version bump
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-18 18:09:45 -04:00
Sara Damiano
516db057b5 Merge pull request #543 from FStefanni/master
Added ublox method to set technology + other minor improvements
2021-05-18 17:32:19 -04:00
Francesco Stefanni
a0d246be80 Added ublox method to set technology
Added missing TinyGSM.h
2021-05-18 08:13:33 +02:00
Sara Damiano
6e10a3a009 Fix crash on SIM7000SSL
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-17 12:23:29 -04:00
Sara Damiano
60a88ef89e Fix BG96 unused argument
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 17:24:42 -04:00
Sara Damiano
78130df146 Minor ReadMe fixes
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 14:49:20 -04:00
Sara Damiano
f508e78b4e Can't test *everything* on small processors
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 14:19:22 -04:00
Sara Damiano
4f9d284030 remove sapbr commands from 7000SSL
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 14:17:37 -04:00
Sara Damiano
4dc0fa2abd add some missing tags
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 14:14:38 -04:00
Sara Damiano
1e4ecae77d Add some read-me notes
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 12:04:45 -04:00
Sara Damiano
07b402721d Add gsm location to 70xx series.
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 11:44:21 -04:00
Sara Damiano
70af3cf488 Version bump
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 11:10:04 -04:00
Sara Damiano
cad8f7a61a Update some example text and add new modems
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 11:04:56 -04:00
Sara Damiano
db756813d4 Adjustments to all fxns
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 10:40:02 -04:00
Sara Damiano
6e64e867ec Got 7000SSL and 7080 sort of working again
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-14 10:37:57 -04:00
Sara Damiano
b5c5a62b2d Change 7000SSL to check available/state for all mux
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-11 17:18:06 -04:00
Sara Damiano
644085b30e Merge branch 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2021-05-11 17:13:23 -04:00
Sara Damiano
0879deab70 Split SIM7000, add SIM7070, NTP
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-05-11 16:40:32 -04:00
Sara Damiano
4eedb84cd3 Merge pull request #534 from yaroshd81/fixUssd
fix bug for ussd answers over 127 chars
2021-05-05 14:47:39 -04:00
unknown
243afe7245 fix bug for ussd answers over 127 chars 2021-05-05 16:53:19 +03:00
Sara Damiano
93fc96d9ec sim7000 syntax fix
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-29 15:43:21 -04:00
Sara Damiano
9128baeb27 xbee fixes
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-29 15:20:51 -04:00
Sara Damiano
459106a854 re-write some of xbee to minimize flash writes
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-29 14:32:41 -04:00
Sara Damiano
68a03b3ba0 Add (unused) argument for XBee modem get connected
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-29 12:37:11 -04:00
Sara Damiano
9af0acc18b Fix IP from string in MC60
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-29 12:14:33 -04:00
Sara Damiano
0094193049 Fix MQTT example
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 17:28:29 -04:00
Sara Damiano
ecca37d778 fix sed
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 16:46:20 -04:00
Sara Damiano
8766eac978 update examples to fix action for uno
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 16:40:07 -04:00
Sara Damiano
2d603d600e First take at migrating to github actions
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 15:58:20 -04:00
Sara Damiano
4fc428c945 Fix #511, ignore response to set timezone in ublox
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 15:30:58 -04:00
Fabrice Fontaine
38a712500e TinyGsmClientSequansMonarch.h: use data mode
Use data mode instead of text mode to be able to send any content such
as raw binary. This will allow us to use TinyGSM with ArduinoBearSSL and
ArduinoMqtt.

It should be noted that for an unclear reason GSM_NL must be set to '\n'
instead of '\r\n' to avoid "CME ERROR: operation not supported" in this
mode with the Monarch GMS01Q.

Signed-off-by: Fabrice Fontaine <fabrice.fontaine@orange.com>
2021-04-28 21:28:48 +02:00
Sara Damiano
b22aa854d6 Merge branch 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2021-04-28 15:27:22 -04:00
Sara Damiano
a9f723130c Fix #508, GPS on 7600
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 15:27:08 -04:00
Sara Damiano
772f33636e Merge pull request #503 from Orange-OpenSource/fix-sequans-monarch
src/TinyGsmModem.tpp: fix registration state
2021-04-28 15:17:41 -04:00
Sara Damiano
75104a49c3 Call modem get connected for modems w/o buffer
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 13:53:47 -04:00
Sara Damiano
51f4da58e5 Merge pull request #520 from I-Connect/patch-1
Added NTPServerSync() and related methods to Sim7000 implementation
2021-04-28 13:08:59 -04:00
Sara Damiano
f6d7480a69 Update state of SSL for SIM7000 in readme
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
2021-04-28 13:04:03 -04:00
Sara Damiano
d3944ecc8b Merge branch 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2021-04-28 12:58:18 -04:00
Sara Damiano
b1f81f485e Merge pull request #507 from FStefanni/master
SIM7000: TLS support plus other minor improvements
2021-04-28 12:57:54 -04:00
Bascy
750108ee09 Added NTPServerSync() and related methoeds 2021-04-14 00:52:06 +02:00
Francesco Stefanni
c1d6abaff7 Supported SNI (fix by kyriazis) 2021-04-07 11:24:39 +02:00
Francesco Stefanni
7f19c69554 sim7000: added fix on read 2021-03-18 08:06:14 +01:00
Francesco Stefanni
28f7e7b298 Some improvements 2021-03-17 15:19:04 +01:00
Francesco Stefanni
f0abeef22d Supported root certificates 2021-03-17 15:17:13 +01:00
Francesco Stefanni
b8a54d37e0 Some improvements to sim7000 2021-03-17 14:27:43 +01:00
Francesco Stefanni
57895868f2 Added missing waitResponse() 2021-03-17 08:36:09 +01:00
Francesco Stefanni
57514b7c4d Supported factory reset for sim7000 2021-03-12 15:27:57 +01:00
Francesco Stefanni
7cf19beb44 A deep debug of sim7000 2021-03-12 15:26:35 +01:00
Francesco Stefanni
0be9622e9c Removed some debug print 2021-03-12 10:38:47 +01:00
Francesco Stefanni
81f583a80f SIM7000: TLS + some refinements 2021-03-12 10:11:58 +01:00
Sara Damiano
9498800b50 Merge pull request #506 from FStefanni/pr_sim7000_connection
SIM7000: added methods to get some connection preferences
2021-03-10 10:40:27 -05:00
Francesco Stefanni
f20293905f SIM7000: added methods to get some connection preferences, plus the
current connection technology
2021-03-10 08:55:38 +01:00
Fabrice Fontaine
1291a4407d src/TinyGsmModem.tpp: fix registration state
As specified in the ETSI standards (e.g. ETSI TS 127 001), CREG and
CEREG responses can contain optional parameters:

+CEREG:         <n>,<stat>[,<tac>,<ci>[,<AcT>]]

For example, the Monarch GMS01Q returns the following response:

+CEREG: 2,1,"3982","00DF3B03",7

This results in TinyGSM setting state as '7' instead of 1 preventing
any connection.

Fix this by picking the next integer after the first ',' which will
always works (with or without optional parameters)

Signed-off-by: Fabrice Fontaine <fabrice.fontaine@orange.com>
2021-03-05 18:59:29 +01:00
Sara Damiano
98d67a4155 Merge pull request #502 from Orange-OpenSource/fix-sequans-monarch
src/TinyGsmClientSequansMonarch.h: fix connection handling
2021-03-05 11:34:49 -05:00
Fabrice Fontaine
eb9c1f7786 src/TinyGsmClientSequansMonarch.h: fix connection handling
There is an issue in the handling of +SQNSS answer: the
sock->sock_connected state will always be set to the state of the last
socket. This will prevent any communication.

Fix this issue by checking that muxNo is equal to mux before updating.

Signed-off-by: Fabrice Fontaine <fabrice.fontaine@orange.com>
2021-03-05 16:47:35 +01:00
Sara Damiano
7f2900b278 Merge branch 'master' of https://github.com/vshymanskyy/TinyGSM into v_master 2021-03-02 17:24:03 -05:00
Sara Damiano
b0e363c536 Merge pull request #488 from adrianca88/SIM808_bt_support
First SIM808 bluetooth support commit. Template class and basic functionality
2021-02-08 13:58:14 -05:00
Sara Damiano
88320025ec Merge pull request #487 from adrianca88/restart_with_pin_param
Added pin parameter on restart() (necessary for init() with pin)
2021-02-03 17:54:20 -05:00
Adrian Cervera Andes
54c25cce23 First SIM808 support commit. Added template base class and some basic functionality 2021-01-31 12:11:11 +01:00
Adrian Cervera Andes
a51cfda25d Added pin parameter on restart() (necessary for init() with pin) 2021-01-29 15:02:35 +01:00
Sara Damiano
31bb5cbeed Merge pull request #467 from soracom-labs/master
use CEREG first to check registration status for BG96
2020-12-03 12:21:50 -05:00
moto
ba778adb74 use CEREG first for BG96
I refered TinyGsmClientSaraR4.h for this patch.
2020-12-03 10:34:29 +09:00
Sara Damiano
f6d636274f Merge pull request #459 from fishingbit/master
disable memory optimizations on ATmega4809
2020-11-09 11:12:55 -05:00
Markus Schmidleitner
23742b4b9c disable memory optimizations on ATmega4809 2020-11-06 15:17:34 +01:00
48 changed files with 3408 additions and 906 deletions

View File

@@ -25,7 +25,7 @@ with your board before submitting any issues.
Modem: <!-- Brand, model, variant, firmware version, ie Quectel BG96 Revision: BG96MAR02A07M1G -->
Main processor board: <!-- Uno, Zero, ESP32, Particle, etc -->
TinyGSM version: <!-- always try to use the latest (0.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
View File

@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'daily'
labels:
- 'CI/CD'
commit-message:
prefix: ci

View 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

View File

@@ -1,3 +1,5 @@
[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine)
![TinyGSM logo](https://cdn.rawgit.com/vshymanskyy/TinyGSM/d18e93dc51fe988a0b175aac647185457ef640b5/extras/logo.svg)
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:
[![Gitter](https://img.shields.io/gitter/room/vshymanskyy/TinyGSM.svg)](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)

View File

@@ -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(); }
}

View File

@@ -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

View File

@@ -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); }
}

View File

@@ -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); }
}

View File

@@ -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); }
}

View File

@@ -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;

View File

@@ -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); }
}

View 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": "*"
}
]

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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.

View File

@@ -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
View File

@@ -0,0 +1,6 @@
#ifndef TINYGSM_H
#define TINYGSM_H
#include "TinyGsmClient.h"
#endif

57
src/TinyGsmBluetooth.tpp Normal file
View 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_

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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
*/

View File

@@ -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_

View 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: Cant bind the port
// 13: Cant listen the port
// 20: Cant resolve the host
// 21: Network not active
// 23: Remote refuse
// 24: Certificates time expired
// 25: Certificates common name does not match
// 26: Certificates 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
View 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: Cant bind the port
// 13: Cant listen the port
// 20: Cant resolve the host
// 21: Network not active
// 23: Remote refuse
// 24: Certificates time expired
// 25: Certificates common name does not match
// 26: Certificates 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
View 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_

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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_

View File

@@ -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() {

View File

@@ -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_

View File

@@ -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]) {

View File

@@ -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;

View File

@@ -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))

View File

@@ -122,6 +122,11 @@ public:
return n - c;
}
uint8_t peek()
{
return _b[_r];
}
private:
int _inc(int i, int n = 1)
{

View File

@@ -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
View 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_

View File

@@ -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,
};

View File

@@ -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();

View File

@@ -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

View File

@@ -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); }
}

View File

@@ -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);

View File

@@ -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;